diff --git a/.clang-format b/.clang-format index 400349f1..7411a0c6 100644 --- a/.clang-format +++ b/.clang-format @@ -57,7 +57,7 @@ SpacesInCStyleCastParentheses: 'false' SpacesInContainerLiterals: 'true' SpacesInParentheses: 'false' SpacesInSquareBrackets: 'false' -UseTab: 'Always' +UseTab: 'Never' --- Language: Cpp diff --git a/.clangd b/.clangd index 0605ccdb..cd9c5e1d 100644 --- a/.clangd +++ b/.clangd @@ -4,3 +4,6 @@ CompileFlags: - "-I../ext" - "-I../ext/prometheus-cpp-lite-1.0/core/include" - "-I../ext/prometheus-cpp-lite-1.0/simpleapi/include" + - "-I./ext" + - "-I./ext/prometheus-cpp-lite-1.0/core/include" + - "-I./ext/prometheus-cpp-lite-1.0/simpleapi/include" diff --git a/.drone.jsonnet b/.drone.jsonnet deleted file mode 100644 index 7daef37f..00000000 --- a/.drone.jsonnet +++ /dev/null @@ -1,256 +0,0 @@ -// -// tweakables -// - -local registry = "084037375216.dkr.ecr.us-east-2.amazonaws.com"; -local build_channel = "zerotier-builds"; -local release_channel = "zerotier-releases"; - -local targets = [ - { "os": "linux", distro: "redhat", "name": "el9", "isas": [ "amd64", "arm64", "ppc64le", "s390x" ], "events": [ "tag", "custom" ] }, - { "os": "linux", distro: "redhat", "name": "el8", "isas": [ "amd64", "arm64", "ppc64le", "s390x" ], "events": [ "tag" ] }, - { "os": "linux", distro: "redhat", "name": "el7", "isas": [ "386", "amd64", "ppc64le"], "events": [ "tag" ] }, - { "os": "linux", distro: "amazon", "name": "amzn2", "isas": [ "amd64", "arm64" ], "events": [ "tag" ] }, - { "os": "linux", distro: "amazon", "name": "amzn2022", "isas": [ "amd64", "arm64" ], "events": [ "tag" ] }, - { "os": "linux", distro: "fedora", "name": "fc38", "isas": [ "amd64", "arm64", "ppc64le", "s390x" ], "events": [ "tag" ] }, - { "os": "linux", distro: "fedora", "name": "fc37", "isas": [ "amd64", "arm64", "ppc64le", "s390x" ], "events": [ "tag" ] }, - { "os": "linux", distro: "fedora", "name": "fc36", "isas": [ "amd64", "arm64", "ppc64le", "s390x" ], "events": [ "tag" ] }, - { "os": "linux", distro: "ubuntu", "name": "jammy", "isas": [ "armv7", "amd64", "arm64", "ppc64le", "s390x", "riscv64" ], "events": [ "tag" ] }, - { "os": "linux", distro: "ubuntu", "name": "focal", "isas": [ "armv7", "amd64", "arm64", "ppc64le", "s390x", "riscv64" ], "events": [ "tag" ] }, - { "os": "linux", distro: "ubuntu", "name": "bionic", "isas": [ "386", "armv7", "amd64", "arm64", "ppc64le", "s390x" ], "events": [ "tag" ] }, - { "os": "linux", distro: "ubuntu", "name": "xenial", "isas": [ "386", "armv7", "amd64", "arm64", "ppc64le", "s390x" ], "events": [ "tag" ] }, - { "os": "linux", distro: "ubuntu", "name": "trusty", "isas": [ "386", "armv7", "amd64", "arm64" ], "events": [ "tag" ] }, - { "os": "linux", distro: "debian", "name": "bookworm", "isas": [ "386", "armv7", "amd64", "arm64", "mips64le", "ppc64le", "s390x" ], "events": [ "tag"] }, - { "os": "linux", distro: "debian", "name": "bullseye", "isas": [ "386", "armv7", "amd64", "arm64", "mips64le", "ppc64le", "s390x" ], "events": [ "push", "tag", "custom" ] }, - { "os": "linux", distro: "debian", "name": "buster", "isas": [ "386", "armv7", "amd64", "arm64" ], "events": [ "tag" ] }, - { "os": "linux", distro: "debian", "name": "stretch", "isas": [ "386", "armv7", "amd64", "arm64" ], "events": [ "tag" ] }, - { "os": "linux", distro: "debian", "name": "jessie", "isas": [ "386", "armv7", "amd64" ], "events": [ "tag" ] }, - -// { "os": "windows", distro: "windows", "name": "windows", "isas": [ "amd64" ], "events": [ "push", "tag", "custom" ] }, -// { "os": "darwin", distro: "darwin", "name": "darwin", "isas": [ "amd64" ], "events": [ "push", "tag", "custom" ] }, - -]; - -local less_targets = [ - { "os": "linux", distro: "redhat", "name": "el9", "isas": [ "amd64", "arm64" ], "events": [ "push", "tag", "custom" ] }, - { "os": "linux", distro: "redhat", "name": "el8", "isas": [ "amd64", "arm64" ], "events": [ "push", "tag", "custom" ] }, - { "os": "linux", distro: "ubuntu", "name": "jammy", "isas": [ "armv7", "amd64", "arm64" ], "events": [ "push", "tag", "custom" ] }, - { "os": "linux", distro: "ubuntu", "name": "focal", "isas": [ "armv7", "amd64", "arm64" ], "events": [ "push", "tag", "custom" ] }, -]; - - -local native_targets = [ - { "os": "linux", distro: "debian", "name": "bullseye", "isas": [ "386", "armv7", "amd64", "arm64" ], "events": [ "push", "tag", "custom" ] }, -]; - -local master_targets = [ - // - // copypasta from here - // - { "os": "linux", distro: "redhat", "name": "el9", "isas": [ "amd64", "arm64", "ppc64le", "s390x" ], "events": [ "push", "tag", "custom" ] }, - { "os": "linux", distro: "redhat", "name": "el8", "isas": [ "amd64", "arm64", "ppc64le", "s390x" ], "events": [ "push", "tag", "custom" ] }, - { "os": "linux", distro: "redhat", "name": "el7", "isas": [ "386", "amd64", "ppc64le"], "events": [ "push", "tag", "custom" ] }, - { "os": "linux", distro: "amazon", "name": "amzn2", "isas": [ "amd64", "arm64" ], "events": [ "push", "tag", "custom" ] }, - { "os": "linux", distro: "amazon", "name": "amzn2022", "isas": [ "amd64", "arm64" ], "events": [ "push", "tag", "custom" ] }, - { "os": "linux", distro: "fedora", "name": "fc38", "isas": [ "amd64", "arm64", "ppc64le", "s390x" ], "events": [ "push", "tag", "custom" ] }, - { "os": "linux", distro: "fedora", "name": "fc37", "isas": [ "amd64", "arm64", "ppc64le", "s390x" ], "events": [ "push", "tag", "custom" ] }, - { "os": "linux", distro: "fedora", "name": "fc36", "isas": [ "amd64", "arm64", "ppc64le", "s390x" ], "events": [ "push", "tag", "custom" ] }, - { "os": "linux", distro: "ubuntu", "name": "jammy", "isas": [ "armv7", "amd64", "arm64", "ppc64le", "s390x", "riscv64" ], "events": [ "push", "tag", "custom" ] }, - { "os": "linux", distro: "ubuntu", "name": "focal", "isas": [ "armv7", "amd64", "arm64", "ppc64le", "s390x", "riscv64" ], "events": [ "push", "tag", "custom" ] }, - { "os": "linux", distro: "ubuntu", "name": "bionic", "isas": [ "386", "armv7", "amd64", "arm64", "ppc64le", "s390x" ], "events": [ "push", "tag", "custom" ] }, - { "os": "linux", distro: "ubuntu", "name": "xenial", "isas": [ "386", "armv7", "amd64", "arm64", "ppc64le", "s390x" ], "events": [ "push", "tag", "custom" ] }, - { "os": "linux", distro: "ubuntu", "name": "trusty", "isas": [ "386", "armv7", "amd64", "arm64" ], "events": [ "push", "tag", "custom" ] }, - { "os": "linux", distro: "debian", "name": "sid", "isas": [ "386", "armv7", "amd64", "arm64", "mips64le", "ppc64le", "s390x", "riscv64" ], "events": [ "push", "tag", "custom" ] }, - { "os": "linux", distro: "debian", "name": "bookworm", "isas": [ "386", "armv7", "amd64", "arm64", "mips64le", "ppc64le", "s390x" ], "events": [ "push", "tag", "custom" ] }, - { "os": "linux", distro: "debian", "name": "bullseye", "isas": [ "386", "armv7", "amd64", "arm64", "mips64le", "ppc64le", "s390x" ], "events": [ "push", "tag", "custom" ] }, - { "os": "linux", distro: "debian", "name": "buster", "isas": [ "386", "armv7", "amd64", "arm64" ], "events": [ "push", "tag", "custom" ] }, - { "os": "linux", distro: "debian", "name": "stretch", "isas": [ "386", "armv7", "amd64", "arm64" ], "events": [ "push", "tag", "custom" ] }, - { "os": "linux", distro: "debian", "name": "jessie", "isas": [ "386", "armv7", "amd64" ], "events": [ "push", "tag", "custom" ] }, - { "os": "windows", distro: "windows", "name": "win2k22", "isas": [ "amd64" ], "events": [ "push", "tag", "custom" ] } -]; - -// -// functions -// - -local pipeline_type(os) = if os == "darwin" then "exec" else "docker"; -local builder_image(os) = if os == "linux" then registry + "/honda-builder" else registry + "/windows-builder"; -local tester_image(os) = if os == "linux" then registry + "/honda-builder" else registry + "/windows-tester"; -local build_step_volumes(os) = if os == "linux" then [ { name: "zerotier-builds", path: "/zerotier-builds" } ] else []; -local release_step_volumes(os) = if os == "linux" then [ { name: "zerotier-releases", path: "/zerotier-releases" } ] else []; -local host_volumes(os) = if os == "linux" then [ - { name: "zerotier-builds", host: { path: "/zerotier-builds" } }, - { name: "zerotier-releases", host: { path: "/zerotier-releases" } }, -] else []; - -local index_image(distro) = - if distro == "debian" || distro == "ubuntu" then - registry + "/apt-builder" - else if distro == "redhat" || distro == "fedora" || distro == "amazon" then - registry + "/dnf-builder" - else if distro == "windows" then - registry + "/msi-builder" -; - -local copy_commands(os, distro, name, isa, version) = - if os == "linux" then [ - std.join(" ", [ "./ci/scripts/publish.sh", name, distro, isa, version, "${DRONE_BUILD_EVENT}" ]) - ] - else if os == "windows" then [ - "C:\\scripts\\fix-ec2-metadata.ps1", - "Get-ChildItem windows", - // "aws s3 cp windows\\bytey-SetupFiles\\bytey.msi s3://zerotier-builds/windows/" + version + "/bytey.msi", - ] else if os == "darwin" then [ - "echo hello" - ] -; - -local index_commands(os, channel, distro, name, isas) = - if os == "linux" then - [ "/usr/local/bin/index " + channel + " " + distro + " " + name + " " + std.join(" ", isas) ] - else if os == "windows" then - [ "Get-ChildItem -Recurse windows" ] -; - -local build_commands(os, distro, name, isa, version) = - if os == "linux" then - [ std.join(" ", [ "./ci/scripts/build.sh", name, distro, isa, version, "${DRONE_BUILD_EVENT}" ]) ] - else - if os == "windows" then - [ "windows/build.ps1", "windows/package.ps1" ] - else - if os == "darwin" then - [ "whoami" ] -; - -local test_commands(os, distro, name, isa, version) = - if os == "linux" then - [ std.join(" ", [ "./ci/scripts/test.sh", name, distro, isa, version, "${DRONE_BUILD_EVENT}" ]) ] - else - if os == "windows" then - [ "windows/testpackage.ps1 " + version ] -; - -// -// render -// - -local Build(os, distro, name, isa, events) = { - "kind": "pipeline", - "type": pipeline_type(os), - "name": std.join(" ", [ name, isa, "build" ]), - "pull": "always", - "clone": { "depth": 1, [ if os == "darwin" then "disable" ]: true }, - "steps": [ - { - "name": "build", - "image": builder_image(os), - "commands": build_commands(os, distro, name, isa, "100.0.0+${DRONE_COMMIT_SHA:0:8}"), - "when": { "event": [ "push" ]}, - }, - { - "name": "release", - "image": builder_image(os), - "commands": build_commands(os, distro, name, isa, "${DRONE_TAG}"), - "when": { "event": [ "tag" ]}, - }, - { - "name": "copy build", - "image": builder_image(os), - "commands": copy_commands(os, distro, name, isa, "100.0.0+${DRONE_COMMIT_SHA:0:8}"), - "volumes": build_step_volumes(os), - "when": { "event": [ "push" ]}, - }, - { - "name": "copy relase", - "image": builder_image(os), - "commands": copy_commands(os, distro, name, isa, "${DRONE_TAG}"), - "volumes": release_step_volumes(os), - "when": { "event": [ "tag" ]}, - }, - ], - "volumes": host_volumes(os), - "platform": { "os": os, [ if isa == "arm64" || isa == "armv7" then "arch" ]: "arm64" }, - "trigger": { "event": events } -}; - -local Test(os, distro, name, isa, events) = { - "kind": "pipeline", - "type": pipeline_type(os), - "name": std.join(" ", [ name, isa, "test"]), - "pull": "always", - "clone": { "depth": 1 }, - "steps": [ - { - "name": "test build", - "image": tester_image(os), - "volumes": build_step_volumes(os), - "commands": test_commands(os, distro, name, isa, "100.0.0+${DRONE_COMMIT_SHA:0:8}"), - "when": { "event": [ "push" ]}, - }, - { - "name": "test release", - "image": tester_image(os), - "volumes": release_step_volumes(os), - "commands": test_commands(os, distro, name, isa, "${DRONE_TAG}"), - "when": { "event": [ "tag" ]}, - }, - ], - "volumes": host_volumes(os), - "platform": { "os": os, [ if isa == "arm64" || isa == "armv7" then "arch" ]: "arm64" }, - "depends_on": [ std.join(" ", [ name, "index" ]) ], - "trigger": { "event": events } -}; - -local Index(p) = { - "kind": "pipeline", - "type": pipeline_type(p.os), - "name": std.join(" ", [ p.name, "index" ]), - "pull": "always", - "clone": { "depth": 1 }, - "steps": [ - { - "name": "index build", - "image": index_image(p.distro), - "commands": index_commands(p.os, "zerotier-builds", p.distro, p.name, p.isas), - "volumes": build_step_volumes(p.os), - "environment":{ "GPG_PRIVATE_KEY": { from_secret: "gpg-private-key" }}, - "when": { "event": [ "push" ]}, - }, - { - "name": "index release", - "image": index_image(p.distro), - "commands": index_commands(p.os, "zerotier-releases", p.distro, p.name, p.isas), - "volumes": release_step_volumes(p.os), - "environment":{ "GPG_PRIVATE_KEY": { from_secret: "gpg-private-key" }}, - "when": { "event": [ "tag" ]}, - }, - ], - "volumes": host_volumes(p.os), - "platform": { "os": p.os }, - depends_on: std.flattenArrays([ [ std.join(" ", [ p.name, isa, "build" ]) ] for isa in p.isas ]), - "trigger": { "event": p.events } -}; - -// -// print -// - -std.flattenArrays([ - [ - Build(p.os, p.distro, p.name, isa, p.events) - for isa in p.isas - ] + - [ - Index(p) - ] - for p in native_targets - ]) + - std.flattenArrays([ - [ - Test(p.os, p.distro, p.name, isa, p.events) - for isa in p.isas - ] - for p in native_targets - ]) - \ No newline at end of file diff --git a/.drone.yml b/.drone.yml deleted file mode 100644 index b837b1b2..00000000 --- a/.drone.yml +++ /dev/null @@ -1,465 +0,0 @@ ---- -clone: - depth: 1 -kind: pipeline -name: bullseye 386 build -platform: - os: linux -pull: always -steps: -- commands: - - ./ci/scripts/build.sh bullseye debian 386 100.0.0+${DRONE_COMMIT_SHA:0:8} ${DRONE_BUILD_EVENT} - image: 084037375216.dkr.ecr.us-east-2.amazonaws.com/honda-builder - name: build - when: - event: - - push -- commands: - - ./ci/scripts/build.sh bullseye debian 386 ${DRONE_TAG} ${DRONE_BUILD_EVENT} - image: 084037375216.dkr.ecr.us-east-2.amazonaws.com/honda-builder - name: release - when: - event: - - tag -- commands: - - ./ci/scripts/publish.sh bullseye debian 386 100.0.0+${DRONE_COMMIT_SHA:0:8} ${DRONE_BUILD_EVENT} - image: 084037375216.dkr.ecr.us-east-2.amazonaws.com/honda-builder - name: copy build - volumes: - - name: zerotier-builds - path: /zerotier-builds - when: - event: - - push -- commands: - - ./ci/scripts/publish.sh bullseye debian 386 ${DRONE_TAG} ${DRONE_BUILD_EVENT} - image: 084037375216.dkr.ecr.us-east-2.amazonaws.com/honda-builder - name: copy relase - volumes: - - name: zerotier-releases - path: /zerotier-releases - when: - event: - - tag -trigger: - event: - - push - - tag - - custom -type: docker -volumes: -- host: - path: /zerotier-builds - name: zerotier-builds -- host: - path: /zerotier-releases - name: zerotier-releases ---- -clone: - depth: 1 -kind: pipeline -name: bullseye armv7 build -platform: - arch: arm64 - os: linux -pull: always -steps: -- commands: - - ./ci/scripts/build.sh bullseye debian armv7 100.0.0+${DRONE_COMMIT_SHA:0:8} ${DRONE_BUILD_EVENT} - image: 084037375216.dkr.ecr.us-east-2.amazonaws.com/honda-builder - name: build - when: - event: - - push -- commands: - - ./ci/scripts/build.sh bullseye debian armv7 ${DRONE_TAG} ${DRONE_BUILD_EVENT} - image: 084037375216.dkr.ecr.us-east-2.amazonaws.com/honda-builder - name: release - when: - event: - - tag -- commands: - - ./ci/scripts/publish.sh bullseye debian armv7 100.0.0+${DRONE_COMMIT_SHA:0:8} - ${DRONE_BUILD_EVENT} - image: 084037375216.dkr.ecr.us-east-2.amazonaws.com/honda-builder - name: copy build - volumes: - - name: zerotier-builds - path: /zerotier-builds - when: - event: - - push -- commands: - - ./ci/scripts/publish.sh bullseye debian armv7 ${DRONE_TAG} ${DRONE_BUILD_EVENT} - image: 084037375216.dkr.ecr.us-east-2.amazonaws.com/honda-builder - name: copy relase - volumes: - - name: zerotier-releases - path: /zerotier-releases - when: - event: - - tag -trigger: - event: - - push - - tag - - custom -type: docker -volumes: -- host: - path: /zerotier-builds - name: zerotier-builds -- host: - path: /zerotier-releases - name: zerotier-releases ---- -clone: - depth: 1 -kind: pipeline -name: bullseye amd64 build -platform: - os: linux -pull: always -steps: -- commands: - - ./ci/scripts/build.sh bullseye debian amd64 100.0.0+${DRONE_COMMIT_SHA:0:8} ${DRONE_BUILD_EVENT} - image: 084037375216.dkr.ecr.us-east-2.amazonaws.com/honda-builder - name: build - when: - event: - - push -- commands: - - ./ci/scripts/build.sh bullseye debian amd64 ${DRONE_TAG} ${DRONE_BUILD_EVENT} - image: 084037375216.dkr.ecr.us-east-2.amazonaws.com/honda-builder - name: release - when: - event: - - tag -- commands: - - ./ci/scripts/publish.sh bullseye debian amd64 100.0.0+${DRONE_COMMIT_SHA:0:8} - ${DRONE_BUILD_EVENT} - image: 084037375216.dkr.ecr.us-east-2.amazonaws.com/honda-builder - name: copy build - volumes: - - name: zerotier-builds - path: /zerotier-builds - when: - event: - - push -- commands: - - ./ci/scripts/publish.sh bullseye debian amd64 ${DRONE_TAG} ${DRONE_BUILD_EVENT} - image: 084037375216.dkr.ecr.us-east-2.amazonaws.com/honda-builder - name: copy relase - volumes: - - name: zerotier-releases - path: /zerotier-releases - when: - event: - - tag -trigger: - event: - - push - - tag - - custom -type: docker -volumes: -- host: - path: /zerotier-builds - name: zerotier-builds -- host: - path: /zerotier-releases - name: zerotier-releases ---- -clone: - depth: 1 -kind: pipeline -name: bullseye arm64 build -platform: - arch: arm64 - os: linux -pull: always -steps: -- commands: - - ./ci/scripts/build.sh bullseye debian arm64 100.0.0+${DRONE_COMMIT_SHA:0:8} ${DRONE_BUILD_EVENT} - image: 084037375216.dkr.ecr.us-east-2.amazonaws.com/honda-builder - name: build - when: - event: - - push -- commands: - - ./ci/scripts/build.sh bullseye debian arm64 ${DRONE_TAG} ${DRONE_BUILD_EVENT} - image: 084037375216.dkr.ecr.us-east-2.amazonaws.com/honda-builder - name: release - when: - event: - - tag -- commands: - - ./ci/scripts/publish.sh bullseye debian arm64 100.0.0+${DRONE_COMMIT_SHA:0:8} - ${DRONE_BUILD_EVENT} - image: 084037375216.dkr.ecr.us-east-2.amazonaws.com/honda-builder - name: copy build - volumes: - - name: zerotier-builds - path: /zerotier-builds - when: - event: - - push -- commands: - - ./ci/scripts/publish.sh bullseye debian arm64 ${DRONE_TAG} ${DRONE_BUILD_EVENT} - image: 084037375216.dkr.ecr.us-east-2.amazonaws.com/honda-builder - name: copy relase - volumes: - - name: zerotier-releases - path: /zerotier-releases - when: - event: - - tag -trigger: - event: - - push - - tag - - custom -type: docker -volumes: -- host: - path: /zerotier-builds - name: zerotier-builds -- host: - path: /zerotier-releases - name: zerotier-releases ---- -clone: - depth: 1 -depends_on: -- bullseye 386 build -- bullseye armv7 build -- bullseye amd64 build -- bullseye arm64 build -kind: pipeline -name: bullseye index -platform: - os: linux -pull: always -steps: -- commands: - - /usr/local/bin/index zerotier-builds debian bullseye 386 armv7 amd64 arm64 - environment: - GPG_PRIVATE_KEY: - from_secret: gpg-private-key - image: 084037375216.dkr.ecr.us-east-2.amazonaws.com/apt-builder - name: index build - volumes: - - name: zerotier-builds - path: /zerotier-builds - when: - event: - - push -- commands: - - /usr/local/bin/index zerotier-releases debian bullseye 386 armv7 amd64 arm64 - environment: - GPG_PRIVATE_KEY: - from_secret: gpg-private-key - image: 084037375216.dkr.ecr.us-east-2.amazonaws.com/apt-builder - name: index release - volumes: - - name: zerotier-releases - path: /zerotier-releases - when: - event: - - tag -trigger: - event: - - push - - tag - - custom -type: docker -volumes: -- host: - path: /zerotier-builds - name: zerotier-builds -- host: - path: /zerotier-releases - name: zerotier-releases ---- -clone: - depth: 1 -depends_on: -- bullseye index -kind: pipeline -name: bullseye 386 test -platform: - os: linux -pull: always -steps: -- commands: - - ./ci/scripts/test.sh bullseye debian 386 100.0.0+${DRONE_COMMIT_SHA:0:8} ${DRONE_BUILD_EVENT} - image: 084037375216.dkr.ecr.us-east-2.amazonaws.com/honda-builder - name: test build - volumes: - - name: zerotier-builds - path: /zerotier-builds - when: - event: - - push -- commands: - - ./ci/scripts/test.sh bullseye debian 386 ${DRONE_TAG} ${DRONE_BUILD_EVENT} - image: 084037375216.dkr.ecr.us-east-2.amazonaws.com/honda-builder - name: test release - volumes: - - name: zerotier-releases - path: /zerotier-releases - when: - event: - - tag -trigger: - event: - - push - - tag - - custom -type: docker -volumes: -- host: - path: /zerotier-builds - name: zerotier-builds -- host: - path: /zerotier-releases - name: zerotier-releases ---- -clone: - depth: 1 -depends_on: -- bullseye index -kind: pipeline -name: bullseye armv7 test -platform: - arch: arm64 - os: linux -pull: always -steps: -- commands: - - ./ci/scripts/test.sh bullseye debian armv7 100.0.0+${DRONE_COMMIT_SHA:0:8} ${DRONE_BUILD_EVENT} - image: 084037375216.dkr.ecr.us-east-2.amazonaws.com/honda-builder - name: test build - volumes: - - name: zerotier-builds - path: /zerotier-builds - when: - event: - - push -- commands: - - ./ci/scripts/test.sh bullseye debian armv7 ${DRONE_TAG} ${DRONE_BUILD_EVENT} - image: 084037375216.dkr.ecr.us-east-2.amazonaws.com/honda-builder - name: test release - volumes: - - name: zerotier-releases - path: /zerotier-releases - when: - event: - - tag -trigger: - event: - - push - - tag - - custom -type: docker -volumes: -- host: - path: /zerotier-builds - name: zerotier-builds -- host: - path: /zerotier-releases - name: zerotier-releases ---- -clone: - depth: 1 -depends_on: -- bullseye index -kind: pipeline -name: bullseye amd64 test -platform: - os: linux -pull: always -steps: -- commands: - - ./ci/scripts/test.sh bullseye debian amd64 100.0.0+${DRONE_COMMIT_SHA:0:8} ${DRONE_BUILD_EVENT} - image: 084037375216.dkr.ecr.us-east-2.amazonaws.com/honda-builder - name: test build - volumes: - - name: zerotier-builds - path: /zerotier-builds - when: - event: - - push -- commands: - - ./ci/scripts/test.sh bullseye debian amd64 ${DRONE_TAG} ${DRONE_BUILD_EVENT} - image: 084037375216.dkr.ecr.us-east-2.amazonaws.com/honda-builder - name: test release - volumes: - - name: zerotier-releases - path: /zerotier-releases - when: - event: - - tag -trigger: - event: - - push - - tag - - custom -type: docker -volumes: -- host: - path: /zerotier-builds - name: zerotier-builds -- host: - path: /zerotier-releases - name: zerotier-releases ---- -clone: - depth: 1 -depends_on: -- bullseye index -kind: pipeline -name: bullseye arm64 test -platform: - arch: arm64 - os: linux -pull: always -steps: -- commands: - - ./ci/scripts/test.sh bullseye debian arm64 100.0.0+${DRONE_COMMIT_SHA:0:8} ${DRONE_BUILD_EVENT} - image: 084037375216.dkr.ecr.us-east-2.amazonaws.com/honda-builder - name: test build - volumes: - - name: zerotier-builds - path: /zerotier-builds - when: - event: - - push -- commands: - - ./ci/scripts/test.sh bullseye debian arm64 ${DRONE_TAG} ${DRONE_BUILD_EVENT} - image: 084037375216.dkr.ecr.us-east-2.amazonaws.com/honda-builder - name: test release - volumes: - - name: zerotier-releases - path: /zerotier-releases - when: - event: - - tag -trigger: - event: - - push - - tag - - custom -type: docker -volumes: -- host: - path: /zerotier-builds - name: zerotier-builds -- host: - path: /zerotier-releases - name: zerotier-releases ---- -kind: signature -hmac: 887a3ef78d3fe8f0149911e1e4876401dd7dd313b36eb893e791fa42f45d7768 - -... diff --git a/.kick b/.kick deleted file mode 100644 index 28b8ee7f..00000000 --- a/.kick +++ /dev/null @@ -1,14 +0,0 @@ -kick -kick -kick -kick -kick -kick -kick -kick -kick -kick -kick -kick -kick -kick diff --git a/AUTHORS.md b/AUTHORS.md deleted file mode 100644 index 84bb8631..00000000 --- a/AUTHORS.md +++ /dev/null @@ -1,75 +0,0 @@ -# Authors and Third Party Code Licensing Information - -## Primary Authors - - * ZeroTier Core and ZeroTier One virtual networking service
- Adam Ierymenko / adam.ierymenko@zerotier.com - Joseph Henry / joseph.henry@zerotier.com (QoS and multipath) - - * Java JNI Interface to enable Android application development, and Android app itself (code for that is elsewhere)
- Grant Limberg / glimberg@gmail.com - - * ZeroTier SDK (formerly known as Network Containers)
- Joseph Henry / joseph.henry@zerotier.com - -## Third Party Contributors - - * A number of fixes and improvements to the new controller, other stuff.
- Kees Bos / https://github.com/keesbos/ - - * Debugging and testing, OpenWRT support fixes.
- Moritz Warning / moritzwarning@web.de - - * Debian GNU/Linux packaging, manual pages, and license compliance edits.
- Ben Finney - - * Several others made smaller contributions, which GitHub tracks here:
- https://github.com/zerotier/ZeroTierOne/graphs/contributors/ - -## Third-Party Code - -ZeroTier includes the following third party code, either in ext/ or incorporated into the ZeroTier core. This third party code remains licensed under its original license and is not subject to ZeroTier's BSL license. - - * LZ4 compression algorithm by Yann Collet - - * Files: node/Packet.cpp (bundled within anonymous namespace) - * Home page: http://code.google.com/p/lz4/ - * License grant: BSD 2-clause - - * http-parser by Joyent, Inc. (many authors) - - * Files: ext/http-parser/* - * Home page: https://github.com/joyent/http-parser/ - * License grant: MIT/Expat - - * C++11 json (nlohmann/json) by Niels Lohmann - - * Files: ext/json/* - * Home page: https://github.com/nlohmann/json - * License grant: MIT - - * tap-windows6 by the OpenVPN project - - * Files: windows/TapDriver6/* - * Home page: https://github.com/OpenVPN/tap-windows6/ - * License grant: GNU GPL v2 - * ZeroTier Modifications: change name of driver to ZeroTier, add ioctl() to get L2 multicast memberships (source is in ext/ and modifications inherit GPL) - - * Salsa20 stream cipher, Curve25519 elliptic curve cipher, Ed25519 digital signature algorithm, and Poly1305 MAC algorithm, all by Daniel J. Bernstein - - * Files: node/Salsa20.* node/C25519.* node/Poly1305.* - * Home page: http://cr.yp.to/ - * License grant: public domain - * ZeroTier Modifications: slight cryptographically-irrelevant modifications for inclusion into ZeroTier core - - * MiniUPNPC and libnatpmp by Thomas Bernard - - * Files: ext/libnatpmp/* ext/miniupnpc/* - * Home page: http://miniupnp.free.fr/ - * License grant: BSD attribution no-endorsement - - * cpp-httplib by yhirose - - * Files: ext/cpp-httplib/* - * Home page: https://github.com/yhirose/cpp-httplib - * License grant: MIT diff --git a/COPYING b/COPYING index d07f3524..7f0801e2 100644 --- a/COPYING +++ b/COPYING @@ -1,7 +1,7 @@ ZeroTier One, an endpoint server for the ZeroTier virtual network layer. Copyright © 2011–2019 ZeroTier, Inc. -ZeroTier is released under the terms of the BSL version 1.1. See the +ZeroTier is released under the terms of the BUSL version 1.1. See the file LICENSE.txt for details. .. diff --git a/OFFICIAL-RELEASE-STEPS.md b/OFFICIAL-RELEASE-STEPS.md index f7842e9f..0c198bd6 100644 --- a/OFFICIAL-RELEASE-STEPS.md +++ b/OFFICIAL-RELEASE-STEPS.md @@ -30,4 +30,4 @@ You will need [Packages](http://s.sudre.free.fr/Software/Packages/about.html) an ## Windows -First load the Visual Studio solution and rebuild the UI and ZeroTier One in both x64 and i386 `Release` mode. Then load [Advanced Installer Enterprise](http://www.advancedinstaller.com/), check that the version is correct, and build. The build will fail if any build artifacts are missing, and Windows must have our product singing key (from DigiCert) available to sign the resulting MSI file. The MSI must then be tested on at least a few different CLEAN Windows VMs to ensure that the installer is valid and properly signed. +First load the Visual Studio solution and rebuild the UI and ZeroTier One in both x64, i386, and arm64 `Release` mode. Then load [Advanced Installer Enterprise](http://www.advancedinstaller.com/), check that the version is correct, and build. The build will fail if any build artifacts are missing, and Windows must have our product singing key (from DigiCert) available to sign the resulting MSI file. The MSI must then be tested on at least a few different CLEAN Windows VMs to ensure that the installer is valid and properly signed. diff --git a/attic/WinUI/APIHandler.cs b/attic/WinUI/APIHandler.cs deleted file mode 100644 index 7192f3f2..00000000 --- a/attic/WinUI/APIHandler.cs +++ /dev/null @@ -1,459 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Net; -using System.IO; -using System.Windows; -using Newtonsoft.Json; -using System.Diagnostics; -using System.Windows.Threading; - -namespace WinUI -{ - - - public class APIHandler - { - private string authtoken; - - private string url = null; - - private static volatile APIHandler instance; - private static object syncRoot = new Object(); - - public delegate void NetworkListCallback(List networks); - public delegate void StatusCallback(ZeroTierStatus status); - - private string ZeroTierAddress = ""; - - public static APIHandler Instance - { - get - { - if (instance == null) - { - lock (syncRoot) - { - if (instance == null) - { - if (!initHandler()) - { - return null; - } - } - } - } - - return instance; - } - } - - private static bool initHandler(bool resetToken = false) - { - String localZtDir = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) + "\\ZeroTier\\One"; - String globalZtDir = Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData) + "\\ZeroTier\\One"; - - String authToken = ""; - Int32 port = 9993; - - if (resetToken) - { - instance = null; - if (File.Exists(localZtDir + "\\authtoken.secret")) - { - File.Delete(localZtDir + "\\authtoken.secret"); - } - - if (File.Exists(localZtDir + "\\zerotier-one.port")) - { - File.Delete(localZtDir + "\\zerotier-one.port"); - } - } - - if (!File.Exists(localZtDir + "\\authtoken.secret") || !File.Exists(localZtDir + "\\zerotier-one.port")) - { - // launch external process to copy file into place - String curPath = System.Reflection.Assembly.GetEntryAssembly().Location; - int index = curPath.LastIndexOf("\\"); - curPath = curPath.Substring(0, index); - ProcessStartInfo startInfo = new ProcessStartInfo(curPath + "\\copyutil.exe", "\"" + globalZtDir + "\"" + " " + "\"" + localZtDir + "\""); - startInfo.Verb = "runas"; - - - var process = Process.Start(startInfo); - process.WaitForExit(); - } - - authToken = readAuthToken(localZtDir + "\\authtoken.secret"); - - if ((authToken == null) || (authToken.Length <= 0)) - { - MessageBox.Show("Unable to read ZeroTier One authtoken", "ZeroTier One"); - return false; - } - - port = readPort(localZtDir + "\\zerotier-one.port"); - instance = new APIHandler(port, authToken); - return true; - } - - private static String readAuthToken(String path) - { - String authToken = ""; - - if (File.Exists(path)) - { - try - { - byte[] tmp = File.ReadAllBytes(path); - authToken = System.Text.Encoding.UTF8.GetString(tmp).Trim(); - } - catch - { - MessageBox.Show("Unable to read ZeroTier One Auth Token from:\r\n" + path, "ZeroTier One"); - } - } - - return authToken; - } - - private static Int32 readPort(String path) - { - Int32 port = 9993; - - try - { - byte[] tmp = File.ReadAllBytes(path); - port = Int32.Parse(System.Text.Encoding.ASCII.GetString(tmp).Trim()); - if ((port <= 0) || (port > 65535)) - port = 9993; - } - catch - { - } - - return port; - } - - private APIHandler() - { - url = "http://127.0.0.1:9993"; - } - - public APIHandler(int port, string authtoken) - { - url = "http://127.0.0.1:" + port; - this.authtoken = authtoken; - } - - - - public void GetStatus(StatusCallback cb) - { - var request = WebRequest.Create(url + "/status" + "?auth=" + authtoken) as HttpWebRequest; - if (request != null) - { - request.Method = "GET"; - request.ContentType = "application/json"; - } - - try - { - var httpResponse = (HttpWebResponse)request.GetResponse(); - if (httpResponse.StatusCode == HttpStatusCode.OK) - { - using (var streamReader = new StreamReader(httpResponse.GetResponseStream())) - { - var responseText = streamReader.ReadToEnd(); - - ZeroTierStatus status = null; - try - { - status = JsonConvert.DeserializeObject(responseText); - - if (ZeroTierAddress != status.Address) - { - ZeroTierAddress = status.Address; - } - } - catch (JsonReaderException e) - { - Console.WriteLine(e.ToString()); - } - cb(status); - } - } - else if (httpResponse.StatusCode == HttpStatusCode.Unauthorized) - { - APIHandler.initHandler(true); - } - } - catch (System.Net.Sockets.SocketException) - { - cb(null); - } - catch (System.Net.WebException e) - { - HttpWebResponse res = (HttpWebResponse)e.Response; - if (res != null && res.StatusCode == HttpStatusCode.Unauthorized) - { - APIHandler.initHandler(true); - } - else - { - cb(null); - } - } - } - - - - public void GetNetworks(NetworkListCallback cb) - { - var request = WebRequest.Create(url + "/network" + "?auth=" + authtoken) as HttpWebRequest; - if (request == null) - { - cb(null); - } - - request.Method = "GET"; - request.ContentType = "application/json"; - request.Timeout = 10000; - - try - { - var httpResponse = (HttpWebResponse)request.GetResponse(); - - if (httpResponse.StatusCode == HttpStatusCode.OK) - { - using (var streamReader = new StreamReader(httpResponse.GetResponseStream())) - { - var responseText = streamReader.ReadToEnd(); - - List networkList = null; - try - { - networkList = JsonConvert.DeserializeObject>(responseText); - foreach (ZeroTierNetwork n in networkList) - { - // all networks received via JSON are connected by definition - n.IsConnected = true; - } - } - catch (JsonReaderException e) - { - Console.WriteLine(e.ToString()); - } - cb(networkList); - } - } - else if (httpResponse.StatusCode == HttpStatusCode.Unauthorized) - { - APIHandler.initHandler(true); - } - } - catch (System.Net.Sockets.SocketException) - { - cb(null); - } - catch (System.Net.WebException e) - { - HttpWebResponse res = (HttpWebResponse)e.Response; - if (res != null && res.StatusCode == HttpStatusCode.Unauthorized) - { - APIHandler.initHandler(true); - } - else - { - cb(null); - } - } - } - - public void JoinNetwork(Dispatcher d, string nwid, bool allowManaged = true, bool allowGlobal = false, bool allowDefault = false, bool allowDNS = false) - { - Task.Factory.StartNew(() => - { - var request = WebRequest.Create(url + "/network/" + nwid + "?auth=" + authtoken) as HttpWebRequest; - if (request == null) - { - return; - } - - request.Method = "POST"; - request.ContentType = "applicaiton/json"; - request.Timeout = 30000; - try - { - using (var streamWriter = new StreamWriter(((HttpWebRequest)request).GetRequestStream())) - { - string json = "{\"allowManaged\":" + (allowManaged ? "true" : "false") + "," + - "\"allowGlobal\":" + (allowGlobal ? "true" : "false") + "," + - "\"allowDefault\":" + (allowDefault ? "true" : "false") + "," + - "\"allowDNS\":" + (allowDNS ? "true" : "false") + "}"; - streamWriter.Write(json); - streamWriter.Flush(); - streamWriter.Close(); - } - } - catch (System.Net.WebException) - { - d.BeginInvoke(DispatcherPriority.Normal, new Action(() => - { - MessageBox.Show("Error Joining Network: Cannot connect to ZeroTier service."); - })); - return; - } - - try - { - var httpResponse = (HttpWebResponse)request.GetResponse(); - - if (httpResponse.StatusCode == HttpStatusCode.Unauthorized) - { - APIHandler.initHandler(true); - } - else if (httpResponse.StatusCode != HttpStatusCode.OK) - { - Console.WriteLine("Error sending join network message"); - } - } - catch (System.Net.Sockets.SocketException) - { - d.BeginInvoke(DispatcherPriority.Normal, new Action(() => - { - MessageBox.Show("Error Joining Network: Cannot connect to ZeroTier service."); - })); - } - catch (System.Net.WebException e) - { - HttpWebResponse res = (HttpWebResponse)e.Response; - if (res != null && res.StatusCode == HttpStatusCode.Unauthorized) - { - APIHandler.initHandler(true); - } - d.BeginInvoke(DispatcherPriority.Normal, new Action(() => - { - MessageBox.Show("Error Joining Network: Cannot connect to ZeroTier service."); - })); - } - }); - } - - public void LeaveNetwork(Dispatcher d, string nwid) - { - Task.Factory.StartNew(() => - { - var request = WebRequest.Create(url + "/network/" + nwid + "?auth=" + authtoken) as HttpWebRequest; - if (request == null) - { - return; - } - - request.Method = "DELETE"; - request.Timeout = 30000; - - try - { - var httpResponse = (HttpWebResponse)request.GetResponse(); - - if (httpResponse.StatusCode == HttpStatusCode.Unauthorized) - { - APIHandler.initHandler(true); - } - else if (httpResponse.StatusCode != HttpStatusCode.OK) - { - Console.WriteLine("Error sending leave network message"); - } - } - catch (System.Net.Sockets.SocketException) - { - d.BeginInvoke(DispatcherPriority.Normal, new Action(() => - { - MessageBox.Show("Error Leaving Network: Cannot connect to ZeroTier service."); - })); - } - catch (System.Net.WebException e) - { - HttpWebResponse res = (HttpWebResponse)e.Response; - if (res != null && res.StatusCode == HttpStatusCode.Unauthorized) - { - APIHandler.initHandler(true); - } - d.BeginInvoke(DispatcherPriority.Normal, new Action(() => - { - MessageBox.Show("Error Leaving Network: Cannot connect to ZeroTier service."); - })); - } - catch - { - Console.WriteLine("Error leaving network: Unknown error"); - } - }); - } - - public delegate void PeersCallback(List peers); - - public void GetPeers(PeersCallback cb) - { - var request = WebRequest.Create(url + "/peer" + "?auth=" + authtoken) as HttpWebRequest; - if (request == null) - { - cb(null); - } - - request.Method = "GET"; - request.ContentType = "application/json"; - - try - { - var httpResponse = (HttpWebResponse)request.GetResponse(); - if (httpResponse.StatusCode == HttpStatusCode.OK) - { - using (var streamReader = new StreamReader(httpResponse.GetResponseStream())) - { - var responseText = streamReader.ReadToEnd(); - //Console.WriteLine(responseText); - List peerList = null; - try - { - peerList = JsonConvert.DeserializeObject>(responseText); - } - catch (JsonReaderException e) - { - Console.WriteLine(e.ToString()); - } - cb(peerList); - } - } - else if (httpResponse.StatusCode == HttpStatusCode.Unauthorized) - { - APIHandler.initHandler(true); - } - } - catch (System.Net.Sockets.SocketException) - { - cb(null); - } - catch (System.Net.WebException e) - { - HttpWebResponse res = (HttpWebResponse)e.Response; - if (res != null && res.StatusCode == HttpStatusCode.Unauthorized) - { - APIHandler.initHandler(true); - } - else - { - cb(null); - } - } - } - - public string NodeAddress() - { - return ZeroTierAddress; - } - } -} diff --git a/attic/WinUI/AboutView.xaml b/attic/WinUI/AboutView.xaml deleted file mode 100644 index 295d27bd..00000000 --- a/attic/WinUI/AboutView.xaml +++ /dev/null @@ -1,35 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/attic/WinUI/AboutView.xaml.cs b/attic/WinUI/AboutView.xaml.cs deleted file mode 100644 index 9c48493d..00000000 --- a/attic/WinUI/AboutView.xaml.cs +++ /dev/null @@ -1,35 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Windows; -using System.Windows.Controls; -using System.Windows.Data; -using System.Windows.Documents; -using System.Windows.Input; -using System.Windows.Media; -using System.Windows.Media.Imaging; -using System.Windows.Navigation; -using System.Windows.Shapes; - -namespace WinUI -{ - /// - /// Interaction logic for AboutView.xaml - /// - public partial class AboutView : Window - { - public AboutView() - { - InitializeComponent(); - } - - private void Hyperlink_MouseLeftButtonDown(object sender, RequestNavigateEventArgs e) - { - var hyperlink = (Hyperlink)sender; - Process.Start(hyperlink.NavigateUri.ToString()); - } - } -} diff --git a/attic/WinUI/App.config b/attic/WinUI/App.config deleted file mode 100644 index 8e156463..00000000 --- a/attic/WinUI/App.config +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/attic/WinUI/App.xaml b/attic/WinUI/App.xaml deleted file mode 100644 index 12ed85f9..00000000 --- a/attic/WinUI/App.xaml +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - - - - diff --git a/attic/WinUI/App.xaml.cs b/attic/WinUI/App.xaml.cs deleted file mode 100644 index 53ef2f67..00000000 --- a/attic/WinUI/App.xaml.cs +++ /dev/null @@ -1,25 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Configuration; -using System.Data; -using System.Linq; -using System.Threading.Tasks; -using System.Windows; -using Hardcodet.Wpf.TaskbarNotification; - -namespace WinUI -{ - /// - /// Interaction logic for App.xaml - /// - public partial class App : Application - { - private TaskbarIcon tb; - - private void InitApplication() - { - tb = (TaskbarIcon)FindResource("NotifyIcon"); - tb.Visibility = Visibility.Visible; - } - } -} diff --git a/attic/WinUI/CentralAPI.cs b/attic/WinUI/CentralAPI.cs deleted file mode 100644 index 22bdc697..00000000 --- a/attic/WinUI/CentralAPI.cs +++ /dev/null @@ -1,256 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Net; -using System.Net.Http; -using System.Text; -using System.Threading.Tasks; -using Newtonsoft.Json; - -namespace WinUI -{ - class CentralAPI - { - private static volatile CentralAPI instance; - private static object syncRoot = new Object(); - - private CookieContainer cookieContainer; - private HttpClientHandler clientHandler; - private HttpClient client; - - private CentralServer server; - public CentralServer Central - { - get - { - return this.server; - } - set - { - this.server = value; - WriteCentralConfig(); - UpdateRequestHeaders(); - } - } - - public static CentralAPI Instance - { - get - { - if (instance == null) - { - lock (syncRoot) - { - if (instance == null) - { - instance = new CentralAPI(); - } - } - } - - return instance; - } - } - - - - private CentralAPI() - { -#if DEBUG - ServicePointManager.ServerCertificateValidationCallback += (sender, cert, chain, sslPolicyErrors) => true; -#endif - cookieContainer = new CookieContainer(); - clientHandler = new HttpClientHandler - { - AllowAutoRedirect = true, - UseCookies = true, - CookieContainer = cookieContainer - }; - - client = new HttpClient(clientHandler); - - string centralConfigPath = CentralConfigFile(); - if (File.Exists(centralConfigPath)) - { - byte[] tmp = File.ReadAllBytes(centralConfigPath); - string json = Encoding.UTF8.GetString(tmp).Trim(); - CentralServer ctmp = JsonConvert.DeserializeObject(json); - if (ctmp != null) - { - Central = ctmp; - } - else - { - Central = new CentralServer(); - } - } - else - { - Central = new CentralServer(); - } - } - - public bool HasAccessToken() - { - if (Central == null) - return false; - - return !string.IsNullOrEmpty(Central.APIKey); - } - - private string ZeroTierDir() - { - return Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) + "\\ZeroTier\\One"; - } - - private string CentralConfigFile() - { - return ZeroTierDir() + "\\central.conf"; - } - - public void WriteCentralConfig() - { - string json = JsonConvert.SerializeObject(Central); - byte[] tmp = Encoding.UTF8.GetBytes(json); - if (tmp != null) - { - File.WriteAllBytes(CentralConfigFile(), tmp); - } - } - - private void UpdateRequestHeaders() - { - if (client.DefaultRequestHeaders.Contains("Authorization")) - { - client.DefaultRequestHeaders.Remove("Authorization"); - } - - if (!string.IsNullOrEmpty(Central.APIKey)) - { - client.DefaultRequestHeaders.Add("Authorization", "bearer " + Central.APIKey); - } - } - - public async Task Login(string email, string password, bool isNewUser) - { - string postURL = Central.ServerURL + "/api/_auth/local"; - CentralLogin login = new CentralLogin(email, password, isNewUser); - var content = new StringContent(JsonConvert.SerializeObject(login), Encoding.UTF8, "application/json"); - HttpResponseMessage response = await client.PostAsync(postURL, content); - - if (!response.IsSuccessStatusCode) - { - return false; - } - - string resContent = await response.Content.ReadAsStringAsync(); - - CentralUser user = JsonConvert.DeserializeObject(resContent); - - if (user.Tokens.Count == 0) - { - // create token - user = await CreateAuthToken(user); - } - - Central.APIKey = user.Tokens[0]; - - UpdateRequestHeaders(); - WriteCentralConfig(); - - return true; - } - - public async Task CreateAuthToken(CentralUser user) - { - string randomTokenURL = Central.ServerURL + "/api/randomToken"; - HttpResponseMessage response = await client.GetAsync(randomTokenURL); - - if (!response.IsSuccessStatusCode) - { - // TODO: throw an error - return null; - } - - string resContent = await response.Content.ReadAsStringAsync(); - - CentralToken t = JsonConvert.DeserializeObject(resContent); - - user.Tokens.Add(t.Token); - - string tokenObj = "{ \"tokens\": " + JsonConvert.SerializeObject(user.Tokens) + " } "; - - string postURL = Central.ServerURL + "/api/user/" + user.Id; - var postContent = new StringContent(tokenObj, Encoding.UTF8, "application/json"); - response = await client.PostAsync(postURL, postContent); - - if (!response.IsSuccessStatusCode) - { - // TODO: thrown an error - return null; - } - - resContent = await response.Content.ReadAsStringAsync(); - user = JsonConvert.DeserializeObject(resContent); - - return user; - } - - public async Task> GetNetworkList() - { - string networkURL = Central.ServerURL + "/api/network"; - - HttpResponseMessage response = await client.GetAsync(networkURL); - - if (!response.IsSuccessStatusCode) - { - // TODO: Throw Error - return new List(); - } - - string resContent = await response.Content.ReadAsStringAsync(); - - List networkList = JsonConvert.DeserializeObject>(resContent); - - return networkList; - } - - public async Task CreateNewNetwork() - { - string networkURL = Central.ServerURL + "/api/network?easy=1"; - CentralNetwork network = new CentralNetwork(); - network.Config = new CentralNetwork.CentralNetworkConfig(); - network.Config.Name = NetworkNameGenerator.GenerateName(); - string jsonNetwork = JsonConvert.SerializeObject(network); - var postContent = new StringContent(jsonNetwork, Encoding.UTF8, "application/json"); - HttpResponseMessage response = await client.PostAsync(networkURL, postContent); - - if (!response.IsSuccessStatusCode) - { - return null; - } - - string resContent = await response.Content.ReadAsStringAsync(); - - CentralNetwork newNetwork = JsonConvert.DeserializeObject(resContent); - - return newNetwork; - } - - public async Task AuthorizeNode(string nodeAddress, string networkId) - { - string json = "{ \"config\": { \"authorized\": true } }"; - string postURL = Central.ServerURL + "/api/network/" + networkId + "/member/" + nodeAddress; - var postContent = new StringContent(json, Encoding.UTF8, "application/json"); - HttpResponseMessage response = await client.PostAsync(postURL, postContent); - - if (response.IsSuccessStatusCode) - { - return true; - } - - return false; - } - } -} diff --git a/attic/WinUI/CentralLogin.cs b/attic/WinUI/CentralLogin.cs deleted file mode 100644 index 97265dcf..00000000 --- a/attic/WinUI/CentralLogin.cs +++ /dev/null @@ -1,30 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Newtonsoft.Json; - -namespace WinUI -{ - class CentralLogin - { - - - public CentralLogin(string email, string password, bool isNew) - { - Login = email; - Password = password; - IsNew = isNew; - } - - [JsonProperty("login")] - public string Login { get; set; } - - [JsonProperty("password")] - public string Password { get; set; } - - [JsonProperty("register")] - public bool IsNew { get; set; } - } -} diff --git a/attic/WinUI/CentralNetwork.cs b/attic/WinUI/CentralNetwork.cs deleted file mode 100644 index 26ad5234..00000000 --- a/attic/WinUI/CentralNetwork.cs +++ /dev/null @@ -1,48 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Newtonsoft.Json; - -namespace WinUI -{ - class CentralNetwork - { - [JsonProperty("id")] - public string Id { get; set; } - - [JsonProperty("type")] - public string Type { get; set; } - - [JsonProperty("clock")] - public UInt64 Clock { get; set; } - - [JsonProperty("rulesSource")] - public string RulesSource { get; set; } - - [JsonProperty("description")] - public string Description { get; set; } - - [JsonProperty("ownerId")] - public string OwnerID { get; set; } - - [JsonProperty("onlineMemberCount")] - public int OnlineMemberCount { get; set; } - - [JsonProperty("config")] - public CentralNetworkConfig Config { get; set; } - - public class CentralNetworkConfig - { - [JsonProperty("id")] - public string Id { get; set; } - - [JsonProperty("nwid")] - public string NetworkID { get; set; } - - [JsonProperty("name")] - public string Name { get; set; } - } - } -} diff --git a/attic/WinUI/CentralServer.cs b/attic/WinUI/CentralServer.cs deleted file mode 100644 index 8e268653..00000000 --- a/attic/WinUI/CentralServer.cs +++ /dev/null @@ -1,23 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Newtonsoft.Json; - -namespace WinUI -{ - class CentralServer - { - public CentralServer() - { - ServerURL = "https://my.zerotier.com"; - } - - [JsonProperty("server_url")] - public string ServerURL { get; set; } - - [JsonProperty("api_key")] - public string APIKey { get; set; } - } -} diff --git a/attic/WinUI/CentralToken.cs b/attic/WinUI/CentralToken.cs deleted file mode 100644 index 1db548aa..00000000 --- a/attic/WinUI/CentralToken.cs +++ /dev/null @@ -1,21 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Newtonsoft.Json; - -namespace WinUI -{ - class CentralToken - { - [JsonProperty("token")] - public string Token { get; set; } - - [JsonProperty("clock")] - public UInt64 Clock { get; set; } - - [JsonProperty("raw")] - public string Raw { get; set; } - } -} diff --git a/attic/WinUI/CentralUser.cs b/attic/WinUI/CentralUser.cs deleted file mode 100644 index 8a8945a2..00000000 --- a/attic/WinUI/CentralUser.cs +++ /dev/null @@ -1,51 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Newtonsoft.Json; - -namespace WinUI -{ - class CentralUser - { - public class CentralGlobalPermissions - { - [JsonProperty("a")] - public bool Administrator { get; set; } - - [JsonProperty("d")] - public bool Delete { get; set; } - - [JsonProperty("m")] - public bool Modify { get; set; } - - [JsonProperty("r")] - public bool Read { get; set; } - } - - [JsonProperty("id")] - public string Id { get; set; } - - [JsonProperty("type")] - public string Type { get; set; } - - [JsonProperty("clock")] - public UInt64 Clock { get; set; } - - [JsonProperty("globalPermissions")] - public CentralGlobalPermissions GlobalPermissions { get; set; } - - [JsonProperty("displayName")] - public string DisplayName { get; set; } - - [JsonProperty("email")] - public string Email { get; set; } - - [JsonProperty("smsNumber")] - public string SmsNumber { get; set; } - - [JsonProperty("tokens")] - public List Tokens { get; set; } - } -} diff --git a/attic/WinUI/Fonts/segoeui.ttf b/attic/WinUI/Fonts/segoeui.ttf deleted file mode 100644 index fc18ebd0..00000000 Binary files a/attic/WinUI/Fonts/segoeui.ttf and /dev/null differ diff --git a/attic/WinUI/Fonts/segoeuib.ttf b/attic/WinUI/Fonts/segoeuib.ttf deleted file mode 100644 index 5f31e0ca..00000000 Binary files a/attic/WinUI/Fonts/segoeuib.ttf and /dev/null differ diff --git a/attic/WinUI/Fonts/segoeuii.ttf b/attic/WinUI/Fonts/segoeuii.ttf deleted file mode 100644 index 7efb70d6..00000000 Binary files a/attic/WinUI/Fonts/segoeuii.ttf and /dev/null differ diff --git a/attic/WinUI/Fonts/segoeuiz.ttf b/attic/WinUI/Fonts/segoeuiz.ttf deleted file mode 100644 index d7bb186b..00000000 Binary files a/attic/WinUI/Fonts/segoeuiz.ttf and /dev/null differ diff --git a/attic/WinUI/ISwitchable.cs b/attic/WinUI/ISwitchable.cs deleted file mode 100644 index e485a14c..00000000 --- a/attic/WinUI/ISwitchable.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace WinUI -{ - interface ISwitchable - { - void UtilizeState(object state); - } -} diff --git a/attic/WinUI/JoinNetworkView.xaml b/attic/WinUI/JoinNetworkView.xaml deleted file mode 100644 index 9898f020..00000000 --- a/attic/WinUI/JoinNetworkView.xaml +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - - - - - - - - - - - diff --git a/attic/macui/ZeroTier One/Network.h b/attic/macui/ZeroTier One/Network.h deleted file mode 100644 index c1cfbaf2..00000000 --- a/attic/macui/ZeroTier One/Network.h +++ /dev/null @@ -1,69 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#import - -enum NetworkStatus { - REQUESTING_CONFIGURATION, - OK, - ACCESS_DENIED, - NOT_FOUND, - PORT_ERROR, - CLIENT_TOO_OLD, -}; - -enum NetworkType { - PUBLIC, - PRIVATE, -}; - -@interface Network : NSObject - -@property (readonly) NSArray *assignedAddresses; -@property (readonly) BOOL bridge; -@property (readonly) BOOL broadcastEnabled; -@property (readonly) BOOL dhcp; -@property (readonly) NSString *mac; -@property (readonly) int mtu; -@property (readonly) int netconfRevision; -@property (readonly) NSString *name; -@property (readonly) UInt64 nwid; -@property (readonly) NSString *portDeviceName; -@property (readonly) int portError; -@property (readonly) enum NetworkStatus status; -@property (readonly) enum NetworkType type; -@property (readonly) BOOL allowManaged; -@property (readonly) BOOL allowGlobal; -@property (readonly) BOOL allowDefault; -@property (readonly) BOOL allowDNS; -@property (readonly) BOOL connected; // not persisted. set to YES if loaded via json - -- (id)initWithJsonData:(NSDictionary*)jsonData; -- (id)initWithCoder:(NSCoder *)aDecoder; -- (void)encodeWithCoder:(NSCoder *)aCoder; -+ (BOOL)defaultRouteExists:(NSArray*)netList; -- (NSString*)statusString; -- (NSString*)typeString; - -- (BOOL)hasSameNetworkId:(UInt64)networkId; - -- (BOOL)isEqualToNetwork:(Network*)network; -- (BOOL)isEqual:(id)object; -- (NSUInteger)hash; - -@end diff --git a/attic/macui/ZeroTier One/Network.m b/attic/macui/ZeroTier One/Network.m deleted file mode 100644 index 2379eb69..00000000 --- a/attic/macui/ZeroTier One/Network.m +++ /dev/null @@ -1,352 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#import "Network.h" - -NSString *NetworkAddressesKey = @"addresses"; -NSString *NetworkBridgeKey = @"bridge"; -NSString *NetworkBroadcastKey = @"broadcast"; -NSString *NetworkDhcpKey = @"dhcp"; -NSString *NetworkMacKey = @"mac"; -NSString *NetworkMtuKey = @"mtu"; -NSString *NetworkMulticastKey = @"multicast"; -NSString *NetworkNameKey = @"name"; -NSString *NetworkNetconfKey = @"netconf"; -NSString *NetworkNwidKey = @"nwid"; -NSString *NetworkPortNameKey = @"port"; -NSString *NetworkPortErrorKey = @"portError"; -NSString *NetworkStatusKey = @"status"; -NSString *NetworkTypeKey = @"type"; -NSString *NetworkAllowManagedKey = @"allowManaged"; -NSString *NetworkAllowGlobalKey = @"allowGlobal"; -NSString *NetworkAllowDefaultKey = @"allowDefault"; -NSString *NetworkAllowDNSKey = @"allowDNS"; - -@implementation Network - -- (id)initWithJsonData:(NSDictionary*)jsonData -{ - self = [super init]; - - if(self) { - if([jsonData objectForKey:@"assignedAddresses"]) { - _assignedAddresses = (NSArray*)[jsonData objectForKey:@"assignedAddresses"]; - } - - if([jsonData objectForKey:@"bridge"]) { - _bridge = [(NSNumber*)[jsonData objectForKey:@"bridge"] boolValue]; - } - - if([jsonData objectForKey:@"broadcastEnabled"]) { - _broadcastEnabled = [(NSNumber*)[jsonData objectForKey:@"broadcastEnabled"] boolValue]; - } - - if([jsonData objectForKey:@"dhcp"]) { - _dhcp = [(NSNumber*)[jsonData objectForKey:@"dhcp"] boolValue]; - } - - if([jsonData objectForKey:@"mac"]) { - _mac = (NSString*)[jsonData objectForKey:@"mac"]; - } - - if([jsonData objectForKey:@"mtu"]) { - _mtu = [(NSNumber*)[jsonData objectForKey:@"mtu"] intValue]; - } - - if([jsonData objectForKey:@"name"]) { - _name = (NSString*)[jsonData objectForKey:@"name"]; - } - - if([jsonData objectForKey:@"netconfRevision"]) { - _netconfRevision = [(NSNumber*)[jsonData objectForKey:@"netconfRevision"] intValue]; - } - - if([jsonData objectForKey:@"nwid"]) { - NSString *networkid = (NSString*)[jsonData objectForKey:@"nwid"]; - - NSScanner *scanner = [NSScanner scannerWithString:networkid]; - [scanner scanHexLongLong:&_nwid]; - } - - if([jsonData objectForKey:@"portDeviceName"]) { - _portDeviceName = (NSString*)[jsonData objectForKey:@"portDeviceName"]; - } - - if([jsonData objectForKey:@"portError"]) { - _portError = [(NSNumber*)[jsonData objectForKey:@"portError"] intValue]; - } - - if([jsonData objectForKey:@"allowManaged"]) { - _allowManaged = [(NSNumber*)[jsonData objectForKey:@"allowManaged"] boolValue]; - } - - if([jsonData objectForKey:@"allowGlobal"]) { - _allowGlobal = [(NSNumber*)[jsonData objectForKey:@"allowGlobal"] boolValue]; - } - - if([jsonData objectForKey:@"allowDefault"]) { - _allowDefault = [(NSNumber*)[jsonData objectForKey:@"allowDefault"] boolValue]; - } - if([jsonData objectForKey:@"allowDNS"]) { - _allowDNS = [(NSNumber*)[jsonData objectForKey:@"allowDNS"] boolValue]; - } else { - _allowDNS = false; - } - - if([jsonData objectForKey:@"status"]) { - NSString *statusStr = (NSString*)[jsonData objectForKey:@"status"]; - if([statusStr isEqualToString:@"REQUESTING_CONFIGURATION"]) { - _status = REQUESTING_CONFIGURATION; - } - else if([statusStr isEqualToString:@"OK"]) { - _status = OK; - } - else if([statusStr isEqualToString:@"ACCESS_DENIED"]) { - _status = ACCESS_DENIED; - } - else if([statusStr isEqualToString:@"NOT_FOUND"]) { - _status = NOT_FOUND; - } - else if([statusStr isEqualToString:@"PORT_ERROR"]) { - _status = PORT_ERROR; - } - else if([statusStr isEqualToString:@"CLIENT_TOO_OLD"]) { - _status = CLIENT_TOO_OLD; - } - } - - if([jsonData objectForKey:@"type"]) { - NSString *typeStr = (NSString*)[jsonData objectForKey:@"type"]; - if([typeStr isEqualToString:@"PRIVATE"]) { - _type = PRIVATE; - } - else if([typeStr isEqualToString:@"PUBLIC"]) { - _type = PUBLIC; - } - } - - _connected = YES; - } - - return self; -} -- (id)initWithCoder:(NSCoder *)aDecoder -{ - self = [super init]; - - if(self) { - if([aDecoder containsValueForKey:NetworkAddressesKey]) { - _assignedAddresses = (NSArray*)[aDecoder decodeObjectForKey:NetworkAddressesKey]; - } - - if([aDecoder containsValueForKey:NetworkBridgeKey]) { - _bridge = [aDecoder decodeBoolForKey:NetworkBridgeKey]; - } - - if([aDecoder containsValueForKey:NetworkBroadcastKey]) { - _broadcastEnabled = [aDecoder decodeBoolForKey:NetworkBroadcastKey]; - } - - if([aDecoder containsValueForKey:NetworkDhcpKey]) { - _dhcp = [aDecoder decodeBoolForKey:NetworkDhcpKey]; - } - - if([aDecoder containsValueForKey:NetworkMacKey]) { - _mac = (NSString*)[aDecoder decodeObjectForKey:NetworkMacKey]; - } - - if([aDecoder containsValueForKey:NetworkMtuKey]) { - _mtu = (int)[aDecoder decodeIntegerForKey:NetworkMtuKey]; - } - - if([aDecoder containsValueForKey:NetworkNameKey]) { - _name = (NSString*)[aDecoder decodeObjectForKey:NetworkNameKey]; - } - - if([aDecoder containsValueForKey:NetworkNetconfKey]) { - _netconfRevision = (int)[aDecoder decodeIntegerForKey:NetworkNetconfKey]; - } - - if([aDecoder containsValueForKey:NetworkNwidKey]) { - _nwid = [(NSNumber*)[aDecoder decodeObjectForKey:NetworkNwidKey] unsignedLongLongValue]; - } - - if([aDecoder containsValueForKey:NetworkPortNameKey]) { - _portDeviceName = (NSString*)[aDecoder decodeObjectForKey:NetworkPortNameKey]; - } - - if([aDecoder containsValueForKey:NetworkPortErrorKey]) { - _portError = (int)[aDecoder decodeIntegerForKey:NetworkPortErrorKey]; - } - - if([aDecoder containsValueForKey:NetworkStatusKey]) { - _status = (enum NetworkStatus)[aDecoder decodeIntegerForKey:NetworkStatusKey]; - } - - if([aDecoder containsValueForKey:NetworkTypeKey]) { - _type = (enum NetworkType)[aDecoder decodeIntegerForKey:NetworkTypeKey]; - } - - if([aDecoder containsValueForKey:NetworkAllowManagedKey]) { - _allowManaged = [aDecoder decodeBoolForKey:NetworkAllowManagedKey]; - } - - if([aDecoder containsValueForKey:NetworkAllowGlobalKey]) { - _allowGlobal = [aDecoder decodeBoolForKey:NetworkAllowGlobalKey]; - } - - if([aDecoder containsValueForKey:NetworkAllowDefaultKey]) { - _allowDefault = [aDecoder decodeBoolForKey:NetworkAllowDefaultKey]; - } - - if([aDecoder containsValueForKey:NetworkAllowDNSKey]) { - _allowDNS = [aDecoder decodeBoolForKey:NetworkAllowDNSKey]; - } else { - _allowDNS = false; - } - - _connected = NO; - } - - return self; -} - -- (void)encodeWithCoder:(NSCoder *)aCoder -{ - [aCoder encodeObject:_assignedAddresses forKey:NetworkAddressesKey]; - [aCoder encodeBool:_bridge forKey:NetworkBridgeKey]; - [aCoder encodeBool:_broadcastEnabled forKey:NetworkBroadcastKey]; - [aCoder encodeBool:_dhcp forKey:NetworkDhcpKey]; - [aCoder encodeObject:_mac forKey:NetworkMacKey]; - [aCoder encodeInteger:_mtu forKey:NetworkMtuKey]; - [aCoder encodeObject:_name forKey:NetworkNameKey]; - [aCoder encodeInteger:_netconfRevision forKey:NetworkNetconfKey]; - [aCoder encodeObject:[NSNumber numberWithUnsignedLongLong:_nwid] - forKey:NetworkNwidKey]; - [aCoder encodeObject:_portDeviceName forKey:NetworkPortNameKey]; - [aCoder encodeInteger:_portError forKey:NetworkPortErrorKey]; - [aCoder encodeInteger:_status forKey:NetworkStatusKey]; - [aCoder encodeInteger:_type forKey:NetworkTypeKey]; - [aCoder encodeBool:_allowManaged forKey:NetworkAllowManagedKey]; - [aCoder encodeBool:_allowGlobal forKey:NetworkAllowGlobalKey]; - [aCoder encodeBool:_allowDefault forKey:NetworkAllowDefaultKey]; - [aCoder encodeBool:_allowDNS forKey:NetworkAllowDNSKey]; -} - -+ (BOOL)defaultRouteExists:(NSArray*)netList -{ - for(Network *net in netList) { - if (net.allowDefault && net.connected) { - return YES; - } - } - return NO; -} - -- (NSString*)statusString { - switch(_status) { - case REQUESTING_CONFIGURATION: - return @"REQUESTING_CONFIGURATION"; - case OK: - return @"OK"; - case ACCESS_DENIED: - return @"ACCESS_DENIED"; - case NOT_FOUND: - return @"NOT_FOUND"; - case PORT_ERROR: - return @"PORT_ERROR"; - case CLIENT_TOO_OLD: - return @"CLIENT_TOO_OLD"; - default: - return @""; - } -} - -- (NSString*)typeString { - switch(_type) { - case PUBLIC: - return @"PUBLIC"; - case PRIVATE: - return @"PRIVATE"; - default: - return @""; - } -} - -- (BOOL)hasSameNetworkId:(UInt64)networkId -{ - return self.nwid == networkId; -} - -- (BOOL)isEqualToNetwork:(Network*)network -{ - return [self.assignedAddresses isEqualToArray:network.assignedAddresses] && - self.bridge == network.bridge && - self.broadcastEnabled == network.broadcastEnabled && - self.dhcp == network.dhcp && - [self.mac isEqualToString:network.mac] && - self.mtu == network.mtu && - self.netconfRevision == network.netconfRevision && - [self.name isEqualToString:network.name] && - self.nwid == network.nwid && - [self.portDeviceName isEqualToString:network.portDeviceName] && - self.status == network.status && - self.type == network.type && - self.allowManaged == network.allowManaged && - self.allowGlobal == network.allowGlobal && - self.allowDefault == network.allowDefault && - self.allowDNS == network.allowDNS && - self.connected == network.connected; -} - -- (BOOL)isEqual:(id)object -{ - if (self == object) { - return YES; - } - - if (![object isKindOfClass:[Network class]]) { - return NO; - } - - return [self isEqualToNetwork:object]; -} - -- (NSUInteger)hash -{ - return [self.assignedAddresses hash] ^ - self.bridge ^ - self.broadcastEnabled ^ - self.dhcp ^ - [self.mac hash] ^ - self.mtu ^ - self.netconfRevision ^ - [self.name hash] ^ - self.nwid ^ - [self.portDeviceName hash] ^ - self.portError ^ - self.status ^ - self.type ^ - self.allowManaged ^ - self.allowGlobal ^ - self.allowDefault ^ - self.allowDNS ^ - self.connected; -} - -@end diff --git a/attic/macui/ZeroTier One/NetworkInfoCell.h b/attic/macui/ZeroTier One/NetworkInfoCell.h deleted file mode 100644 index f764034e..00000000 --- a/attic/macui/ZeroTier One/NetworkInfoCell.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#import - -@class ShowNetworksViewController; - -@interface NetworkInfoCell : NSTableCellView - -@property (weak, nonatomic) ShowNetworksViewController *parent; - -@property (weak, nonatomic) IBOutlet NSTextField *networkIdField; -@property (weak, nonatomic) IBOutlet NSTextField *networkNameField; -@property (weak, nonatomic) IBOutlet NSTextField *statusField; -@property (weak, nonatomic) IBOutlet NSTextField *typeField; -@property (weak, nonatomic) IBOutlet NSTextField *macField; -@property (weak, nonatomic) IBOutlet NSTextField *mtuField; -@property (weak, nonatomic) IBOutlet NSTextField *broadcastField; -@property (weak, nonatomic) IBOutlet NSTextField *bridgingField; -@property (weak, nonatomic) IBOutlet NSTextField *deviceField; -@property (weak, nonatomic) IBOutlet NSTextField *addressesField; -@property (weak, nonatomic) IBOutlet NSButton *allowManaged; -@property (weak, nonatomic) IBOutlet NSButton *allowGlobal; -@property (weak, nonatomic) IBOutlet NSButton *allowDefault; -@property (weak, nonatomic) IBOutlet NSButton *allowDNS; -@property (weak, nonatomic) IBOutlet NSButton *connectedCheckbox; -@property (weak, nonatomic) IBOutlet NSButton *deleteButton; - -- (IBAction)onConnectCheckStateChanged:(NSButton*)sender; -- (IBAction)deleteNetwork:(NSButton*)sender; -- (IBAction)onAllowStatusChanged:(NSButton*)sender; - -- (void)joinNetwork:(NSString*)nwid; -- (void)leaveNetwork:(NSString*)nwid; - -@end diff --git a/attic/macui/ZeroTier One/NetworkInfoCell.m b/attic/macui/ZeroTier One/NetworkInfoCell.m deleted file mode 100644 index df1bbf67..00000000 --- a/attic/macui/ZeroTier One/NetworkInfoCell.m +++ /dev/null @@ -1,86 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#import "NetworkInfoCell.h" -#import "ServiceCom.h" -#import "ShowNetworksViewController.h" -#import "Network.h" - -@implementation NetworkInfoCell - -- (void)drawRect:(NSRect)dirtyRect { - [super drawRect:dirtyRect]; - - // Drawing code here. -} - -- (IBAction)onConnectCheckStateChanged:(NSButton*)sender -{ - if(sender.state == NSOnState) { - [self joinNetwork:self.networkIdField.stringValue]; - } - else { - [self leaveNetwork:self.networkIdField.stringValue]; - } -} - -- (IBAction)deleteNetwork:(NSButton*)sender; -{ - [self leaveNetwork:self.networkIdField.stringValue]; - [self.parent deleteNetworkFromList:self.networkIdField.stringValue]; -} - -- (IBAction)onAllowStatusChanged:(NSButton*)sender -{ - [self joinNetwork:self.networkIdField.stringValue]; -} - -- (void)joinNetwork:(NSString*)nwid -{ - NSError *error = nil; - [[ServiceCom sharedInstance] joinNetwork:nwid - allowManaged:(self.allowManaged.state == NSOnState) - allowGlobal:(self.allowGlobal.state == NSOnState) - allowDefault:![Network defaultRouteExists:_parent.networkList] && (self.allowDefault.state == NSOnState) - allowDNS:(self.allowDNS.state == NSOnState) - error:&error]; - - if (error) { - NSAlert *alert = [NSAlert alertWithError:error]; - alert.alertStyle = NSCriticalAlertStyle; - [alert addButtonWithTitle:@"Ok"]; - - [alert runModal]; - } -} - -- (void)leaveNetwork:(NSString*)nwid -{ - NSError *error = nil; - [[ServiceCom sharedInstance] leaveNetwork:nwid error:&error]; - - if (error) { - NSAlert *alert = [NSAlert alertWithError:error]; - alert.alertStyle = NSCriticalAlertStyle; - [alert addButtonWithTitle:@"Ok"]; - - [alert runModal]; - } -} - -@end diff --git a/attic/macui/ZeroTier One/NetworkMonitor.h b/attic/macui/ZeroTier One/NetworkMonitor.h deleted file mode 100644 index 8cdec4ed..00000000 --- a/attic/macui/ZeroTier One/NetworkMonitor.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#import - -extern NSString * const NetworkUpdateKey; -extern NSString * const StatusUpdateKey; - -@class Network; - -@interface NetworkMonitor : NSObject -{ - NSMutableArray *_savedNetworks; - NSArray *_receivedNetworks; - NSMutableArray *_allNetworks; - - NSTimer *_timer; -} - -- (id)init; -- (void)dealloc; - -- (void)start; -- (void)stop; - -- (void)updateNetworkInfo; - -- (void)deleteSavedNetwork:(NSString*)networkId; - -@end diff --git a/attic/macui/ZeroTier One/NetworkMonitor.m b/attic/macui/ZeroTier One/NetworkMonitor.m deleted file mode 100644 index 7ed22c4a..00000000 --- a/attic/macui/ZeroTier One/NetworkMonitor.m +++ /dev/null @@ -1,253 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#import "NetworkMonitor.h" -#import "Network.h" -#import "ServiceCom.h" -#import "NodeStatus.h" - -@import AppKit; - - -NSString * const NetworkUpdateKey = @"com.zerotier.one.network-list"; -NSString * const StatusUpdateKey = @"com.zerotier.one.status"; - -@interface NetworkMonitor (private) - -- (NSString*)dataFile; -- (void)internal_updateNetworkInfo; -- (NSInteger)findNetworkWithID:(UInt64)networkId; -- (NSInteger)findSavedNetworkWithID:(UInt64)networkId; -- (void)saveNetworks; - -@end - -@implementation NetworkMonitor - -- (id)init -{ - self = [super init]; - if(self) - { - _savedNetworks = [NSMutableArray array]; - _receivedNetworks = [NSArray array]; - _allNetworks = [NSMutableArray array]; - _timer = nil; - } - - return self; -} - -- (void)dealloc -{ - [_timer invalidate]; -} - -- (void)start -{ - NSLog(@"ZeroTier monitor started"); - _timer = [NSTimer scheduledTimerWithTimeInterval:1.0f - target:self - selector:@selector(updateNetworkInfo) - userInfo:nil - repeats:YES]; -} - -- (void)stop -{ - NSLog(@"ZeroTier monitor stopped"); - [_timer invalidate]; - _timer = nil; -} - -- (void)updateNetworkInfo -{ - NSString *filePath = [self dataFile]; - - if([[NSFileManager defaultManager] fileExistsAtPath:filePath]) { - NSArray *networks = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath]; - - if(networks != nil) { - _savedNetworks = [networks mutableCopy]; - } - } - - NSError *error = nil; - - [[ServiceCom sharedInstance] getNetworklist:^(NSArray *networkList) { - _receivedNetworks = networkList; - - [[NSOperationQueue mainQueue] addOperationWithBlock:^{ - [self internal_updateNetworkInfo]; - } ]; - } error:&error]; - - if(error) { - [self stop]; - - NSAlert *alert = [NSAlert alertWithError:error]; - alert.alertStyle = NSCriticalAlertStyle; - [alert addButtonWithTitle:@"Quit"]; - [alert addButtonWithTitle:@"Retry"]; - - NSModalResponse res = [alert runModal]; - - if(res == NSAlertFirstButtonReturn) { - [NSApp performSelector:@selector(terminate:) withObject:nil afterDelay:0.0]; - } - else if(res == NSAlertSecondButtonReturn) { - [self start]; - return; - } - } - - [[ServiceCom sharedInstance] getNodeStatus:^(NodeStatus *status) { - NSDictionary *userInfo = [NSDictionary dictionaryWithObject:status forKey:@"status"]; - - [[NSOperationQueue mainQueue] addOperationWithBlock:^{ - [[NSNotificationCenter defaultCenter] postNotificationName:StatusUpdateKey - object:nil - userInfo:userInfo]; - }]; - } error:&error]; - - if (error) { - [self stop]; - - NSAlert *alert = [NSAlert alertWithError:error]; - alert.alertStyle = NSCriticalAlertStyle; - [alert addButtonWithTitle:@"Quit"]; - [alert addButtonWithTitle:@"Retry"]; - - NSModalResponse res = [alert runModal]; - - if(res == NSAlertFirstButtonReturn) { - [NSApp performSelector:@selector(terminate:) withObject:nil afterDelay:0.0]; - } - else if(res == NSAlertSecondButtonReturn) { - [self start]; - return; - } - } -} - -- (void)deleteSavedNetwork:(NSString*)networkId -{ - UInt64 nwid = 0; - NSScanner *scanner = [NSScanner scannerWithString:networkId]; - [scanner scanHexLongLong:&nwid]; - - NSInteger index = [self findNetworkWithID:nwid]; - - if(index != NSNotFound) { - [_allNetworks removeObjectAtIndex:index]; - } - - index = [self findSavedNetworkWithID:nwid]; - - if(index != NSNotFound) { - [_savedNetworks removeObjectAtIndex:index]; - } - - [self saveNetworks]; -} - -@end - -@implementation NetworkMonitor (private) -- (NSString*)dataFile -{ - NSURL *appSupport = [[[NSFileManager defaultManager] URLsForDirectory:NSApplicationSupportDirectory - inDomains:NSUserDomainMask] objectAtIndex:0]; - - appSupport = [[[appSupport URLByAppendingPathComponent:@"ZeroTier"] URLByAppendingPathComponent:@"One"] URLByAppendingPathComponent:@"networkinfo.dat"]; - return appSupport.path; -} - -- (void)internal_updateNetworkInfo -{ - NSMutableArray *networks = [_savedNetworks mutableCopy]; - - for(Network *nw in _receivedNetworks) { - NSInteger index = [self findSavedNetworkWithID:nw.nwid]; - - if(index != NSNotFound) { - [networks setObject:nw atIndexedSubscript:index]; - } - else { - [networks addObject:nw]; - } - } - - [networks sortUsingComparator:^NSComparisonResult(Network *obj1, Network *obj2) { - if(obj1.nwid > obj2.nwid) { - return true; - } - return false; - }]; - - @synchronized(_allNetworks) { - _allNetworks = networks; - } - - [self saveNetworks]; - - NSDictionary *userInfo = [NSDictionary dictionaryWithObject:networks forKey:@"networks"]; - - [[NSNotificationCenter defaultCenter] postNotificationName:NetworkUpdateKey - object:nil - userInfo:userInfo]; -} - -- (NSInteger)findNetworkWithID:(UInt64)networkId -{ - for(int i = 0; i < [_allNetworks count]; ++i) { - Network *nw = [_allNetworks objectAtIndex:i]; - - if(nw.nwid == networkId) { - return i; - } - } - - return NSNotFound; -} - - -- (NSInteger)findSavedNetworkWithID:(UInt64)networkId -{ - for(int i = 0; i < [_savedNetworks count]; ++i) { - Network *nw = [_savedNetworks objectAtIndex:i]; - - if(nw.nwid == networkId) { - return i; - } - } - - return NSNotFound; -} - -- (void)saveNetworks -{ - NSString *filePath = [self dataFile]; - - @synchronized(_allNetworks) { - [NSKeyedArchiver archiveRootObject:_allNetworks toFile:filePath]; - } -} - -@end diff --git a/attic/macui/ZeroTier One/NodeStatus.h b/attic/macui/ZeroTier One/NodeStatus.h deleted file mode 100644 index eab5bfe4..00000000 --- a/attic/macui/ZeroTier One/NodeStatus.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#import - -@interface NodeStatus : NSObject - -@property (readonly) NSString *address; -@property (readonly) NSString *publicIdentity; -@property (readonly) BOOL online; -@property (readonly) BOOL tcpFallbackActive; -@property (readonly) int versionMajor; -@property (readonly) int versionMinor; -@property (readonly) int versionRev; -@property (readonly) NSString *version; -@property (readonly) UInt64 clock; - -- (id)initWithJsonData:(NSDictionary*)jsonData; - -@end diff --git a/attic/macui/ZeroTier One/NodeStatus.m b/attic/macui/ZeroTier One/NodeStatus.m deleted file mode 100644 index 3bae3c7d..00000000 --- a/attic/macui/ZeroTier One/NodeStatus.m +++ /dev/null @@ -1,40 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -#import "NodeStatus.h" - -@implementation NodeStatus - -- (id)initWithJsonData:(NSDictionary*)jsonData -{ - self = [super init]; - - if(self) { - _address = (NSString*)[jsonData objectForKey:@"address"]; - _publicIdentity = (NSString*)[jsonData objectForKey:@"publicIdentity"]; - _online = [(NSNumber*)[jsonData objectForKey:@"online"] boolValue]; - _tcpFallbackActive = [(NSNumber*)[jsonData objectForKey:@"tcpFallbackActive"] boolValue]; - _versionMajor = [(NSNumber*)[jsonData objectForKey:@"versionMajor"] intValue]; - _versionMinor = [(NSNumber*)[jsonData objectForKey:@"versionMinor"] intValue]; - _versionRev = [(NSNumber*)[jsonData objectForKey:@"versionRev"] intValue]; - _version = (NSString*)[jsonData objectForKey:@"version"]; - _clock = [(NSNumber*)[jsonData objectForKey:@"clock"] unsignedLongLongValue]; - } - - return self; -} -@end diff --git a/attic/macui/ZeroTier One/PreferencesViewController.h b/attic/macui/ZeroTier One/PreferencesViewController.h deleted file mode 100644 index 56d0fdb8..00000000 --- a/attic/macui/ZeroTier One/PreferencesViewController.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#import - -@interface PreferencesViewController : NSViewController - -@property (nonatomic, weak) IBOutlet NSButton *startupCheckBox; - -- (IBAction)onStartupCheckBoxChanged:(NSButton*)sender; - -- (BOOL)isLaunchAtStartup; -- (LSSharedFileListItemRef)itemRefInLoginItems; -- (void)setLaunchAtLoginEnabled:(BOOL)enabled; - -@end diff --git a/attic/macui/ZeroTier One/PreferencesViewController.m b/attic/macui/ZeroTier One/PreferencesViewController.m deleted file mode 100644 index 13927fba..00000000 --- a/attic/macui/ZeroTier One/PreferencesViewController.m +++ /dev/null @@ -1,112 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#import "PreferencesViewController.h" - -@interface PreferencesViewController () - -@end - -@implementation PreferencesViewController - -- (void)viewDidLoad { - [super viewDidLoad]; - - if([self isLaunchAtStartup]) { - self.startupCheckBox.state = NSOnState; - } - else { - self.startupCheckBox.state = NSOffState; - } -} - -- (IBAction)onStartupCheckBoxChanged:(NSButton *)sender -{ - if(sender.state == NSOnState) { - [self setLaunchAtLoginEnabled:YES]; - } - else { - [self setLaunchAtLoginEnabled:NO]; - } - -} - -- (void)setLaunchAtLoginEnabled:(BOOL)enabled -{ - LSSharedFileListRef loginItemsRef = LSSharedFileListCreate(NULL, kLSSharedFileListSessionLoginItems, NULL); - - if (enabled) { - // Add the app to the LoginItems list. - CFURLRef appUrl = (__bridge CFURLRef)[NSURL fileURLWithPath:[[NSBundle mainBundle] bundlePath]]; - LSSharedFileListItemRef itemRef = LSSharedFileListInsertItemURL(loginItemsRef, kLSSharedFileListItemLast, NULL, NULL, appUrl, NULL, NULL); - if (itemRef) CFRelease(itemRef); - } - else { - // Remove the app from the LoginItems list. - LSSharedFileListItemRef itemRef = [self itemRefInLoginItems]; - LSSharedFileListItemRemove(loginItemsRef,itemRef); - if (itemRef != nil) CFRelease(itemRef); - } -} - - -- (BOOL)isLaunchAtStartup { - // See if the app is currently in LoginItems. - LSSharedFileListItemRef itemRef = [self itemRefInLoginItems]; - // Store away that boolean. - BOOL isInList = itemRef != nil; - // Release the reference if it exists. - if (itemRef != nil) CFRelease(itemRef); - - return isInList; -} - -- (LSSharedFileListItemRef)itemRefInLoginItems { - LSSharedFileListItemRef itemRef = nil; - - NSString * appPath = [[NSBundle mainBundle] bundlePath]; - - // This will retrieve the path for the application - // For example, /Applications/test.app - CFURLRef url = (__bridge CFURLRef)[NSURL fileURLWithPath:appPath]; - - // Create a reference to the shared file list. - LSSharedFileListRef loginItems = LSSharedFileListCreate(NULL, kLSSharedFileListSessionLoginItems, NULL); - - if (loginItems) { - UInt32 seedValue; - //Retrieve the list of Login Items and cast them to - // a NSArray so that it will be easier to iterate. - NSArray *loginItemsArray = (__bridge NSArray *)LSSharedFileListCopySnapshot(loginItems, &seedValue); - for(int i = 0; i< [loginItemsArray count]; i++){ - LSSharedFileListItemRef currentItemRef = (__bridge LSSharedFileListItemRef)[loginItemsArray - objectAtIndex:i]; - //Resolve the item with URL - if (LSSharedFileListItemResolve(currentItemRef, 0, (CFURLRef*) &url, NULL) == noErr) { - NSString * urlPath = [(__bridge NSURL*)url path]; - if ([urlPath compare:appPath] == NSOrderedSame){ - itemRef = currentItemRef; - } - } - } - } - CFRelease(loginItems); - return itemRef; -} - -@end diff --git a/attic/macui/ZeroTier One/PreferencesViewController.xib b/attic/macui/ZeroTier One/PreferencesViewController.xib deleted file mode 100644 index 62aef4c0..00000000 --- a/attic/macui/ZeroTier One/PreferencesViewController.xib +++ /dev/null @@ -1,33 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/attic/macui/ZeroTier One/ServiceCom.h b/attic/macui/ZeroTier One/ServiceCom.h deleted file mode 100644 index 17b738e4..00000000 --- a/attic/macui/ZeroTier One/ServiceCom.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#import - -@class NodeStatus; -@class Network; - -@interface ServiceCom : NSObject -{ - NSString *baseURL; - NSURLSession *session; - BOOL _isQuitting; - BOOL _resetKey; -} -+ (ServiceCom*)sharedInstance; - -- (id)init; - -- (void)getNetworklist:(void (^)(NSArray*))completionHandler error:(NSError* __autoreleasing *)error; -- (void)getNodeStatus:(void (^)(NodeStatus*))completionHandler error:(NSError*__autoreleasing*)error; -- (void)joinNetwork:(NSString*)networkId allowManaged:(BOOL)allowManaged allowGlobal:(BOOL)allowGlobal allowDefault:(BOOL)allowDefault allowDNS:(BOOL)allowDNS error:(NSError*__autoreleasing*)error; -- (void)leaveNetwork:(NSString*)networkId error:(NSError*__autoreleasing*)error; - -@end diff --git a/attic/macui/ZeroTier One/ServiceCom.m b/attic/macui/ZeroTier One/ServiceCom.m deleted file mode 100644 index 55d67741..00000000 --- a/attic/macui/ZeroTier One/ServiceCom.m +++ /dev/null @@ -1,522 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#import "ServiceCom.h" -#import "AuthtokenCopy.h" -#import "Network.h" -#import "NodeStatus.h" -@import AppKit; - -@interface ServiceCom (Private) - -- (NSString*)key; - -@end - -@implementation ServiceCom - -+ (ServiceCom*)sharedInstance { - static ServiceCom *sc = nil; - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - sc = [[ServiceCom alloc] init]; - }); - return sc; -} - -- (id)init -{ - self = [super init]; - if(self) { - baseURL = @"http://127.0.0.1:9993"; - session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration ephemeralSessionConfiguration]]; - _isQuitting = NO; - _resetKey = NO; - } - - return self; -} - -- (NSString*)key:(NSError* __autoreleasing *)err -{ - static NSString *k = nil; - static NSUInteger resetCount = 0; - - @synchronized (self) { - if (_isQuitting) { - return @""; - } - - if (_resetKey && k != nil) { - k = nil; - ++resetCount; - NSLog(@"ResetCount: %lu", (unsigned long)resetCount); - if (resetCount > 10) { - [[NSOperationQueue mainQueue] addOperationWithBlock:^{ - NSAlert *alert = [NSAlert alertWithMessageText:@"Error obtaining Auth Token" - defaultButton:@"Quit" - alternateButton:@"Retry" - otherButton:nil - informativeTextWithFormat:@"Please ensure ZeroTier is installed correctly"]; - alert.alertStyle = NSCriticalAlertStyle; - - NSModalResponse res; - if (!_isQuitting) { - res = [alert runModal]; - } - else { - return; - } - - if(res == 1) { - _isQuitting = YES; - [NSApp performSelector:@selector(terminate:) withObject:nil afterDelay:0.0]; - } - }]; - return @""; - } - } - - if (k == nil) { - NSError *error = nil; - NSURL *appSupportDir = [[NSFileManager defaultManager] URLForDirectory:NSApplicationSupportDirectory inDomain:NSUserDomainMask appropriateForURL:nil create:false error:&error]; - - if (error) { - NSLog(@"Error: %@", error); - return @""; - } - - appSupportDir = [[appSupportDir URLByAppendingPathComponent:@"ZeroTier"] URLByAppendingPathComponent:@"One"]; - NSURL *authtokenURL = [appSupportDir URLByAppendingPathComponent:@"authtoken.secret"]; - - if (!_resetKey && [[NSFileManager defaultManager] fileExistsAtPath:[authtokenURL path]]) { - k = [NSString stringWithContentsOfURL:authtokenURL - encoding:NSUTF8StringEncoding - error:&error]; - - k = [k stringByReplacingOccurrencesOfString:@"\n" withString:@""]; - - if (error) { - NSLog(@"Error: %@", error); - k = nil; - *err = error; - return @""; - } - } - else { - _resetKey = NO; - NSURL *sysAppSupportDir = [[NSFileManager defaultManager] URLForDirectory:NSApplicationSupportDirectory inDomain:NSSystemDomainMask appropriateForURL:nil create:false error:nil]; - - sysAppSupportDir = [[sysAppSupportDir URLByAppendingPathComponent:@"ZeroTier"] URLByAppendingPathComponent:@"One"]; - NSURL *sysAuthtokenURL = [sysAppSupportDir URLByAppendingPathComponent:@"authtoken.secret"]; - - if(![[NSFileManager defaultManager] fileExistsAtPath:[sysAuthtokenURL path]]) { - - } - - [[NSFileManager defaultManager] createDirectoryAtURL:appSupportDir - withIntermediateDirectories:YES - attributes:nil - error:&error]; - - if (error) { - NSLog(@"Error: %@", error); - *err = error; - k = nil; - return @""; - } - - AuthorizationRef authRef; - OSStatus status = AuthorizationCreate(nil, nil, kAuthorizationFlagDefaults, &authRef); - - if (status != errAuthorizationSuccess) { - NSLog(@"Authorization Failed! %d", status); - - NSDictionary *userInfo = @{ - NSLocalizedDescriptionKey: NSLocalizedString(@"Couldn't create AuthorizationRef", nil), - }; - *err = [NSError errorWithDomain:@"com.zerotier.one" code:-1 userInfo:userInfo]; - - return @""; - } - - AuthorizationItem authItem; - authItem.name = kAuthorizationRightExecute; - authItem.valueLength = 0; - authItem.flags = 0; - - AuthorizationRights authRights; - authRights.count = 1; - authRights.items = &authItem; - - AuthorizationFlags authFlags = kAuthorizationFlagDefaults | - kAuthorizationFlagInteractionAllowed | - kAuthorizationFlagPreAuthorize | - kAuthorizationFlagExtendRights; - - status = AuthorizationCopyRights(authRef, &authRights, nil, authFlags, nil); - - if (status != errAuthorizationSuccess) { - NSLog(@"Authorization Failed! %d", status); - NSDictionary *userInfo = @{ - NSLocalizedDescriptionKey: NSLocalizedString(@"Couldn't copy authorization rights", nil), - }; - *err = [NSError errorWithDomain:@"com.zerotier.one" code:-1 userInfo:userInfo]; - return @""; - } - - NSString *localKey = getAdminAuthToken(authRef); - AuthorizationFree(authRef, kAuthorizationFlagDestroyRights); - - if (localKey != nil && [localKey lengthOfBytesUsingEncoding:NSUTF8StringEncoding] > 0) { - k = localKey; - - [localKey writeToURL:authtokenURL - atomically:YES - encoding:NSUTF8StringEncoding - error:&error]; - - if (error) { - NSLog(@"Error writing token to disk: %@", error); - *err = error; - } - } - } - } - - if (k == nil) { - NSDictionary *userInfo = @{ - NSLocalizedDescriptionKey: NSLocalizedString(@"Unknown error finding authorization key", nil), - }; - *err = [NSError errorWithDomain:@"com.zerotier.one" code:-1 userInfo:userInfo]; - - return @""; - } - } - return k; -} - -- (void)getNetworklist:(void (^)(NSArray *))completionHandler error:(NSError *__autoreleasing*)error -{ - NSString* key = [self key:error]; - if(*error) { - return; - } - - NSString *urlString = [[baseURL stringByAppendingString:@"/network?auth="] stringByAppendingString:key]; - - NSURL *url = [NSURL URLWithString:urlString]; - NSURLSessionDataTask *task = - [session dataTaskWithURL:url - completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable err) { - - if (err) { - [[NSOperationQueue mainQueue] addOperationWithBlock:^{ - NSAlert *alert = [NSAlert alertWithError:err]; - alert.alertStyle = NSCriticalAlertStyle; - [alert addButtonWithTitle:@"Quit"]; - [alert addButtonWithTitle:@"Retry"]; - - NSModalResponse res; - if (!_isQuitting) { - res = [alert runModal]; - } - else { - return; - } - - if(res == NSAlertFirstButtonReturn) { - [NSApp performSelector:@selector(terminate:) withObject:nil afterDelay:0.0]; - _isQuitting = YES; - } - }]; - return; - } - - NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse*)response; - NSInteger status = [httpResponse statusCode]; - - NSError *err2; - - if (status == 200) { - NSArray *json = [NSJSONSerialization JSONObjectWithData:data - options:0 - error:&err2]; - if (err) { - NSLog(@"Error fetching network list: %@", err2); - - [[NSOperationQueue mainQueue] addOperationWithBlock:^{ - NSAlert *alert = [NSAlert alertWithError:err2]; - alert.alertStyle = NSCriticalAlertStyle; - [alert addButtonWithTitle:@"Quit"]; - [alert addButtonWithTitle:@"Retry"]; - - NSModalResponse res; - if (!_isQuitting) { - res = [alert runModal]; - } - else { - return; - } - - if(res == NSAlertFirstButtonReturn) { - _isQuitting = YES; - [NSApp performSelector:@selector(terminate:) withObject:nil afterDelay:0.0]; - } - }]; - return; - } - - NSMutableArray *networks = [[NSMutableArray alloc] init]; - for(NSDictionary *dict in json) { - [networks addObject:[[Network alloc] initWithJsonData:dict]]; - } - - completionHandler(networks); - } - else if (status == 401) { - self->_resetKey = YES; - } - }]; - [task resume]; -} - -- (void)getNodeStatus:(void (^)(NodeStatus*))completionHandler error:(NSError*__autoreleasing*)error -{ - NSString *key = [self key:error]; - if(*error) { - return; - } - - NSString *urlString = [[baseURL stringByAppendingString:@"/status?auth="] stringByAppendingString:key]; - - NSURL *url = [NSURL URLWithString:urlString]; - NSURLSessionDataTask *task = - [session dataTaskWithURL:url - completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable err) { - - if(err) { - [[NSOperationQueue mainQueue] addOperationWithBlock:^{ - NSAlert *alert = [NSAlert alertWithError:err]; - alert.alertStyle = NSCriticalAlertStyle; - [alert addButtonWithTitle:@"Quit"]; - [alert addButtonWithTitle:@"Retry"]; - - NSModalResponse res; - if (!_isQuitting) { - res = [alert runModal]; - } - else { - return; - } - - if(res == NSAlertFirstButtonReturn) { - [NSApp performSelector:@selector(terminate:) withObject:nil afterDelay:0.0]; - _isQuitting = YES; - } - }]; - return; - } - - NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse*)response; - NSInteger status = [httpResponse statusCode]; - - NSError *err2; - if(status == 200) { - NSDictionary *json = [NSJSONSerialization JSONObjectWithData:data - options:0 - error:&err2]; - - if(err2) { - NSLog(@"Error fetching node status: %@", err2); - [[NSOperationQueue mainQueue] addOperationWithBlock:^{ - NSAlert *alert = [NSAlert alertWithError:err2]; - alert.alertStyle = NSCriticalAlertStyle; - [alert addButtonWithTitle:@"Quit"]; - [alert addButtonWithTitle:@"Retry"]; - - NSModalResponse res; - if (!_isQuitting) { - res = [alert runModal]; - } - else { - return; - } - - if(res == NSAlertFirstButtonReturn) { - [NSApp performSelector:@selector(terminate:) withObject:nil afterDelay:0.0]; - _isQuitting = YES; - } - }]; - return; - } - - NodeStatus *status = [[NodeStatus alloc] initWithJsonData:json]; - - completionHandler(status); - } - else if (status == 401) { - self->_resetKey = YES; - } - }]; - [task resume]; -} - -- (void)joinNetwork:(NSString*)networkId - allowManaged:(BOOL)allowManaged - allowGlobal:(BOOL)allowGlobal - allowDefault:(BOOL)allowDefault - allowDNS:(BOOL)allowDNS - error:(NSError *__autoreleasing*)error -{ - NSString *key = [self key:error]; - if(*error) { - return; - } - - NSString *urlString = [[[[baseURL stringByAppendingString:@"/network/"] - stringByAppendingString:networkId] - stringByAppendingString:@"?auth="] - stringByAppendingString:key]; - - NSURL *url = [NSURL URLWithString:urlString]; - - NSMutableDictionary *jsonDict = [NSMutableDictionary dictionary]; - [jsonDict setObject:[NSNumber numberWithBool:allowManaged] forKey:@"allowManaged"]; - [jsonDict setObject:[NSNumber numberWithBool:allowGlobal] forKey:@"allowGlobal"]; - [jsonDict setObject:[NSNumber numberWithBool:allowDefault] forKey:@"allowDefault"]; - [jsonDict setObject:[NSNumber numberWithBool:allowDNS] forKey:@"allowDNS"]; - - NSError *err = nil; - - NSData *json = [NSJSONSerialization dataWithJSONObject:jsonDict - options:0 - error:&err]; - - if(err) { - NSLog(@"Error creating json data: %@", err); - *error = err; - return; - } - - NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url]; - request.HTTPMethod = @"POST"; - request.HTTPBody = json; - [request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"]; - - NSURLSessionDataTask *task = - [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable err) { - if(err) { - NSLog(@"Error posting join request: %@", err); - [[NSOperationQueue mainQueue] addOperationWithBlock:^{ - NSAlert *alert = [NSAlert alertWithError:err]; - alert.alertStyle = NSCriticalAlertStyle; - [alert addButtonWithTitle:@"Quit"]; - [alert addButtonWithTitle:@"Retry"]; - - NSModalResponse res; - if (!_isQuitting) { - res = [alert runModal]; - } - else { - return; - } - - if(res == NSAlertFirstButtonReturn) { - [NSApp performSelector:@selector(terminate:) withObject:nil afterDelay:0.0]; - _isQuitting = YES; - } - }]; - } - - NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse*)response; - NSInteger status = [httpResponse statusCode]; - - if(status == 200) { - NSLog(@"join ok"); - } - else if (status == 401) { - self->_resetKey = YES; - } - else { - NSLog(@"join error: %ld", (long)status); - } - }]; - [task resume]; -} - -- (void)leaveNetwork:(NSString*)networkId error:(NSError*__autoreleasing*)error -{ - NSString *key = [self key:error]; - if(*error) { - return; - } - - NSString *urlString = [[[[baseURL stringByAppendingString:@"/network/"] - stringByAppendingString:networkId] - stringByAppendingString:@"?auth="] - stringByAppendingString:key]; - - NSURL *url = [NSURL URLWithString:urlString]; - - NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url]; - request.HTTPMethod = @"DELETE"; - - NSURLSessionDataTask *task = - [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable err) { - if(err) { - NSLog(@"Error posting delete request: %@", err); - [[NSOperationQueue mainQueue] addOperationWithBlock:^{ - NSAlert *alert = [NSAlert alertWithError:err]; - alert.alertStyle = NSCriticalAlertStyle; - [alert addButtonWithTitle:@"Quit"]; - [alert addButtonWithTitle:@"Retry"]; - - NSModalResponse res; - if (!_isQuitting) { - res = [alert runModal]; - } - else { - return; - } - - if(res == NSAlertFirstButtonReturn) { - [NSApp performSelector:@selector(terminate:) withObject:nil afterDelay:0.0]; - _isQuitting = YES; - } - }]; - return; - } - - NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse*)response; - NSInteger status = httpResponse.statusCode; - - if(status == 200) { - NSLog(@"leave ok"); - } - else if (status == 401) { - self->_resetKey = YES; - } - else { - NSLog(@"leave error: %ld", status); - } - }]; - [task resume]; -} - -@end diff --git a/attic/macui/ZeroTier One/ShowNetworksViewController.h b/attic/macui/ZeroTier One/ShowNetworksViewController.h deleted file mode 100644 index 6138958d..00000000 --- a/attic/macui/ZeroTier One/ShowNetworksViewController.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#import - -@class NetworkMonitor; -@class Network; - -@interface ShowNetworksViewController : NSViewController - -@property (nonatomic) NSMutableArray *networkList; -@property (nonatomic) NetworkMonitor *netMonitor; -@property (nonatomic) BOOL visible; - -@property (weak, nonatomic) IBOutlet NSTableView *tableView; - -- (void)deleteNetworkFromList:(NSString*)nwid; -- (void)setNetworks:(NSArray*)list; - - -@end diff --git a/attic/macui/ZeroTier One/ShowNetworksViewController.m b/attic/macui/ZeroTier One/ShowNetworksViewController.m deleted file mode 100644 index acd29479..00000000 --- a/attic/macui/ZeroTier One/ShowNetworksViewController.m +++ /dev/null @@ -1,184 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#import "ShowNetworksViewController.h" -#import "NetworkMonitor.h" -#import "NetworkInfoCell.h" -#import "Network.h" - -BOOL hasNetworkWithID(NSArray *list, UInt64 nwid) -{ - for(Network *n in list) { - if(n.nwid == nwid) { - return YES; - } - } - - return NO; -} - -@interface ShowNetworksViewController () - -@end - -@implementation ShowNetworksViewController - -- (void)viewDidLoad { - [super viewDidLoad]; - - self.networkList = [NSMutableArray array]; - - [self.tableView setDelegate:self]; - [self.tableView setDataSource:self]; - [self.tableView setBackgroundColor:[NSColor clearColor]]; -} - -- (void)viewWillAppear { - [super viewWillAppear]; - self.visible = YES; -} - -- (void)viewWillDisappear { - [super viewWillDisappear]; - self.visible = NO; -} - -- (NSInteger)findNetworkWithID:(UInt64)networkId -{ - for(int i = 0; i < [_networkList count]; ++i) { - Network *nw = [_networkList objectAtIndex:i]; - - if(nw.nwid == networkId) { - return i; - } - } - - return NSNotFound; -} - - -- (void)deleteNetworkFromList:(NSString *)nwid { - [self.netMonitor deleteSavedNetwork:nwid]; - - UInt64 netid = 0; - NSScanner *scanner = [NSScanner scannerWithString:nwid]; - [scanner scanHexLongLong:&netid]; - for (Network *n in _networkList) { - if (n.nwid == netid) { - NSInteger index = [self findNetworkWithID:netid]; - - if (index != NSNotFound) { - [_networkList removeObjectAtIndex:index]; - [_tableView reloadData]; - } - } - } -} - -- (void)setNetworks:(NSArray *)list { - for (Network *n in list) { - if ([_networkList containsObject:n]) { - // don't need to do anything here. Already an identical object in the list - continue; - } - else { - // network not in the list based on equality. Did an object change? or is it a new item? - if (hasNetworkWithID(_networkList, n.nwid)) { - - for (int i = 0; i < [_networkList count]; ++i) { - Network *n2 = [_networkList objectAtIndex:i]; - if (n.nwid == n2.nwid) - { - [_networkList replaceObjectAtIndex:i withObject:n]; - [_tableView reloadDataForRowIndexes:[NSIndexSet indexSetWithIndex:i] - columnIndexes:[NSIndexSet indexSetWithIndex:0]]; - } - } - } - else { - [_networkList addObject:n]; - [_tableView reloadData]; - } - } - } -} - -- (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView { - return [_networkList count]; -} - -- (NSView*)tableView:(NSTableView *)tableView viewForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row -{ - NetworkInfoCell *cell = (NetworkInfoCell*)[tableView makeViewWithIdentifier:@"NetworkInfoCell" - owner:nil]; - Network *network = [_networkList objectAtIndex:row]; - cell.parent = self; - cell.networkIdField.stringValue = [NSString stringWithFormat:@"%10llx", network.nwid]; - cell.networkNameField.stringValue = network.name; - cell.statusField.stringValue = [network statusString]; - cell.typeField.stringValue = [network typeString]; - cell.mtuField.stringValue = [NSString stringWithFormat:@"%d", network.mtu]; - cell.macField.stringValue = network.mac; - cell.broadcastField.stringValue = network.broadcastEnabled ? @"ENABLED" : @"DISABLED"; - cell.bridgingField.stringValue = network.bridge ? @"ENABLED" : @"DISABLED"; - cell.deviceField.stringValue = network.portDeviceName; - - if(network.connected) { - cell.connectedCheckbox.state = NSOnState; - - if(network.allowDefault) { - cell.allowDefault.enabled = YES; - cell.allowDefault.state = NSOnState; - } - else { - cell.allowDefault.state = NSOffState; - - if([Network defaultRouteExists:_networkList]) { - cell.allowDefault.enabled = NO; - } - else { - cell.allowDefault.enabled = YES; - } - } - - cell.allowGlobal.enabled = YES; - cell.allowManaged.enabled = YES; - cell.allowDNS.enabled = YES; - } - else { - cell.connectedCheckbox.state = NSOffState; - cell.allowDefault.enabled = NO; - cell.allowGlobal.enabled = NO; - cell.allowManaged.enabled = NO; - cell.allowDNS.enabled = NO; - } - - cell.allowGlobal.state = network.allowGlobal ? NSOnState : NSOffState; - cell.allowManaged.state = network.allowManaged ? NSOnState : NSOffState; - cell.allowDNS.state = network.allowDNS ? NSOnState : NSOffState; - - cell.addressesField.stringValue = @""; - - for(NSString *addr in network.assignedAddresses) { - cell.addressesField.stringValue = [[cell.addressesField.stringValue stringByAppendingString:addr] stringByAppendingString:@"\n"]; - } - - return cell; -} - -@end diff --git a/attic/macui/ZeroTier One/ShowNetworksViewController.xib b/attic/macui/ZeroTier One/ShowNetworksViewController.xib deleted file mode 100644 index 485adb0c..00000000 --- a/attic/macui/ZeroTier One/ShowNetworksViewController.xib +++ /dev/null @@ -1,394 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/attic/macui/ZeroTier One/ZeroTier One.entitlements b/attic/macui/ZeroTier One/ZeroTier One.entitlements deleted file mode 100644 index 0c67376e..00000000 --- a/attic/macui/ZeroTier One/ZeroTier One.entitlements +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/attic/macui/ZeroTier One/ZeroTierIcon.icns b/attic/macui/ZeroTier One/ZeroTierIcon.icns deleted file mode 100644 index 17e60d58..00000000 Binary files a/attic/macui/ZeroTier One/ZeroTierIcon.icns and /dev/null differ diff --git a/attic/macui/ZeroTier One/about.html b/attic/macui/ZeroTier One/about.html deleted file mode 100644 index 09f6eb36..00000000 --- a/attic/macui/ZeroTier One/about.html +++ /dev/null @@ -1,58 +0,0 @@ - - - - - -
-
-

Welcome to ZeroTier

-

Getting Started

-

Networks are identified by 16-digit network IDs. If someone invited you to join theirs you probably received one. If not you can create your own at my.zerotier.com or by running running your own network controller. -

Your computer is identified by a 10-digit ZeroTier address. You can find it at the top of the ZeroTier app's pull-down menu or by typing "sudo zerotier-cli info" in a terminal window. This number is unique to your system and is how network administrators can recognize you. If someone invited you to a network, give them this ID so they can authorize you to join.

-

Starting, Stopping, and Uninstalling

-

The ZeroTier service is separate from the UI app and starts on system boot. The app can be started on login or only when needed. To stop the ZeroTier service use:

-      sudo launchctl unload /Library/LaunchDaemons/com.zerotier.one.plist

- Replace "unload" with "load" to start it again.

-

ZeroTier can be uninstalled with:

-      sudo '/Library/Application Support/ZeroTier/One/uninstall.sh' -

-

For more information, visit zerotier.com.

-
- - \ No newline at end of file diff --git a/attic/macui/ZeroTier One/main.m b/attic/macui/ZeroTier One/main.m deleted file mode 100644 index 108a6bd1..00000000 --- a/attic/macui/ZeroTier One/main.m +++ /dev/null @@ -1,23 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#import - -int main(int argc, const char * argv[]) { - return NSApplicationMain(argc, argv); -} diff --git a/attic/world/mkworld.cpp b/attic/world/mkworld.cpp index 6b9bbe8d..ed2c499a 100644 --- a/attic/world/mkworld.cpp +++ b/attic/world/mkworld.cpp @@ -43,7 +43,7 @@ #include #include -#include +#include #include #include #include @@ -54,7 +54,7 @@ int main(int argc,char **argv) { std::string previous,current; if ((!OSUtils::readFile("previous.c25519",previous))||(!OSUtils::readFile("current.c25519",current))) { - C25519::Pair np(C25519::generate()); + ECC::Pair np(ECC::generate()); previous = std::string(); previous.append((const char *)np.pub.data,ZT_C25519_PUBLIC_KEY_LEN); previous.append((const char *)np.priv.data,ZT_C25519_PRIVATE_KEY_LEN); @@ -68,10 +68,10 @@ int main(int argc,char **argv) fprintf(stderr,"FATAL: previous.c25519 or current.c25519 empty or invalid" ZT_EOL_S); return 1; } - C25519::Pair previousKP; + ECC::Pair previousKP; memcpy(previousKP.pub.data,previous.data(),ZT_C25519_PUBLIC_KEY_LEN); memcpy(previousKP.priv.data,previous.data() + ZT_C25519_PUBLIC_KEY_LEN,ZT_C25519_PRIVATE_KEY_LEN); - C25519::Pair currentKP; + ECC::Pair currentKP; memcpy(currentKP.pub.data,current.data(),ZT_C25519_PUBLIC_KEY_LEN); memcpy(currentKP.priv.data,current.data() + ZT_C25519_PUBLIC_KEY_LEN,ZT_C25519_PRIVATE_KEY_LEN); diff --git a/ext/ed25519-amd64-asm/sign.c b/ext/ed25519-amd64-asm/sign.c index 882ae76f..715feb5b 100644 --- a/ext/ed25519-amd64-asm/sign.c +++ b/ext/ed25519-amd64-asm/sign.c @@ -61,7 +61,7 @@ int crypto_sign( #endif #if 0 -void C25519::sign(const C25519::Private &myPrivate,const C25519::Public &myPublic,const void *msg,unsigned int len,void *signature) +void ECC::sign(const ECC::Private &myPrivate,const ECC::Public &myPublic,const void *msg,unsigned int len,void *signature) { sc25519 sck, scs, scsk; ge25519 ger; diff --git a/include/ZeroTierDebug.h b/include/ZeroTierDebug.h index 3d1942fd..2e9cc2c5 100644 --- a/include/ZeroTierDebug.h +++ b/include/ZeroTierDebug.h @@ -21,84 +21,81 @@ #define ZT_DEBUG_H #if defined(__linux__) || defined(__APPLE__) -#include #include +#include #include #endif #include -#define ZT_MSG_INFO true -#define ZT_COLOR true +#define ZT_MSG_INFO true +#define ZT_COLOR true // Debug output colors #if defined(__APPLE__) - #include "TargetConditionals.h" +#include "TargetConditionals.h" #endif -#if defined(ZT_COLOR) && !defined(_WIN32) && !defined(__ANDROID__) && !defined(TARGET_OS_IPHONE) && !defined(TARGET_IPHONE_SIMULATOR) && !defined(__APP_FRAMEWORK__) - #define ZT_RED "\x1B[31m" - #define ZT_GRN "\x1B[32m" - #define ZT_YEL "\x1B[33m" - #define ZT_BLU "\x1B[34m" - #define ZT_MAG "\x1B[35m" - #define ZT_CYN "\x1B[36m" - #define ZT_WHT "\x1B[37m" - #define ZT_RESET "\x1B[0m" +#if defined(ZT_COLOR) && ! defined(_WIN32) && ! defined(__ANDROID__) && ! defined(TARGET_OS_IPHONE) && ! defined(TARGET_IPHONE_SIMULATOR) && ! defined(__APP_FRAMEWORK__) +#define ZT_RED "\x1B[31m" +#define ZT_GRN "\x1B[32m" +#define ZT_YEL "\x1B[33m" +#define ZT_BLU "\x1B[34m" +#define ZT_MAG "\x1B[35m" +#define ZT_CYN "\x1B[36m" +#define ZT_WHT "\x1B[37m" +#define ZT_RESET "\x1B[0m" #else - #define ZT_RED - #define ZT_GRN - #define ZT_YEL - #define ZT_BLU - #define ZT_MAG - #define ZT_CYN - #define ZT_WHT - #define ZT_RESET +#define ZT_RED +#define ZT_GRN +#define ZT_YEL +#define ZT_BLU +#define ZT_MAG +#define ZT_CYN +#define ZT_WHT +#define ZT_RESET #endif -#define ZT_FILENAME (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__) // short +#define ZT_FILENAME (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__) // short #ifdef __linux__ - #define ZT_THREAD_ID (long)0 // syscall(SYS_gettid) +#define ZT_THREAD_ID (long)0 // syscall(SYS_gettid) #endif #ifdef __APPLE__ - #define ZT_THREAD_ID (long)0 // (long)gettid() +#define ZT_THREAD_ID (long)0 // (long)gettid() #endif #ifdef __FreeBSD__ - #define ZT_THREAD_ID (long)0 // (long)gettid() +#define ZT_THREAD_ID (long)0 // (long)gettid() #endif #ifdef _WIN32 - #define ZT_THREAD_ID (long)0 // +#define ZT_THREAD_ID (long)0 // #endif #if defined(__JNI_LIB__) - #include +#include #endif #if defined(__ANDROID__) - #include - #define ZT_LOG_TAG "ZTSDK" +#include +#define ZT_LOG_TAG "ZTSDK" #endif #if defined(ZT_DEBUG_TRACE) - #if ZT_MSG_INFO == true - #if defined(__ANDROID__) - #define DEBUG_INFO(fmt, args...) ((void)__android_log_print(ANDROID_LOG_VERBOSE, ZT_LOG_TAG, \ - "INFO : %17s:%5d:%20s: " fmt "\n", ZT_FILENAME, __LINE__, __FUNCTION__, ##args)) - #endif - #if defined(_WIN32) - #define DEBUG_INFO(fmt, ...) fprintf(stderr, ZT_GRN "INFO [%ld]: %17s:%5d:%25s: " fmt "\n" \ - ZT_RESET, ZT_THREAD_ID, ZT_FILENAME, __LINE__, __FUNCTION__, __VA_ARGS__) - #endif - #if defined(__linux__) or defined(__APPLE__) or defined(__FreeBSD__) - #define DEBUG_INFO(fmt, args ...) fprintf(stderr, ZT_GRN "INFO [%ld]: %17s:%5d:%25s: " fmt "\n" \ - ZT_RESET, ZT_THREAD_ID, ZT_FILENAME, __LINE__, __FUNCTION__, ##args) - #endif - #else - #define DEBUG_INFO(fmt, args...) - #endif -#else // blank - #if defined(_WIN32) - #define DEBUG_INFO(...) - #else - #define DEBUG_INFO(fmt, args...) - #endif +#if ZT_MSG_INFO == true +#if defined(__ANDROID__) +#define DEBUG_INFO(fmt, args...) ((void)__android_log_print(ANDROID_LOG_VERBOSE, ZT_LOG_TAG, "INFO : %17s:%5d:%20s: " fmt "\n", ZT_FILENAME, __LINE__, __FUNCTION__, ##args)) +#endif +#if defined(_WIN32) +#define DEBUG_INFO(fmt, ...) fprintf(stderr, ZT_GRN "INFO [%ld]: %17s:%5d:%25s: " fmt "\n" ZT_RESET, ZT_THREAD_ID, ZT_FILENAME, __LINE__, __FUNCTION__, __VA_ARGS__) +#endif +#if defined(__linux__) or defined(__APPLE__) or defined(__FreeBSD__) +#define DEBUG_INFO(fmt, args...) fprintf(stderr, ZT_GRN "INFO [%ld]: %17s:%5d:%25s: " fmt "\n" ZT_RESET, ZT_THREAD_ID, ZT_FILENAME, __LINE__, __FUNCTION__, ##args) +#endif +#else +#define DEBUG_INFO(fmt, args...) +#endif +#else // blank +#if defined(_WIN32) +#define DEBUG_INFO(...) +#else +#define DEBUG_INFO(fmt, args...) +#endif #endif -#endif // _H +#endif // _H diff --git a/include/ZeroTierOne.h b/include/ZeroTierOne.h index 44823469..fa1c909e 100644 --- a/include/ZeroTierOne.h +++ b/include/ZeroTierOne.h @@ -23,22 +23,22 @@ // For the struct sockaddr_storage structure #if defined(_WIN32) || defined(_WIN64) +#include #include #include -#include #else /* not Windows */ #include #include -#include #include +#include #endif /* Windows or not */ -#if defined (_MSC_VER) -#ifdef ZT_EXPORT +#if defined(_MSC_VER) +#ifdef ZT_EXPORT #define ZT_SDK_API __declspec(dllexport) #else #define ZT_SDK_API __declspec(dllimport) -#if !defined(ZT_SDK) +#if ! defined(ZT_SDK) #ifdef _DEBUG #ifdef _WIN64 #pragma comment(lib, "ZeroTierOne_x64d.lib") @@ -291,74 +291,74 @@ extern "C" { #define ZT_RULE_PACKET_CHARACTERISTICS_TCP_FIN 0x0000000000000001ULL // Fields in remote trace dictionaries -#define ZT_REMOTE_TRACE_FIELD__EVENT "event" -#define ZT_REMOTE_TRACE_FIELD__NODE_ID "nodeId" -#define ZT_REMOTE_TRACE_FIELD__PACKET_ID "packetId" -#define ZT_REMOTE_TRACE_FIELD__PACKET_VERB "packetVerb" -#define ZT_REMOTE_TRACE_FIELD__PACKET_TRUSTED_PATH_ID "packetTrustedPathId" +#define ZT_REMOTE_TRACE_FIELD__EVENT "event" +#define ZT_REMOTE_TRACE_FIELD__NODE_ID "nodeId" +#define ZT_REMOTE_TRACE_FIELD__PACKET_ID "packetId" +#define ZT_REMOTE_TRACE_FIELD__PACKET_VERB "packetVerb" +#define ZT_REMOTE_TRACE_FIELD__PACKET_TRUSTED_PATH_ID "packetTrustedPathId" #define ZT_REMOTE_TRACE_FIELD__PACKET_TRUSTED_PATH_APPROVED "packetTrustedPathApproved" -#define ZT_REMOTE_TRACE_FIELD__PACKET_HOPS "packetHops" -#define ZT_REMOTE_TRACE_FIELD__REMOTE_ZTADDR "remoteZtAddr" -#define ZT_REMOTE_TRACE_FIELD__REMOTE_PHYADDR "remotePhyAddr" -#define ZT_REMOTE_TRACE_FIELD__LOCAL_ZTADDR "localZtAddr" -#define ZT_REMOTE_TRACE_FIELD__LOCAL_PHYADDR "localPhyAddr" -#define ZT_REMOTE_TRACE_FIELD__LOCAL_SOCKET "localSocket" -#define ZT_REMOTE_TRACE_FIELD__IP_SCOPE "phyAddrIpScope" -#define ZT_REMOTE_TRACE_FIELD__NETWORK_ID "networkId" -#define ZT_REMOTE_TRACE_FIELD__SOURCE_ZTADDR "sourceZtAddr" -#define ZT_REMOTE_TRACE_FIELD__DEST_ZTADDR "destZtAddr" -#define ZT_REMOTE_TRACE_FIELD__SOURCE_MAC "sourceMac" -#define ZT_REMOTE_TRACE_FIELD__DEST_MAC "destMac" -#define ZT_REMOTE_TRACE_FIELD__ETHERTYPE "etherType" -#define ZT_REMOTE_TRACE_FIELD__VLAN_ID "vlanId" -#define ZT_REMOTE_TRACE_FIELD__FRAME_LENGTH "frameLength" -#define ZT_REMOTE_TRACE_FIELD__FRAME_DATA "frameData" -#define ZT_REMOTE_TRACE_FIELD__FILTER_FLAG_NOTEE "filterNoTee" -#define ZT_REMOTE_TRACE_FIELD__FILTER_FLAG_INBOUND "filterInbound" -#define ZT_REMOTE_TRACE_FIELD__FILTER_RESULT "filterResult" -#define ZT_REMOTE_TRACE_FIELD__FILTER_BASE_RULE_LOG "filterBaseRuleLog" -#define ZT_REMOTE_TRACE_FIELD__FILTER_CAP_RULE_LOG "filterCapRuleLog" -#define ZT_REMOTE_TRACE_FIELD__FILTER_CAP_ID "filterMatchingCapId" -#define ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TYPE "credType" -#define ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ID "credId" -#define ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TIMESTAMP "credTs" -#define ZT_REMOTE_TRACE_FIELD__CREDENTIAL_INFO "credInfo" -#define ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ISSUED_TO "credIssuedTo" +#define ZT_REMOTE_TRACE_FIELD__PACKET_HOPS "packetHops" +#define ZT_REMOTE_TRACE_FIELD__REMOTE_ZTADDR "remoteZtAddr" +#define ZT_REMOTE_TRACE_FIELD__REMOTE_PHYADDR "remotePhyAddr" +#define ZT_REMOTE_TRACE_FIELD__LOCAL_ZTADDR "localZtAddr" +#define ZT_REMOTE_TRACE_FIELD__LOCAL_PHYADDR "localPhyAddr" +#define ZT_REMOTE_TRACE_FIELD__LOCAL_SOCKET "localSocket" +#define ZT_REMOTE_TRACE_FIELD__IP_SCOPE "phyAddrIpScope" +#define ZT_REMOTE_TRACE_FIELD__NETWORK_ID "networkId" +#define ZT_REMOTE_TRACE_FIELD__SOURCE_ZTADDR "sourceZtAddr" +#define ZT_REMOTE_TRACE_FIELD__DEST_ZTADDR "destZtAddr" +#define ZT_REMOTE_TRACE_FIELD__SOURCE_MAC "sourceMac" +#define ZT_REMOTE_TRACE_FIELD__DEST_MAC "destMac" +#define ZT_REMOTE_TRACE_FIELD__ETHERTYPE "etherType" +#define ZT_REMOTE_TRACE_FIELD__VLAN_ID "vlanId" +#define ZT_REMOTE_TRACE_FIELD__FRAME_LENGTH "frameLength" +#define ZT_REMOTE_TRACE_FIELD__FRAME_DATA "frameData" +#define ZT_REMOTE_TRACE_FIELD__FILTER_FLAG_NOTEE "filterNoTee" +#define ZT_REMOTE_TRACE_FIELD__FILTER_FLAG_INBOUND "filterInbound" +#define ZT_REMOTE_TRACE_FIELD__FILTER_RESULT "filterResult" +#define ZT_REMOTE_TRACE_FIELD__FILTER_BASE_RULE_LOG "filterBaseRuleLog" +#define ZT_REMOTE_TRACE_FIELD__FILTER_CAP_RULE_LOG "filterCapRuleLog" +#define ZT_REMOTE_TRACE_FIELD__FILTER_CAP_ID "filterMatchingCapId" +#define ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TYPE "credType" +#define ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ID "credId" +#define ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TIMESTAMP "credTs" +#define ZT_REMOTE_TRACE_FIELD__CREDENTIAL_INFO "credInfo" +#define ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ISSUED_TO "credIssuedTo" #define ZT_REMOTE_TRACE_FIELD__CREDENTIAL_REVOCATION_TARGET "credRevocationTarget" -#define ZT_REMOTE_TRACE_FIELD__REASON "reason" -#define ZT_REMOTE_TRACE_FIELD__NETWORK_CONTROLLER_ID "networkControllerId" +#define ZT_REMOTE_TRACE_FIELD__REASON "reason" +#define ZT_REMOTE_TRACE_FIELD__NETWORK_CONTROLLER_ID "networkControllerId" // Event types in remote traces -#define ZT_REMOTE_TRACE_EVENT__RESETTING_PATHS_IN_SCOPE 0x1000 -#define ZT_REMOTE_TRACE_EVENT__PEER_CONFIRMING_UNKNOWN_PATH 0x1001 -#define ZT_REMOTE_TRACE_EVENT__PEER_LEARNED_NEW_PATH 0x1002 -#define ZT_REMOTE_TRACE_EVENT__PEER_REDIRECTED 0x1003 -#define ZT_REMOTE_TRACE_EVENT__PACKET_MAC_FAILURE 0x1004 -#define ZT_REMOTE_TRACE_EVENT__PACKET_INVALID 0x1005 -#define ZT_REMOTE_TRACE_EVENT__DROPPED_HELLO 0x1006 +#define ZT_REMOTE_TRACE_EVENT__RESETTING_PATHS_IN_SCOPE 0x1000 +#define ZT_REMOTE_TRACE_EVENT__PEER_CONFIRMING_UNKNOWN_PATH 0x1001 +#define ZT_REMOTE_TRACE_EVENT__PEER_LEARNED_NEW_PATH 0x1002 +#define ZT_REMOTE_TRACE_EVENT__PEER_REDIRECTED 0x1003 +#define ZT_REMOTE_TRACE_EVENT__PACKET_MAC_FAILURE 0x1004 +#define ZT_REMOTE_TRACE_EVENT__PACKET_INVALID 0x1005 +#define ZT_REMOTE_TRACE_EVENT__DROPPED_HELLO 0x1006 #define ZT_REMOTE_TRACE_EVENT__OUTGOING_NETWORK_FRAME_DROPPED 0x2000 #define ZT_REMOTE_TRACE_EVENT__INCOMING_NETWORK_ACCESS_DENIED 0x2001 #define ZT_REMOTE_TRACE_EVENT__INCOMING_NETWORK_FRAME_DROPPED 0x2002 -#define ZT_REMOTE_TRACE_EVENT__CREDENTIAL_REJECTED 0x2003 -#define ZT_REMOTE_TRACE_EVENT__CREDENTIAL_ACCEPTED 0x2004 -#define ZT_REMOTE_TRACE_EVENT__NETWORK_CONFIG_REQUEST_SENT 0x2005 -#define ZT_REMOTE_TRACE_EVENT__NETWORK_FILTER_TRACE 0x2006 +#define ZT_REMOTE_TRACE_EVENT__CREDENTIAL_REJECTED 0x2003 +#define ZT_REMOTE_TRACE_EVENT__CREDENTIAL_ACCEPTED 0x2004 +#define ZT_REMOTE_TRACE_EVENT__NETWORK_CONFIG_REQUEST_SENT 0x2005 +#define ZT_REMOTE_TRACE_EVENT__NETWORK_FILTER_TRACE 0x2006 // Event types in remote traces in hex string form -#define ZT_REMOTE_TRACE_EVENT__RESETTING_PATHS_IN_SCOPE_S "1000" -#define ZT_REMOTE_TRACE_EVENT__PEER_CONFIRMING_UNKNOWN_PATH_S "1001" -#define ZT_REMOTE_TRACE_EVENT__PEER_LEARNED_NEW_PATH_S "1002" -#define ZT_REMOTE_TRACE_EVENT__PEER_REDIRECTED_S "1003" -#define ZT_REMOTE_TRACE_EVENT__PACKET_MAC_FAILURE_S "1004" -#define ZT_REMOTE_TRACE_EVENT__PACKET_INVALID_S "1005" -#define ZT_REMOTE_TRACE_EVENT__DROPPED_HELLO_S "1006" +#define ZT_REMOTE_TRACE_EVENT__RESETTING_PATHS_IN_SCOPE_S "1000" +#define ZT_REMOTE_TRACE_EVENT__PEER_CONFIRMING_UNKNOWN_PATH_S "1001" +#define ZT_REMOTE_TRACE_EVENT__PEER_LEARNED_NEW_PATH_S "1002" +#define ZT_REMOTE_TRACE_EVENT__PEER_REDIRECTED_S "1003" +#define ZT_REMOTE_TRACE_EVENT__PACKET_MAC_FAILURE_S "1004" +#define ZT_REMOTE_TRACE_EVENT__PACKET_INVALID_S "1005" +#define ZT_REMOTE_TRACE_EVENT__DROPPED_HELLO_S "1006" #define ZT_REMOTE_TRACE_EVENT__OUTGOING_NETWORK_FRAME_DROPPED_S "2000" #define ZT_REMOTE_TRACE_EVENT__INCOMING_NETWORK_ACCESS_DENIED_S "2001" #define ZT_REMOTE_TRACE_EVENT__INCOMING_NETWORK_FRAME_DROPPED_S "2002" -#define ZT_REMOTE_TRACE_EVENT__CREDENTIAL_REJECTED_S "2003" -#define ZT_REMOTE_TRACE_EVENT__CREDENTIAL_ACCEPTED_S "2004" -#define ZT_REMOTE_TRACE_EVENT__NETWORK_CONFIG_REQUEST_SENT_S "2005" -#define ZT_REMOTE_TRACE_EVENT__NETWORK_FILTER_TRACE_S "2006" +#define ZT_REMOTE_TRACE_EVENT__CREDENTIAL_REJECTED_S "2003" +#define ZT_REMOTE_TRACE_EVENT__CREDENTIAL_ACCEPTED_S "2004" +#define ZT_REMOTE_TRACE_EVENT__NETWORK_CONFIG_REQUEST_SENT_S "2005" +#define ZT_REMOTE_TRACE_EVENT__NETWORK_FILTER_TRACE_S "2006" /****************************************************************************/ /* Structures and other types */ @@ -372,192 +372,189 @@ extern "C" { * indicate serious problems like an inaccessible data store or a compile * problem. */ -enum ZT_ResultCode -{ - /** - * Operation completed normally - */ - ZT_RESULT_OK = 0, +enum ZT_ResultCode { + /** + * Operation completed normally + */ + ZT_RESULT_OK = 0, - /** - * Call produced no error but no action was taken - */ - ZT_RESULT_OK_IGNORED = 1, + /** + * Call produced no error but no action was taken + */ + ZT_RESULT_OK_IGNORED = 1, - // Fatal errors (>=100, <1000) + // Fatal errors (>=100, <1000) - /** - * Ran out of memory - */ - ZT_RESULT_FATAL_ERROR_OUT_OF_MEMORY = 100, + /** + * Ran out of memory + */ + ZT_RESULT_FATAL_ERROR_OUT_OF_MEMORY = 100, - /** - * Data store is not writable or has failed - */ - ZT_RESULT_FATAL_ERROR_DATA_STORE_FAILED = 101, + /** + * Data store is not writable or has failed + */ + ZT_RESULT_FATAL_ERROR_DATA_STORE_FAILED = 101, - /** - * Internal error (e.g. unexpected exception indicating bug or build problem) - */ - ZT_RESULT_FATAL_ERROR_INTERNAL = 102, + /** + * Internal error (e.g. unexpected exception indicating bug or build problem) + */ + ZT_RESULT_FATAL_ERROR_INTERNAL = 102, - // Non-fatal errors (>1000) + // Non-fatal errors (>1000) - /** - * Network ID not valid - */ - ZT_RESULT_ERROR_NETWORK_NOT_FOUND = 1000, + /** + * Network ID not valid + */ + ZT_RESULT_ERROR_NETWORK_NOT_FOUND = 1000, - /** - * The requested operation is not supported on this version or build - */ - ZT_RESULT_ERROR_UNSUPPORTED_OPERATION = 1001, + /** + * The requested operation is not supported on this version or build + */ + ZT_RESULT_ERROR_UNSUPPORTED_OPERATION = 1001, - /** - * The requested operation was given a bad parameter or was called in an invalid state - */ - ZT_RESULT_ERROR_BAD_PARAMETER = 1002 + /** + * The requested operation was given a bad parameter or was called in an invalid state + */ + ZT_RESULT_ERROR_BAD_PARAMETER = 1002 }; /** * @param x Result code * @return True if result code indicates a fatal error */ -#define ZT_ResultCode_isFatal(x) ((((int)(x)) >= 100)&&(((int)(x)) < 1000)) +#define ZT_ResultCode_isFatal(x) ((((int)(x)) >= 100) && (((int)(x)) < 1000)) /** * Status codes sent to status update callback when things happen */ -enum ZT_Event -{ - /** - * Node has been initialized - * - * This is the first event generated, and is always sent. It may occur - * before Node's constructor returns. - * - * Meta-data: none - */ - ZT_EVENT_UP = 0, +enum ZT_Event { + /** + * Node has been initialized + * + * This is the first event generated, and is always sent. It may occur + * before Node's constructor returns. + * + * Meta-data: none + */ + ZT_EVENT_UP = 0, - /** - * Node is offline -- network does not seem to be reachable by any available strategy - * - * Meta-data: none - */ - ZT_EVENT_OFFLINE = 1, + /** + * Node is offline -- network does not seem to be reachable by any available strategy + * + * Meta-data: none + */ + ZT_EVENT_OFFLINE = 1, - /** - * Node is online -- at least one upstream node appears reachable - * - * Meta-data: none - */ - ZT_EVENT_ONLINE = 2, + /** + * Node is online -- at least one upstream node appears reachable + * + * Meta-data: none + */ + ZT_EVENT_ONLINE = 2, - /** - * Node is shutting down - * - * This is generated within Node's destructor when it is being shut down. - * It's done for convenience, since cleaning up other state in the event - * handler may appear more idiomatic. - * - * Meta-data: none - */ - ZT_EVENT_DOWN = 3, + /** + * Node is shutting down + * + * This is generated within Node's destructor when it is being shut down. + * It's done for convenience, since cleaning up other state in the event + * handler may appear more idiomatic. + * + * Meta-data: none + */ + ZT_EVENT_DOWN = 3, - /** - * Your identity has collided with another node's ZeroTier address - * - * This happens if two different public keys both hash (via the algorithm - * in Identity::generate()) to the same 40-bit ZeroTier address. - * - * This is something you should "never" see, where "never" is defined as - * once per 2^39 new node initializations / identity creations. If you do - * see it, you're going to see it very soon after a node is first - * initialized. - * - * This is reported as an event rather than a return code since it's - * detected asynchronously via error messages from authoritative nodes. - * - * If this occurs, you must shut down and delete the node, delete the - * identity.secret record/file from the data store, and restart to generate - * a new identity. If you don't do this, you will not be able to communicate - * with other nodes. - * - * We'd automate this process, but we don't think silently deleting - * private keys or changing our address without telling the calling code - * is good form. It violates the principle of least surprise. - * - * You can technically get away with not handling this, but we recommend - * doing so in a mature reliable application. Besides, handling this - * condition is a good way to make sure it never arises. It's like how - * umbrellas prevent rain and smoke detectors prevent fires. They do, right? - * - * Meta-data: none - */ - ZT_EVENT_FATAL_ERROR_IDENTITY_COLLISION = 4, + /** + * Your identity has collided with another node's ZeroTier address + * + * This happens if two different public keys both hash (via the algorithm + * in Identity::generate()) to the same 40-bit ZeroTier address. + * + * This is something you should "never" see, where "never" is defined as + * once per 2^39 new node initializations / identity creations. If you do + * see it, you're going to see it very soon after a node is first + * initialized. + * + * This is reported as an event rather than a return code since it's + * detected asynchronously via error messages from authoritative nodes. + * + * If this occurs, you must shut down and delete the node, delete the + * identity.secret record/file from the data store, and restart to generate + * a new identity. If you don't do this, you will not be able to communicate + * with other nodes. + * + * We'd automate this process, but we don't think silently deleting + * private keys or changing our address without telling the calling code + * is good form. It violates the principle of least surprise. + * + * You can technically get away with not handling this, but we recommend + * doing so in a mature reliable application. Besides, handling this + * condition is a good way to make sure it never arises. It's like how + * umbrellas prevent rain and smoke detectors prevent fires. They do, right? + * + * Meta-data: none + */ + ZT_EVENT_FATAL_ERROR_IDENTITY_COLLISION = 4, - /** - * Trace (debugging) message - * - * These events are only generated if this is a TRACE-enabled build. - * - * Meta-data: C string, TRACE message - */ - ZT_EVENT_TRACE = 5, + /** + * Trace (debugging) message + * + * These events are only generated if this is a TRACE-enabled build. + * + * Meta-data: C string, TRACE message + */ + ZT_EVENT_TRACE = 5, - /** - * VERB_USER_MESSAGE received - * - * These are generated when a VERB_USER_MESSAGE packet is received via - * ZeroTier VL1. - * - * Meta-data: ZT_UserMessage structure - */ - ZT_EVENT_USER_MESSAGE = 6, + /** + * VERB_USER_MESSAGE received + * + * These are generated when a VERB_USER_MESSAGE packet is received via + * ZeroTier VL1. + * + * Meta-data: ZT_UserMessage structure + */ + ZT_EVENT_USER_MESSAGE = 6, - /** - * Remote trace received - * - * These are generated when a VERB_REMOTE_TRACE is received. Note - * that any node can fling one of these at us. It is your responsibility - * to filter and determine if it's worth paying attention to. If it's - * not just drop it. Most nodes that are not active controllers ignore - * these, and controllers only save them if they pertain to networks - * with remote tracing enabled. - * - * Meta-data: ZT_RemoteTrace structure - */ - ZT_EVENT_REMOTE_TRACE = 7 + /** + * Remote trace received + * + * These are generated when a VERB_REMOTE_TRACE is received. Note + * that any node can fling one of these at us. It is your responsibility + * to filter and determine if it's worth paying attention to. If it's + * not just drop it. Most nodes that are not active controllers ignore + * these, and controllers only save them if they pertain to networks + * with remote tracing enabled. + * + * Meta-data: ZT_RemoteTrace structure + */ + ZT_EVENT_REMOTE_TRACE = 7 }; /** * Payload of REMOTE_TRACE event */ -typedef struct -{ - /** - * ZeroTier address of sender - */ - uint64_t origin; +typedef struct { + /** + * ZeroTier address of sender + */ + uint64_t origin; - /** - * Null-terminated Dictionary containing key/value pairs sent by origin - * - * This *should* be a dictionary, but the implementation only checks - * that it is a valid non-empty C-style null-terminated string. Be very - * careful to use a well-tested parser to parse this as it represents - * data received from a potentially un-trusted peer on the network. - * Invalid payloads should be dropped. - * - * The contents of data[] may be modified. - */ - char *data; + /** + * Null-terminated Dictionary containing key/value pairs sent by origin + * + * This *should* be a dictionary, but the implementation only checks + * that it is a valid non-empty C-style null-terminated string. Be very + * careful to use a well-tested parser to parse this as it represents + * data received from a potentially un-trusted peer on the network. + * Invalid payloads should be dropped. + * + * The contents of data[] may be modified. + */ + char* data; - /** - * Length of dict[] in bytes, including terminating null - */ - unsigned int len; + /** + * Length of dict[] in bytes, including terminating null + */ + unsigned int len; } ZT_RemoteTrace; /** @@ -570,57 +567,55 @@ typedef struct * in the world can send you a user message! (Unless your network is air * gapped.) */ -typedef struct -{ - /** - * ZeroTier address of sender (least significant 40 bits) - */ - uint64_t origin; +typedef struct { + /** + * ZeroTier address of sender (least significant 40 bits) + */ + uint64_t origin; - /** - * User message type ID - */ - uint64_t typeId; + /** + * User message type ID + */ + uint64_t typeId; - /** - * User message data (not including type ID) - */ - const void *data; + /** + * User message data (not including type ID) + */ + const void* data; - /** - * Length of data in bytes - */ - unsigned int length; + /** + * Length of data in bytes + */ + unsigned int length; } ZT_UserMessage; /** * Current node status */ -typedef struct -{ - /** - * 40-bit ZeroTier address of this node - */ - uint64_t address; +typedef struct { + /** + * 40-bit ZeroTier address of this node + */ + uint64_t address; - /** - * Public identity in string-serialized form (safe to send to others) - * - * This pointer will remain valid as long as the node exists. - */ - const char *publicIdentity; + /** + * Public identity in string-serialized form (safe to send to others) + * + * This pointer will remain valid as long as the node exists. + */ + const char* publicIdentity; - /** - * Full identity including secret key in string-serialized form - * - * This pointer will remain valid as long as the node exists. - */ - const char *secretIdentity; + /** + * Full identity including secret key in string-serialized form + * + * This pointer will remain valid as long as the node exists. + */ + const char* secretIdentity; - /** - * True if some kind of connectivity appears available - */ - int online; + /** + * True if some kind of connectivity appears available + */ + int online; } ZT_NodeStatus; /** @@ -628,74 +623,71 @@ typedef struct * * This structure is subject to change between versions. */ -typedef struct -{ - /** - * Number of each protocol verb (possible verbs 0..31) received - */ - uint64_t inVerbCounts[32]; +typedef struct { + /** + * Number of each protocol verb (possible verbs 0..31) received + */ + uint64_t inVerbCounts[32]; - /** - * Number of bytes for each protocol verb received - */ - uint64_t inVerbBytes[32]; + /** + * Number of bytes for each protocol verb received + */ + uint64_t inVerbBytes[32]; } ZT_NodeStatistics; /** * Virtual network status codes */ -enum ZT_VirtualNetworkStatus -{ - /** - * Waiting for network configuration (also means revision == 0) - */ - ZT_NETWORK_STATUS_REQUESTING_CONFIGURATION = 0, +enum ZT_VirtualNetworkStatus { + /** + * Waiting for network configuration (also means revision == 0) + */ + ZT_NETWORK_STATUS_REQUESTING_CONFIGURATION = 0, - /** - * Configuration received and we are authorized - */ - ZT_NETWORK_STATUS_OK = 1, + /** + * Configuration received and we are authorized + */ + ZT_NETWORK_STATUS_OK = 1, - /** - * Netconf master told us 'nope' - */ - ZT_NETWORK_STATUS_ACCESS_DENIED = 2, + /** + * Netconf master told us 'nope' + */ + ZT_NETWORK_STATUS_ACCESS_DENIED = 2, - /** - * Netconf master exists, but this virtual network does not - */ - ZT_NETWORK_STATUS_NOT_FOUND = 3, + /** + * Netconf master exists, but this virtual network does not + */ + ZT_NETWORK_STATUS_NOT_FOUND = 3, - /** - * Initialization of network failed or other internal error - */ - ZT_NETWORK_STATUS_PORT_ERROR = 4, + /** + * Initialization of network failed or other internal error + */ + ZT_NETWORK_STATUS_PORT_ERROR = 4, - /** - * ZeroTier core version too old - */ - ZT_NETWORK_STATUS_CLIENT_TOO_OLD = 5, + /** + * ZeroTier core version too old + */ + ZT_NETWORK_STATUS_CLIENT_TOO_OLD = 5, - /** - * External authentication is required (e.g. SSO) - */ - ZT_NETWORK_STATUS_AUTHENTICATION_REQUIRED = 6 + /** + * External authentication is required (e.g. SSO) + */ + ZT_NETWORK_STATUS_AUTHENTICATION_REQUIRED = 6 }; /** * Virtual network type codes */ -enum ZT_VirtualNetworkType -{ - /** - * Private networks are authorized via certificates of membership - */ - ZT_NETWORK_TYPE_PRIVATE = 0, +enum ZT_VirtualNetworkType { + /** + * Private networks are authorized via certificates of membership + */ + ZT_NETWORK_TYPE_PRIVATE = 0, - /** - * Public networks have no access control -- they'll always be AUTHORIZED - */ - ZT_NETWORK_TYPE_PUBLIC = 1 + /** + * Public networks have no access control -- they'll always be AUTHORIZED + */ + ZT_NETWORK_TYPE_PUBLIC = 1 }; /** @@ -707,85 +699,84 @@ enum ZT_VirtualNetworkType * Each rule is composed of zero or more MATCHes followed by an ACTION. * An ACTION with no MATCHes is always taken. */ -enum ZT_VirtualNetworkRuleType -{ - // 0 to 15 reserved for actions +enum ZT_VirtualNetworkRuleType { + // 0 to 15 reserved for actions - /** - * Drop frame - */ - ZT_NETWORK_RULE_ACTION_DROP = 0, + /** + * Drop frame + */ + ZT_NETWORK_RULE_ACTION_DROP = 0, - /** - * Accept and pass frame - */ - ZT_NETWORK_RULE_ACTION_ACCEPT = 1, + /** + * Accept and pass frame + */ + ZT_NETWORK_RULE_ACTION_ACCEPT = 1, - /** - * Forward a copy of this frame to an observer (by ZT address) - */ - ZT_NETWORK_RULE_ACTION_TEE = 2, + /** + * Forward a copy of this frame to an observer (by ZT address) + */ + ZT_NETWORK_RULE_ACTION_TEE = 2, - /** - * Exactly like TEE but mandates ACKs from observer - */ - ZT_NETWORK_RULE_ACTION_WATCH = 3, + /** + * Exactly like TEE but mandates ACKs from observer + */ + ZT_NETWORK_RULE_ACTION_WATCH = 3, - /** - * Drop and redirect this frame to another node (by ZT address) - */ - ZT_NETWORK_RULE_ACTION_REDIRECT = 4, + /** + * Drop and redirect this frame to another node (by ZT address) + */ + ZT_NETWORK_RULE_ACTION_REDIRECT = 4, - /** - * Stop evaluating rule set (drops unless there are capabilities, etc.) - */ - ZT_NETWORK_RULE_ACTION_BREAK = 5, + /** + * Stop evaluating rule set (drops unless there are capabilities, etc.) + */ + ZT_NETWORK_RULE_ACTION_BREAK = 5, - /** - * Place a matching frame in the specified QoS bucket - */ - ZT_NETWORK_RULE_ACTION_PRIORITY = 6, + /** + * Place a matching frame in the specified QoS bucket + */ + ZT_NETWORK_RULE_ACTION_PRIORITY = 6, - /** - * Maximum ID for an ACTION, anything higher is a MATCH - */ - ZT_NETWORK_RULE_ACTION__MAX_ID = 15, + /** + * Maximum ID for an ACTION, anything higher is a MATCH + */ + ZT_NETWORK_RULE_ACTION__MAX_ID = 15, - // 16 to 63 reserved for match criteria + // 16 to 63 reserved for match criteria - ZT_NETWORK_RULE_MATCH_SOURCE_ZEROTIER_ADDRESS = 24, - ZT_NETWORK_RULE_MATCH_DEST_ZEROTIER_ADDRESS = 25, - ZT_NETWORK_RULE_MATCH_VLAN_ID = 26, - ZT_NETWORK_RULE_MATCH_VLAN_PCP = 27, - ZT_NETWORK_RULE_MATCH_VLAN_DEI = 28, - ZT_NETWORK_RULE_MATCH_MAC_SOURCE = 29, - ZT_NETWORK_RULE_MATCH_MAC_DEST = 30, - ZT_NETWORK_RULE_MATCH_IPV4_SOURCE = 31, - ZT_NETWORK_RULE_MATCH_IPV4_DEST = 32, - ZT_NETWORK_RULE_MATCH_IPV6_SOURCE = 33, - ZT_NETWORK_RULE_MATCH_IPV6_DEST = 34, - ZT_NETWORK_RULE_MATCH_IP_TOS = 35, - ZT_NETWORK_RULE_MATCH_IP_PROTOCOL = 36, - ZT_NETWORK_RULE_MATCH_ETHERTYPE = 37, - ZT_NETWORK_RULE_MATCH_ICMP = 38, - ZT_NETWORK_RULE_MATCH_IP_SOURCE_PORT_RANGE = 39, - ZT_NETWORK_RULE_MATCH_IP_DEST_PORT_RANGE = 40, - ZT_NETWORK_RULE_MATCH_CHARACTERISTICS = 41, - ZT_NETWORK_RULE_MATCH_FRAME_SIZE_RANGE = 42, - ZT_NETWORK_RULE_MATCH_RANDOM = 43, - ZT_NETWORK_RULE_MATCH_TAGS_DIFFERENCE = 44, - ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_AND = 45, - ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_OR = 46, - ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_XOR = 47, - ZT_NETWORK_RULE_MATCH_TAGS_EQUAL = 48, - ZT_NETWORK_RULE_MATCH_TAG_SENDER = 49, - ZT_NETWORK_RULE_MATCH_TAG_RECEIVER = 50, - ZT_NETWORK_RULE_MATCH_INTEGER_RANGE = 51, + ZT_NETWORK_RULE_MATCH_SOURCE_ZEROTIER_ADDRESS = 24, + ZT_NETWORK_RULE_MATCH_DEST_ZEROTIER_ADDRESS = 25, + ZT_NETWORK_RULE_MATCH_VLAN_ID = 26, + ZT_NETWORK_RULE_MATCH_VLAN_PCP = 27, + ZT_NETWORK_RULE_MATCH_VLAN_DEI = 28, + ZT_NETWORK_RULE_MATCH_MAC_SOURCE = 29, + ZT_NETWORK_RULE_MATCH_MAC_DEST = 30, + ZT_NETWORK_RULE_MATCH_IPV4_SOURCE = 31, + ZT_NETWORK_RULE_MATCH_IPV4_DEST = 32, + ZT_NETWORK_RULE_MATCH_IPV6_SOURCE = 33, + ZT_NETWORK_RULE_MATCH_IPV6_DEST = 34, + ZT_NETWORK_RULE_MATCH_IP_TOS = 35, + ZT_NETWORK_RULE_MATCH_IP_PROTOCOL = 36, + ZT_NETWORK_RULE_MATCH_ETHERTYPE = 37, + ZT_NETWORK_RULE_MATCH_ICMP = 38, + ZT_NETWORK_RULE_MATCH_IP_SOURCE_PORT_RANGE = 39, + ZT_NETWORK_RULE_MATCH_IP_DEST_PORT_RANGE = 40, + ZT_NETWORK_RULE_MATCH_CHARACTERISTICS = 41, + ZT_NETWORK_RULE_MATCH_FRAME_SIZE_RANGE = 42, + ZT_NETWORK_RULE_MATCH_RANDOM = 43, + ZT_NETWORK_RULE_MATCH_TAGS_DIFFERENCE = 44, + ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_AND = 45, + ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_OR = 46, + ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_XOR = 47, + ZT_NETWORK_RULE_MATCH_TAGS_EQUAL = 48, + ZT_NETWORK_RULE_MATCH_TAG_SENDER = 49, + ZT_NETWORK_RULE_MATCH_TAG_RECEIVER = 50, + ZT_NETWORK_RULE_MATCH_INTEGER_RANGE = 51, - /** - * Maximum ID allowed for a MATCH entry in the rules table - */ - ZT_NETWORK_RULE_MATCH__MAX_ID = 63 + /** + * Maximum ID allowed for a MATCH entry in the rules table + */ + ZT_NETWORK_RULE_MATCH__MAX_ID = 63 }; /** @@ -799,733 +790,713 @@ enum ZT_VirtualNetworkRuleType * This is designed to be a more memory-efficient way of storing rules than * a wide table, yet still fast and simple to access in code. */ -typedef struct -{ - /** - * Type and flags - * - * Bits are: NOTTTTTT - * - * N - If true, sense of match is inverted (no effect on actions) - * O - If true, result is ORed with previous instead of ANDed (no effect on actions) - * T - Rule or action type - * - * AND with 0x3f to get type, 0x80 to get NOT bit, and 0x40 to get OR bit. - */ - uint8_t t; +typedef struct { + /** + * Type and flags + * + * Bits are: NOTTTTTT + * + * N - If true, sense of match is inverted (no effect on actions) + * O - If true, result is ORed with previous instead of ANDed (no effect on actions) + * T - Rule or action type + * + * AND with 0x3f to get type, 0x80 to get NOT bit, and 0x40 to get OR bit. + */ + uint8_t t; - /** - * Union containing the value of this rule -- which field is used depends on 't' - */ - union { - /** - * IPv6 address in big-endian / network byte order and netmask bits - */ - struct { - uint8_t ip[16]; - uint8_t mask; - } ipv6; + /** + * Union containing the value of this rule -- which field is used depends on 't' + */ + union { + /** + * IPv6 address in big-endian / network byte order and netmask bits + */ + struct { + uint8_t ip[16]; + uint8_t mask; + } ipv6; - /** - * IPv4 address in big-endian / network byte order - */ - struct { - uint32_t ip; - uint8_t mask; - } ipv4; + /** + * IPv4 address in big-endian / network byte order + */ + struct { + uint32_t ip; + uint8_t mask; + } ipv4; - /** - * Integer range match in packet payload - * - * This allows matching of ranges of integers up to 64 bits wide where - * the range is +/- INT32_MAX. It's packed this way so it fits in 16 - * bytes and doesn't enlarge the overall size of this union. - */ - struct { - uint64_t start; // integer range start - uint32_t end; // end of integer range (relative to start, inclusive, 0 for equality w/start) - uint16_t idx; // index in packet of integer - uint8_t format; // bits in integer (range 1-64, ((format&63)+1)) and endianness (MSB 1 for little, 0 for big) - } intRange; + /** + * Integer range match in packet payload + * + * This allows matching of ranges of integers up to 64 bits wide where + * the range is +/- INT32_MAX. It's packed this way so it fits in 16 + * bytes and doesn't enlarge the overall size of this union. + */ + struct { + uint64_t start; // integer range start + uint32_t end; // end of integer range (relative to start, inclusive, 0 for equality w/start) + uint16_t idx; // index in packet of integer + uint8_t format; // bits in integer (range 1-64, ((format&63)+1)) and endianness (MSB 1 for little, 0 for big) + } intRange; - /** - * Packet characteristic flags being matched - */ - uint64_t characteristics; + /** + * Packet characteristic flags being matched + */ + uint64_t characteristics; - /** - * IP port range -- start-end inclusive -- host byte order - */ - uint16_t port[2]; + /** + * IP port range -- start-end inclusive -- host byte order + */ + uint16_t port[2]; - /** - * 40-bit ZeroTier address (in least significant bits, host byte order) - */ - uint64_t zt; + /** + * 40-bit ZeroTier address (in least significant bits, host byte order) + */ + uint64_t zt; - /** - * 0 = never, UINT32_MAX = always - */ - uint32_t randomProbability; + /** + * 0 = never, UINT32_MAX = always + */ + uint32_t randomProbability; - /** - * 48-bit Ethernet MAC address in big-endian order - */ - uint8_t mac[6]; + /** + * 48-bit Ethernet MAC address in big-endian order + */ + uint8_t mac[6]; - /** - * VLAN ID in host byte order - */ - uint16_t vlanId; + /** + * VLAN ID in host byte order + */ + uint16_t vlanId; - /** - * VLAN PCP (least significant 3 bits) - */ - uint8_t vlanPcp; + /** + * VLAN PCP (least significant 3 bits) + */ + uint8_t vlanPcp; - /** - * VLAN DEI (single bit / boolean) - */ - uint8_t vlanDei; + /** + * VLAN DEI (single bit / boolean) + */ + uint8_t vlanDei; - /** - * Ethernet type in host byte order - */ - uint16_t etherType; + /** + * Ethernet type in host byte order + */ + uint16_t etherType; - /** - * IP protocol - */ - uint8_t ipProtocol; + /** + * IP protocol + */ + uint8_t ipProtocol; - /** - * IP type of service a.k.a. DSCP field - */ - struct { - uint8_t mask; - uint8_t value[2]; - } ipTos; + /** + * IP type of service a.k.a. DSCP field + */ + struct { + uint8_t mask; + uint8_t value[2]; + } ipTos; - /** - * Ethernet packet size in host byte order (start-end, inclusive) - */ - uint16_t frameSize[2]; + /** + * Ethernet packet size in host byte order (start-end, inclusive) + */ + uint16_t frameSize[2]; - /** - * ICMP type and code - */ - struct { - uint8_t type; // ICMP type, always matched - uint8_t code; // ICMP code if matched - uint8_t flags; // flag 0x01 means also match code, otherwise only match type - } icmp; + /** + * ICMP type and code + */ + struct { + uint8_t type; // ICMP type, always matched + uint8_t code; // ICMP code if matched + uint8_t flags; // flag 0x01 means also match code, otherwise only match type + } icmp; - /** - * For tag-related rules - */ - struct { - uint32_t id; - uint32_t value; - } tag; + /** + * For tag-related rules + */ + struct { + uint32_t id; + uint32_t value; + } tag; - /** - * Destinations for TEE and REDIRECT - */ - struct { - uint64_t address; - uint32_t flags; - uint16_t length; - } fwd; + /** + * Destinations for TEE and REDIRECT + */ + struct { + uint64_t address; + uint32_t flags; + uint16_t length; + } fwd; - /** - * Quality of Service (QoS) bucket we want a frame to be placed in - */ - uint8_t qosBucket; - } v; + /** + * Quality of Service (QoS) bucket we want a frame to be placed in + */ + uint8_t qosBucket; + } v; } ZT_VirtualNetworkRule; /** * A route to be pushed on a virtual network */ -typedef struct -{ - /** - * Target network / netmask bits (in port field) or NULL or 0.0.0.0/0 for default - */ - struct sockaddr_storage target; +typedef struct { + /** + * Target network / netmask bits (in port field) or NULL or 0.0.0.0/0 for default + */ + struct sockaddr_storage target; - /** - * Gateway IP address (port ignored) or NULL (family == 0) for LAN-local (no gateway) - */ - struct sockaddr_storage via; + /** + * Gateway IP address (port ignored) or NULL (family == 0) for LAN-local (no gateway) + */ + struct sockaddr_storage via; - /** - * Route flags - */ - uint16_t flags; + /** + * Route flags + */ + uint16_t flags; - /** - * Route metric (not currently used) - */ - uint16_t metric; + /** + * Route metric (not currently used) + */ + uint16_t metric; } ZT_VirtualNetworkRoute; /** * DNS configuration to be pushed on a virtual network */ -typedef struct -{ - char domain[128]; - struct sockaddr_storage server_addr[ZT_MAX_DNS_SERVERS]; +typedef struct { + char domain[128]; + struct sockaddr_storage server_addr[ZT_MAX_DNS_SERVERS]; } ZT_VirtualNetworkDNS; /** * An Ethernet multicast group */ -typedef struct -{ - /** - * MAC address (least significant 48 bits) - */ - uint64_t mac; +typedef struct { + /** + * MAC address (least significant 48 bits) + */ + uint64_t mac; - /** - * Additional distinguishing information (usually zero) - */ - unsigned long adi; + /** + * Additional distinguishing information (usually zero) + */ + unsigned long adi; } ZT_MulticastGroup; /** * Virtual network configuration update type */ -enum ZT_VirtualNetworkConfigOperation -{ - /** - * Network is coming up (either for the first time or after service restart) - */ - ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_UP = 1, +enum ZT_VirtualNetworkConfigOperation { + /** + * Network is coming up (either for the first time or after service restart) + */ + ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_UP = 1, - /** - * Network configuration has been updated - */ - ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_CONFIG_UPDATE = 2, + /** + * Network configuration has been updated + */ + ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_CONFIG_UPDATE = 2, - /** - * Network is going down (not permanently) - */ - ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_DOWN = 3, + /** + * Network is going down (not permanently) + */ + ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_DOWN = 3, - /** - * Network is going down permanently (leave/delete) - */ - ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_DESTROY = 4 + /** + * Network is going down permanently (leave/delete) + */ + ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_DESTROY = 4 }; /** * What trust hierarchy role does this peer have? */ -enum ZT_PeerRole -{ - ZT_PEER_ROLE_LEAF = 0, // ordinary node - ZT_PEER_ROLE_MOON = 1, // moon root - ZT_PEER_ROLE_PLANET = 2 // planetary root +enum ZT_PeerRole { + ZT_PEER_ROLE_LEAF = 0, // ordinary node + ZT_PEER_ROLE_MOON = 1, // moon root + ZT_PEER_ROLE_PLANET = 2 // planetary root }; /** * Vendor ID */ -enum ZT_Vendor -{ - ZT_VENDOR_UNSPECIFIED = 0, - ZT_VENDOR_ZEROTIER = 1 -}; +enum ZT_Vendor { ZT_VENDOR_UNSPECIFIED = 0, ZT_VENDOR_ZEROTIER = 1 }; /** * Platform type */ -enum ZT_Platform -{ - ZT_PLATFORM_UNSPECIFIED = 0, - ZT_PLATFORM_LINUX = 1, - ZT_PLATFORM_WINDOWS = 2, - ZT_PLATFORM_MACOS = 3, - ZT_PLATFORM_ANDROID = 4, - ZT_PLATFORM_IOS = 5, - ZT_PLATFORM_SOLARIS_SMARTOS = 6, - ZT_PLATFORM_FREEBSD = 7, - ZT_PLATFORM_NETBSD = 8, - ZT_PLATFORM_OPENBSD = 9, - ZT_PLATFORM_RISCOS = 10, - ZT_PLATFORM_VXWORKS = 11, - ZT_PLATFORM_FREERTOS = 12, - ZT_PLATFORM_SYSBIOS = 13, - ZT_PLATFORM_HURD = 14, - ZT_PLATFORM_WEB = 15 +enum ZT_Platform { + ZT_PLATFORM_UNSPECIFIED = 0, + ZT_PLATFORM_LINUX = 1, + ZT_PLATFORM_WINDOWS = 2, + ZT_PLATFORM_MACOS = 3, + ZT_PLATFORM_ANDROID = 4, + ZT_PLATFORM_IOS = 5, + ZT_PLATFORM_SOLARIS_SMARTOS = 6, + ZT_PLATFORM_FREEBSD = 7, + ZT_PLATFORM_NETBSD = 8, + ZT_PLATFORM_OPENBSD = 9, + ZT_PLATFORM_RISCOS = 10, + ZT_PLATFORM_VXWORKS = 11, + ZT_PLATFORM_FREERTOS = 12, + ZT_PLATFORM_SYSBIOS = 13, + ZT_PLATFORM_HURD = 14, + ZT_PLATFORM_WEB = 15 }; /** * Architecture type */ -enum ZT_Architecture -{ - ZT_ARCHITECTURE_UNSPECIFIED = 0, - ZT_ARCHITECTURE_X86 = 1, - ZT_ARCHITECTURE_X64 = 2, - ZT_ARCHITECTURE_ARM32 = 3, - ZT_ARCHITECTURE_ARM64 = 4, - ZT_ARCHITECTURE_MIPS32 = 5, - ZT_ARCHITECTURE_MIPS64 = 6, - ZT_ARCHITECTURE_POWER32 = 7, - ZT_ARCHITECTURE_POWER64 = 8, - ZT_ARCHITECTURE_OPENRISC32 = 9, - ZT_ARCHITECTURE_OPENRISC64 = 10, - ZT_ARCHITECTURE_SPARC32 = 11, - ZT_ARCHITECTURE_SPARC64 = 12, - ZT_ARCHITECTURE_DOTNET_CLR = 13, - ZT_ARCHITECTURE_JAVA_JVM = 14, - ZT_ARCHITECTURE_WEB = 15, - ZT_ARCHITECTURE_S390X = 16, - ZT_ARCHITECTURE_LOONGARCH64 = 17 +enum ZT_Architecture { + ZT_ARCHITECTURE_UNSPECIFIED = 0, + ZT_ARCHITECTURE_X86 = 1, + ZT_ARCHITECTURE_X64 = 2, + ZT_ARCHITECTURE_ARM32 = 3, + ZT_ARCHITECTURE_ARM64 = 4, + ZT_ARCHITECTURE_MIPS32 = 5, + ZT_ARCHITECTURE_MIPS64 = 6, + ZT_ARCHITECTURE_POWER32 = 7, + ZT_ARCHITECTURE_POWER64 = 8, + ZT_ARCHITECTURE_OPENRISC32 = 9, + ZT_ARCHITECTURE_OPENRISC64 = 10, + ZT_ARCHITECTURE_SPARC32 = 11, + ZT_ARCHITECTURE_SPARC64 = 12, + ZT_ARCHITECTURE_DOTNET_CLR = 13, + ZT_ARCHITECTURE_JAVA_JVM = 14, + ZT_ARCHITECTURE_WEB = 15, + ZT_ARCHITECTURE_S390X = 16, + ZT_ARCHITECTURE_LOONGARCH64 = 17 }; /** * Virtual network configuration */ -typedef struct -{ - /** - * 64-bit ZeroTier network ID - */ - uint64_t nwid; +typedef struct { + /** + * 64-bit ZeroTier network ID + */ + uint64_t nwid; - /** - * Ethernet MAC (48 bits) that should be assigned to port - */ - uint64_t mac; + /** + * Ethernet MAC (48 bits) that should be assigned to port + */ + uint64_t mac; - /** - * Network name (from network configuration master) - */ - char name[ZT_MAX_NETWORK_SHORT_NAME_LENGTH + 1]; + /** + * Network name (from network configuration master) + */ + char name[ZT_MAX_NETWORK_SHORT_NAME_LENGTH + 1]; - /** - * Network configuration request status - */ - enum ZT_VirtualNetworkStatus status; + /** + * Network configuration request status + */ + enum ZT_VirtualNetworkStatus status; - /** - * Network type - */ - enum ZT_VirtualNetworkType type; + /** + * Network type + */ + enum ZT_VirtualNetworkType type; - /** - * Maximum interface MTU - */ - unsigned int mtu; + /** + * Maximum interface MTU + */ + unsigned int mtu; - /** - * If nonzero, the network this port belongs to indicates DHCP availability - * - * This is a suggestion. The underlying implementation is free to ignore it - * for security or other reasons. This is simply a netconf parameter that - * means 'DHCP is available on this network.' - */ - int dhcp; + /** + * If nonzero, the network this port belongs to indicates DHCP availability + * + * This is a suggestion. The underlying implementation is free to ignore it + * for security or other reasons. This is simply a netconf parameter that + * means 'DHCP is available on this network.' + */ + int dhcp; - /** - * If nonzero, this port is allowed to bridge to other networks - * - * This is informational. If this is false (0), bridged packets will simply - * be dropped and bridging won't work. - */ - int bridge; + /** + * If nonzero, this port is allowed to bridge to other networks + * + * This is informational. If this is false (0), bridged packets will simply + * be dropped and bridging won't work. + */ + int bridge; - /** - * If nonzero, this network supports and allows broadcast (ff:ff:ff:ff:ff:ff) traffic - */ - int broadcastEnabled; + /** + * If nonzero, this network supports and allows broadcast (ff:ff:ff:ff:ff:ff) traffic + */ + int broadcastEnabled; - /** - * If the network is in PORT_ERROR state, this is the (negative) error code most recently reported - */ - int portError; + /** + * If the network is in PORT_ERROR state, this is the (negative) error code most recently reported + */ + int portError; - /** - * Revision number as reported by controller or 0 if still waiting for config - */ - unsigned long netconfRevision; + /** + * Revision number as reported by controller or 0 if still waiting for config + */ + unsigned long netconfRevision; - /** - * Number of assigned addresses - */ - unsigned int assignedAddressCount; + /** + * Number of assigned addresses + */ + unsigned int assignedAddressCount; - /** - * ZeroTier-assigned addresses (in sockaddr_storage structures) - * - * For IP, the port number of the sockaddr_XX structure contains the number - * of bits in the address netmask. Only the IP address and port are used. - * Other fields like interface number can be ignored. - * - * This is only used for ZeroTier-managed address assignments sent by the - * virtual network's configuration master. - */ - struct sockaddr_storage assignedAddresses[ZT_MAX_ZT_ASSIGNED_ADDRESSES]; + /** + * ZeroTier-assigned addresses (in sockaddr_storage structures) + * + * For IP, the port number of the sockaddr_XX structure contains the number + * of bits in the address netmask. Only the IP address and port are used. + * Other fields like interface number can be ignored. + * + * This is only used for ZeroTier-managed address assignments sent by the + * virtual network's configuration master. + */ + struct sockaddr_storage assignedAddresses[ZT_MAX_ZT_ASSIGNED_ADDRESSES]; - /** - * Number of ZT-pushed routes - */ - unsigned int routeCount; + /** + * Number of ZT-pushed routes + */ + unsigned int routeCount; - /** - * Routes (excluding those implied by assigned addresses and their masks) - */ - ZT_VirtualNetworkRoute routes[ZT_MAX_NETWORK_ROUTES]; + /** + * Routes (excluding those implied by assigned addresses and their masks) + */ + ZT_VirtualNetworkRoute routes[ZT_MAX_NETWORK_ROUTES]; - /** - * Number of multicast groups subscribed - */ - unsigned int multicastSubscriptionCount; + /** + * Number of multicast groups subscribed + */ + unsigned int multicastSubscriptionCount; - /** - * Multicast groups to which this network's device is subscribed - */ - struct { - uint64_t mac; /* MAC in lower 48 bits */ - uint32_t adi; /* Additional distinguishing information, usually zero except for IPv4 ARP groups */ - } multicastSubscriptions[ZT_MAX_MULTICAST_SUBSCRIPTIONS]; + /** + * Multicast groups to which this network's device is subscribed + */ + struct { + uint64_t mac; /* MAC in lower 48 bits */ + uint32_t adi; /* Additional distinguishing information, usually zero except for IPv4 ARP groups */ + } multicastSubscriptions[ZT_MAX_MULTICAST_SUBSCRIPTIONS]; - /** - * Network specific DNS configuration - */ - ZT_VirtualNetworkDNS dns; + /** + * Network specific DNS configuration + */ + ZT_VirtualNetworkDNS dns; + /** + * sso enabled + */ + bool ssoEnabled; + /** + * SSO version + */ + uint64_t ssoVersion; - /** - * sso enabled - */ - bool ssoEnabled; + /** + * If the status us AUTHENTICATION_REQUIRED, this may contain a URL for authentication. + */ + char authenticationURL[2048]; - /** - * SSO version - */ - uint64_t ssoVersion; + /** + * Time that current authentication expires. only valid if ssoEnabled is true + */ + uint64_t authenticationExpiryTime; - /** - * If the status us AUTHENTICATION_REQUIRED, this may contain a URL for authentication. - */ - char authenticationURL[2048]; + /** + * OIDC issuer URL. + */ + char issuerURL[2048]; - /** - * Time that current authentication expires. only valid if ssoEnabled is true - */ - uint64_t authenticationExpiryTime; + /** + * central base URL. + */ + char centralAuthURL[2048]; - /** - * OIDC issuer URL. - */ - char issuerURL[2048]; + /** + * sso nonce + */ + char ssoNonce[128]; - /** - * central base URL. - */ - char centralAuthURL[2048]; + /** + * sso state + */ + char ssoState[256]; - /** - * sso nonce - */ - char ssoNonce[128]; + /** + * oidc client id + */ + char ssoClientID[256]; - /** - * sso state - */ - char ssoState[256]; - - /** - * oidc client id - */ - char ssoClientID[256]; - - /** - * sso provider - **/ - char ssoProvider[64]; + /** + * sso provider + **/ + char ssoProvider[64]; } ZT_VirtualNetworkConfig; /** * A list of networks */ -typedef struct -{ - ZT_VirtualNetworkConfig *networks; - unsigned long networkCount; +typedef struct { + ZT_VirtualNetworkConfig* networks; + unsigned long networkCount; } ZT_VirtualNetworkList; /** * Physical path configuration */ typedef struct { - /** - * If non-zero set this physical network path to be trusted to disable encryption and authentication - */ - uint64_t trustedPathId; + /** + * If non-zero set this physical network path to be trusted to disable encryption and authentication + */ + uint64_t trustedPathId; - /** - * Physical path MTU from ZT_MIN_PHYSMTU and ZT_MAX_PHYSMTU or <= 0 to use default - */ - int mtu; + /** + * Physical path MTU from ZT_MIN_PHYSMTU and ZT_MAX_PHYSMTU or <= 0 to use default + */ + int mtu; } ZT_PhysicalPathConfiguration; /** * Physical network path to a peer */ -typedef struct -{ - /** - * Address of endpoint - */ - struct sockaddr_storage address; +typedef struct { + /** + * Address of endpoint + */ + struct sockaddr_storage address; - /** - * Time of last send in milliseconds or 0 for never - */ - uint64_t lastSend; + /** + * Time of last send in milliseconds or 0 for never + */ + uint64_t lastSend; - /** - * Time of last receive in milliseconds or 0 for never - */ - uint64_t lastReceive; + /** + * Time of last receive in milliseconds or 0 for never + */ + uint64_t lastReceive; - /** - * Is this a trusted path? If so this will be its nonzero ID. - */ - uint64_t trustedPathId; + /** + * Is this a trusted path? If so this will be its nonzero ID. + */ + uint64_t trustedPathId; - /** - * Mean latency - */ - float latencyMean; + /** + * Mean latency + */ + float latencyMean; - /** - * Maximum observed latency - */ - float latencyMax; + /** + * Maximum observed latency + */ + float latencyMax; - /** - * Variance of latency - */ - float latencyVariance; + /** + * Variance of latency + */ + float latencyVariance; - /** - * Packet loss ratio - */ - float packetLossRatio; + /** + * Packet loss ratio + */ + float packetLossRatio; - /** - * Packet error ratio - */ - float packetErrorRatio; + /** + * Packet error ratio + */ + float packetErrorRatio; - /** - * Number of flows assigned to this path - */ - uint16_t assignedFlowCount; + /** + * Number of flows assigned to this path + */ + uint16_t assignedFlowCount; - /** - * Address scope - */ - uint8_t scope; + /** + * Address scope + */ + uint8_t scope; - /** - * Relative quality value - */ - float relativeQuality; + /** + * Relative quality value + */ + float relativeQuality; - /** - * Name of physical interface this path resides on - */ - char ifname[ZT_MAX_PHYSIFNAME]; + /** + * Name of physical interface this path resides on + */ + char ifname[ZT_MAX_PHYSIFNAME]; - /** - * Pointer to PhySocket object for this path - */ - uint64_t localSocket; + /** + * Pointer to PhySocket object for this path + */ + uint64_t localSocket; - /** - * Local port corresponding to this path's localSocket - */ - uint16_t localPort; + /** + * Local port corresponding to this path's localSocket + */ + uint16_t localPort; - /** - * Is path expired? - */ - int expired; + /** + * Is path expired? + */ + int expired; - /** - * Whether this path is currently included in the bond - */ - uint8_t bonded; + /** + * Whether this path is currently included in the bond + */ + uint8_t bonded; - /** - * Whether this path is currently eligible to be used in a bond - */ - uint8_t eligible; + /** + * Whether this path is currently eligible to be used in a bond + */ + uint8_t eligible; - /** - * The capacity of this link (as given to bonding layer) - */ - uint32_t linkSpeed; + /** + * The capacity of this link (as given to bonding layer) + */ + uint32_t linkSpeed; - /** - * Is path preferred? - */ - int preferred; + /** + * Is path preferred? + */ + int preferred; } ZT_PeerPhysicalPath; /** * Peer status result buffer */ -typedef struct -{ - /** - * ZeroTier address (40 bits) - */ - uint64_t address; +typedef struct { + /** + * ZeroTier address (40 bits) + */ + uint64_t address; - /** - * Remote major version or -1 if not known - */ - int versionMajor; + /** + * Remote major version or -1 if not known + */ + int versionMajor; - /** - * Remote minor version or -1 if not known - */ - int versionMinor; + /** + * Remote minor version or -1 if not known + */ + int versionMinor; - /** - * Remote revision or -1 if not known - */ - int versionRev; + /** + * Remote revision or -1 if not known + */ + int versionRev; - /** - * Last measured latency in milliseconds or -1 if unknown - */ - int latency; + /** + * Last measured latency in milliseconds or -1 if unknown + */ + int latency; - /** - * What trust hierarchy role does this device have? - */ - enum ZT_PeerRole role; + /** + * What trust hierarchy role does this device have? + */ + enum ZT_PeerRole role; - /** - * Whether a multi-link bond has formed - */ - bool isBonded; + /** + * Whether a multi-link bond has formed + */ + bool isBonded; - /** - * The bonding policy used to bond to this peer - */ - int bondingPolicy; + /** + * The bonding policy used to bond to this peer + */ + int bondingPolicy; - /** - * The number of links that comprise the bond to this peer that are considered alive - */ - int numAliveLinks; + /** + * The number of links that comprise the bond to this peer that are considered alive + */ + int numAliveLinks; - /** - * The number of links that comprise the bond to this peer - */ - int numTotalLinks; + /** + * The number of links that comprise the bond to this peer + */ + int numTotalLinks; - /** - * The user-specified bond template name - */ - char customBondName[32]; + /** + * The user-specified bond template name + */ + char customBondName[32]; - /** - * Number of paths (size of paths[]) - */ - unsigned int pathCount; + /** + * Number of paths (size of paths[]) + */ + unsigned int pathCount; - /** - * Known network paths to peer - */ - ZT_PeerPhysicalPath paths[ZT_MAX_PEER_NETWORK_PATHS]; + /** + * Known network paths to peer + */ + ZT_PeerPhysicalPath paths[ZT_MAX_PEER_NETWORK_PATHS]; } ZT_Peer; /** * List of peers */ -typedef struct -{ - ZT_Peer *peers; - unsigned long peerCount; +typedef struct { + ZT_Peer* peers; + unsigned long peerCount; } ZT_PeerList; /** * ZeroTier core state objects */ -enum ZT_StateObjectType -{ - /** - * Null object -- ignored - */ - ZT_STATE_OBJECT_NULL = 0, +enum ZT_StateObjectType { + /** + * Null object -- ignored + */ + ZT_STATE_OBJECT_NULL = 0, - /** - * Public address and public key - * - * Object ID: this node's address if known, or 0 if unknown (first query) - * Canonical path: /identity.public - * Persistence: required - */ - ZT_STATE_OBJECT_IDENTITY_PUBLIC = 1, + /** + * Public address and public key + * + * Object ID: this node's address if known, or 0 if unknown (first query) + * Canonical path: /identity.public + * Persistence: required + */ + ZT_STATE_OBJECT_IDENTITY_PUBLIC = 1, - /** - * Full identity with secret key - * - * Object ID: this node's address if known, or 0 if unknown (first query) - * Canonical path: /identity.secret - * Persistence: required, should be stored with restricted permissions e.g. mode 0600 on *nix - */ - ZT_STATE_OBJECT_IDENTITY_SECRET = 2, + /** + * Full identity with secret key + * + * Object ID: this node's address if known, or 0 if unknown (first query) + * Canonical path: /identity.secret + * Persistence: required, should be stored with restricted permissions e.g. mode 0600 on *nix + */ + ZT_STATE_OBJECT_IDENTITY_SECRET = 2, - /** - * The planet (there is only one per... well... planet!) - * - * Object ID: world ID of planet, or 0 if unknown (first query) - * Canonical path: /planet - * Persistence: recommended - */ - ZT_STATE_OBJECT_PLANET = 3, + /** + * The planet (there is only one per... well... planet!) + * + * Object ID: world ID of planet, or 0 if unknown (first query) + * Canonical path: /planet + * Persistence: recommended + */ + ZT_STATE_OBJECT_PLANET = 3, - /** - * A moon (federated root set) - * - * Object ID: world ID of moon - * Canonical path: /moons.d/.moon (16-digit hex ID) - * Persistence: required if moon memberships should persist - */ - ZT_STATE_OBJECT_MOON = 4, + /** + * A moon (federated root set) + * + * Object ID: world ID of moon + * Canonical path: /moons.d/.moon (16-digit hex ID) + * Persistence: required if moon memberships should persist + */ + ZT_STATE_OBJECT_MOON = 4, - /** - * Peer and related state - * - * Object ID: peer address - * Canonical path: /peers.d/ (10-digit address - * Persistence: optional, can be cleared at any time - */ - ZT_STATE_OBJECT_PEER = 5, + /** + * Peer and related state + * + * Object ID: peer address + * Canonical path: /peers.d/ (10-digit address + * Persistence: optional, can be cleared at any time + */ + ZT_STATE_OBJECT_PEER = 5, - /** - * Network configuration - * - * Object ID: peer address - * Canonical path: /networks.d/.conf (16-digit hex ID) - * Persistence: required if network memberships should persist - */ - ZT_STATE_OBJECT_NETWORK_CONFIG = 6 + /** + * Network configuration + * + * Object ID: peer address + * Canonical path: /networks.d/.conf (16-digit hex ID) + * Persistence: required if network memberships should persist + */ + ZT_STATE_OBJECT_NETWORK_CONFIG = 6 }; /** @@ -1559,13 +1530,13 @@ typedef void ZT_Node; * PORT_ERROR state. */ typedef int (*ZT_VirtualNetworkConfigFunction)( - ZT_Node *, /* Node */ - void *, /* User ptr */ - void *, /* Thread ptr */ - uint64_t, /* Network ID */ - void **, /* Modifiable network user PTR */ - enum ZT_VirtualNetworkConfigOperation, /* Config operation */ - const ZT_VirtualNetworkConfig *); /* Network configuration */ + ZT_Node*, /* Node */ + void*, /* User ptr */ + void*, /* Thread ptr */ + uint64_t, /* Network ID */ + void**, /* Modifiable network user PTR */ + enum ZT_VirtualNetworkConfigOperation, /* Config operation */ + const ZT_VirtualNetworkConfig*); /* Network configuration */ /** * Function to send a frame out to a virtual network port @@ -1575,17 +1546,17 @@ typedef int (*ZT_VirtualNetworkConfigFunction)( * (9) frame length. */ typedef void (*ZT_VirtualNetworkFrameFunction)( - ZT_Node *, /* Node */ - void *, /* User ptr */ - void *, /* Thread ptr */ - uint64_t, /* Network ID */ - void **, /* Modifiable network user PTR */ - uint64_t, /* Source MAC */ - uint64_t, /* Destination MAC */ - unsigned int, /* Ethernet type */ - unsigned int, /* VLAN ID (0 for none) */ - const void *, /* Frame data */ - unsigned int); /* Frame length */ + ZT_Node*, /* Node */ + void*, /* User ptr */ + void*, /* Thread ptr */ + uint64_t, /* Network ID */ + void**, /* Modifiable network user PTR */ + uint64_t, /* Source MAC */ + uint64_t, /* Destination MAC */ + unsigned int, /* Ethernet type */ + unsigned int, /* VLAN ID (0 for none) */ + const void*, /* Frame data */ + unsigned int); /* Frame length */ /** * Callback for events @@ -1597,11 +1568,11 @@ typedef void (*ZT_VirtualNetworkFrameFunction)( * in the definition of ZT_Event. */ typedef void (*ZT_EventCallback)( - ZT_Node *, /* Node */ - void *, /* User ptr */ - void *, /* Thread ptr */ - enum ZT_Event, /* Event type */ - const void *); /* Event payload (if applicable) */ + ZT_Node*, /* Node */ + void*, /* User ptr */ + void*, /* Thread ptr */ + enum ZT_Event, /* Event type */ + const void*); /* Event payload (if applicable) */ /** * Callback for storing and/or publishing state information @@ -1613,13 +1584,13 @@ typedef void (*ZT_EventCallback)( * deleted. */ typedef void (*ZT_StatePutFunction)( - ZT_Node *, /* Node */ - void *, /* User ptr */ - void *, /* Thread ptr */ - enum ZT_StateObjectType, /* State object type */ - const uint64_t [2], /* State object ID (if applicable) */ - const void *, /* State object data */ - int); /* Length of data or -1 to delete */ + ZT_Node*, /* Node */ + void*, /* User ptr */ + void*, /* Thread ptr */ + enum ZT_StateObjectType, /* State object type */ + const uint64_t[2], /* State object ID (if applicable) */ + const void*, /* State object data */ + int); /* Length of data or -1 to delete */ /** * Callback for retrieving stored state information @@ -1629,13 +1600,13 @@ typedef void (*ZT_StatePutFunction)( * small to store it. */ typedef int (*ZT_StateGetFunction)( - ZT_Node *, /* Node */ - void *, /* User ptr */ - void *, /* Thread ptr */ - enum ZT_StateObjectType, /* State object type */ - const uint64_t [2], /* State object ID (if applicable) */ - void *, /* Buffer to store state object data */ - unsigned int); /* Length of data buffer in bytes */ + ZT_Node*, /* Node */ + void*, /* User ptr */ + void*, /* Thread ptr */ + enum ZT_StateObjectType, /* State object type */ + const uint64_t[2], /* State object ID (if applicable) */ + void*, /* Buffer to store state object data */ + unsigned int); /* Length of data buffer in bytes */ /** * Function to send a ZeroTier packet out over the physical wire (L2/L3) @@ -1662,14 +1633,14 @@ typedef int (*ZT_StateGetFunction)( * delivery. It only means that the packet appears to have been sent. */ typedef int (*ZT_WirePacketSendFunction)( - ZT_Node *, /* Node */ - void *, /* User ptr */ - void *, /* Thread ptr */ - int64_t, /* Local socket */ - const struct sockaddr_storage *, /* Remote address */ - const void *, /* Packet data */ - unsigned int, /* Packet length */ - unsigned int); /* TTL or 0 to use default */ + ZT_Node*, /* Node */ + void*, /* User ptr */ + void*, /* Thread ptr */ + int64_t, /* Local socket */ + const struct sockaddr_storage*, /* Remote address */ + const void*, /* Packet data */ + unsigned int, /* Packet length */ + unsigned int); /* TTL or 0 to use default */ /** * Function to check whether a path should be used for ZeroTier traffic @@ -1693,12 +1664,12 @@ typedef int (*ZT_WirePacketSendFunction)( * interface (recursion). */ typedef int (*ZT_PathCheckFunction)( - ZT_Node *, /* Node */ - void *, /* User ptr */ - void *, /* Thread ptr */ - uint64_t, /* ZeroTier address */ - int64_t, /* Local socket or -1 if unknown */ - const struct sockaddr_storage *); /* Remote address */ + ZT_Node*, /* Node */ + void*, /* User ptr */ + void*, /* Thread ptr */ + uint64_t, /* ZeroTier address */ + int64_t, /* Local socket or -1 if unknown */ + const struct sockaddr_storage*); /* Remote address */ /** * Function to get physical addresses for ZeroTier peers @@ -1716,12 +1687,12 @@ typedef int (*ZT_PathCheckFunction)( * with an address. */ typedef int (*ZT_PathLookupFunction)( - ZT_Node *, /* Node */ - void *, /* User ptr */ - void *, /* Thread ptr */ - uint64_t, /* ZeroTier address (40 bits) */ - int, /* Desired ss_family or -1 for any */ - struct sockaddr_storage *); /* Result buffer */ + ZT_Node*, /* Node */ + void*, /* User ptr */ + void*, /* Thread ptr */ + uint64_t, /* ZeroTier address (40 bits) */ + int, /* Desired ss_family or -1 for any */ + struct sockaddr_storage*); /* Result buffer */ /****************************************************************************/ /* C Node API */ @@ -1730,52 +1701,51 @@ typedef int (*ZT_PathLookupFunction)( /** * Structure for configuring ZeroTier core callback functions */ -struct ZT_Node_Callbacks -{ - /** - * Struct version -- must currently be 0 - */ - long version; +struct ZT_Node_Callbacks { + /** + * Struct version -- must currently be 0 + */ + long version; - /** - * REQUIRED: Function to store and/or replicate state objects - */ - ZT_StatePutFunction statePutFunction; + /** + * REQUIRED: Function to store and/or replicate state objects + */ + ZT_StatePutFunction statePutFunction; - /** - * REQUIRED: Function to retrieve state objects from an object store - */ - ZT_StateGetFunction stateGetFunction; + /** + * REQUIRED: Function to retrieve state objects from an object store + */ + ZT_StateGetFunction stateGetFunction; - /** - * REQUIRED: Function to send packets over the physical wire - */ - ZT_WirePacketSendFunction wirePacketSendFunction; + /** + * REQUIRED: Function to send packets over the physical wire + */ + ZT_WirePacketSendFunction wirePacketSendFunction; - /** - * REQUIRED: Function to inject frames into a virtual network's TAP - */ - ZT_VirtualNetworkFrameFunction virtualNetworkFrameFunction; + /** + * REQUIRED: Function to inject frames into a virtual network's TAP + */ + ZT_VirtualNetworkFrameFunction virtualNetworkFrameFunction; - /** - * REQUIRED: Function to be called when virtual networks are configured or changed - */ - ZT_VirtualNetworkConfigFunction virtualNetworkConfigFunction; + /** + * REQUIRED: Function to be called when virtual networks are configured or changed + */ + ZT_VirtualNetworkConfigFunction virtualNetworkConfigFunction; - /** - * REQUIRED: Function to be called to notify external code of important events - */ - ZT_EventCallback eventCallback; + /** + * REQUIRED: Function to be called to notify external code of important events + */ + ZT_EventCallback eventCallback; - /** - * OPTIONAL: Function to check whether a given physical path should be used - */ - ZT_PathCheckFunction pathCheckFunction; + /** + * OPTIONAL: Function to check whether a given physical path should be used + */ + ZT_PathCheckFunction pathCheckFunction; - /** - * OPTIONAL: Function to get hints to physical paths to ZeroTier addresses - */ - ZT_PathLookupFunction pathLookupFunction; + /** + * OPTIONAL: Function to get hints to physical paths to ZeroTier addresses + */ + ZT_PathLookupFunction pathLookupFunction; }; /** @@ -1793,7 +1763,7 @@ struct ZT_Node_Callbacks * @param now Current clock in milliseconds * @return OK (0) or error code if a fatal error condition has occurred */ -ZT_SDK_API enum ZT_ResultCode ZT_Node_new(ZT_Node **node,void *uptr,void *tptr,const struct ZT_Node_Callbacks *callbacks,int64_t now); +ZT_SDK_API enum ZT_ResultCode ZT_Node_new(ZT_Node** node, void* uptr, void* tptr, const struct ZT_Node_Callbacks* callbacks, int64_t now); /** * Delete a node and free all resources it consumes @@ -1803,7 +1773,7 @@ ZT_SDK_API enum ZT_ResultCode ZT_Node_new(ZT_Node **node,void *uptr,void *tptr,c * * @param node Node to delete */ -ZT_SDK_API void ZT_Node_delete(ZT_Node *node); +ZT_SDK_API void ZT_Node_delete(ZT_Node* node); /** * Process a packet received from the physical wire @@ -1818,15 +1788,8 @@ ZT_SDK_API void ZT_Node_delete(ZT_Node *node); * @param nextBackgroundTaskDeadline Value/result: set to deadline for next call to processBackgroundTasks() * @return OK (0) or error code if a fatal error condition has occurred */ -ZT_SDK_API enum ZT_ResultCode ZT_Node_processWirePacket( - ZT_Node *node, - void *tptr, - int64_t now, - int64_t localSocket, - const struct sockaddr_storage *remoteAddress, - const void *packetData, - unsigned int packetLength, - volatile int64_t *nextBackgroundTaskDeadline); +ZT_SDK_API enum ZT_ResultCode +ZT_Node_processWirePacket(ZT_Node* node, void* tptr, int64_t now, int64_t localSocket, const struct sockaddr_storage* remoteAddress, const void* packetData, unsigned int packetLength, volatile int64_t* nextBackgroundTaskDeadline); /** * Process a frame from a virtual network port (tap) @@ -1845,17 +1808,17 @@ ZT_SDK_API enum ZT_ResultCode ZT_Node_processWirePacket( * @return OK (0) or error code if a fatal error condition has occurred */ ZT_SDK_API enum ZT_ResultCode ZT_Node_processVirtualNetworkFrame( - ZT_Node *node, - void *tptr, - int64_t now, - uint64_t nwid, - uint64_t sourceMac, - uint64_t destMac, - unsigned int etherType, - unsigned int vlanId, - const void *frameData, - unsigned int frameLength, - volatile int64_t *nextBackgroundTaskDeadline); + ZT_Node* node, + void* tptr, + int64_t now, + uint64_t nwid, + uint64_t sourceMac, + uint64_t destMac, + unsigned int etherType, + unsigned int vlanId, + const void* frameData, + unsigned int frameLength, + volatile int64_t* nextBackgroundTaskDeadline); /** * Perform periodic background operations @@ -1866,7 +1829,7 @@ ZT_SDK_API enum ZT_ResultCode ZT_Node_processVirtualNetworkFrame( * @param nextBackgroundTaskDeadline Value/result: set to deadline for next call to processBackgroundTasks() * @return OK (0) or error code if a fatal error condition has occurred */ -ZT_SDK_API enum ZT_ResultCode ZT_Node_processBackgroundTasks(ZT_Node *node,void *tptr,int64_t now,volatile int64_t *nextBackgroundTaskDeadline); +ZT_SDK_API enum ZT_ResultCode ZT_Node_processBackgroundTasks(ZT_Node* node, void* tptr, int64_t now, volatile int64_t* nextBackgroundTaskDeadline); /** * Join a network @@ -1882,7 +1845,7 @@ ZT_SDK_API enum ZT_ResultCode ZT_Node_processBackgroundTasks(ZT_Node *node,void * @param uptr An arbitrary pointer to associate with this network (default: NULL) * @return OK (0) or error code if a fatal error condition has occurred */ -ZT_SDK_API enum ZT_ResultCode ZT_Node_join(ZT_Node *node,uint64_t nwid,void *uptr,void *tptr); +ZT_SDK_API enum ZT_ResultCode ZT_Node_join(ZT_Node* node, uint64_t nwid, void* uptr, void* tptr); /** * Leave a network @@ -1899,7 +1862,7 @@ ZT_SDK_API enum ZT_ResultCode ZT_Node_join(ZT_Node *node,uint64_t nwid,void *upt * @param uptr Target pointer is set to uptr (if not NULL) * @return OK (0) or error code if a fatal error condition has occurred */ -ZT_SDK_API enum ZT_ResultCode ZT_Node_leave(ZT_Node *node,uint64_t nwid,void **uptr,void *tptr); +ZT_SDK_API enum ZT_ResultCode ZT_Node_leave(ZT_Node* node, uint64_t nwid, void** uptr, void* tptr); /** * Subscribe to an Ethernet multicast group @@ -1927,7 +1890,7 @@ ZT_SDK_API enum ZT_ResultCode ZT_Node_leave(ZT_Node *node,uint64_t nwid,void **u * @param multicastAdi Multicast ADI (least significant 32 bits only, use 0 if not needed) * @return OK (0) or error code if a fatal error condition has occurred */ -ZT_SDK_API enum ZT_ResultCode ZT_Node_multicastSubscribe(ZT_Node *node,void *tptr,uint64_t nwid,uint64_t multicastGroup,unsigned long multicastAdi); +ZT_SDK_API enum ZT_ResultCode ZT_Node_multicastSubscribe(ZT_Node* node, void* tptr, uint64_t nwid, uint64_t multicastGroup, unsigned long multicastAdi); /** * Unsubscribe from an Ethernet multicast group (or all groups) @@ -1943,7 +1906,7 @@ ZT_SDK_API enum ZT_ResultCode ZT_Node_multicastSubscribe(ZT_Node *node,void *tpt * @param multicastAdi Multicast ADI (least significant 32 bits only, use 0 if not needed) * @return OK (0) or error code if a fatal error condition has occurred */ -ZT_SDK_API enum ZT_ResultCode ZT_Node_multicastUnsubscribe(ZT_Node *node,uint64_t nwid,uint64_t multicastGroup,unsigned long multicastAdi); +ZT_SDK_API enum ZT_ResultCode ZT_Node_multicastUnsubscribe(ZT_Node* node, uint64_t nwid, uint64_t multicastGroup, unsigned long multicastAdi); /** * Add or update a moon @@ -1959,7 +1922,7 @@ ZT_SDK_API enum ZT_ResultCode ZT_Node_multicastUnsubscribe(ZT_Node *node,uint64_ * @param len Length of moonWorld in bytes * @return Error if moon was invalid or failed to be added */ -ZT_SDK_API enum ZT_ResultCode ZT_Node_orbit(ZT_Node *node,void *tptr,uint64_t moonWorldId,uint64_t moonSeed); +ZT_SDK_API enum ZT_ResultCode ZT_Node_orbit(ZT_Node* node, void* tptr, uint64_t moonWorldId, uint64_t moonSeed); /** * Remove a moon (does nothing if not present) @@ -1969,7 +1932,7 @@ ZT_SDK_API enum ZT_ResultCode ZT_Node_orbit(ZT_Node *node,void *tptr,uint64_t mo * @param moonWorldId World ID of moon to remove * @return Error if anything bad happened */ -ZT_SDK_API enum ZT_ResultCode ZT_Node_deorbit(ZT_Node *node,void *tptr,uint64_t moonWorldId); +ZT_SDK_API enum ZT_ResultCode ZT_Node_deorbit(ZT_Node* node, void* tptr, uint64_t moonWorldId); /** * Get this node's 40-bit ZeroTier address @@ -1977,7 +1940,7 @@ ZT_SDK_API enum ZT_ResultCode ZT_Node_deorbit(ZT_Node *node,void *tptr,uint64_t * @param node Node instance * @return ZeroTier address (least significant 40 bits of 64-bit int) */ -ZT_SDK_API uint64_t ZT_Node_address(ZT_Node *node); +ZT_SDK_API uint64_t ZT_Node_address(ZT_Node* node); /** * Get the status of this node @@ -1985,7 +1948,7 @@ ZT_SDK_API uint64_t ZT_Node_address(ZT_Node *node); * @param node Node instance * @param status Buffer to fill with current node status */ -ZT_SDK_API void ZT_Node_status(ZT_Node *node,ZT_NodeStatus *status); +ZT_SDK_API void ZT_Node_status(ZT_Node* node, ZT_NodeStatus* status); /** * Get a list of known peer nodes @@ -1996,7 +1959,7 @@ ZT_SDK_API void ZT_Node_status(ZT_Node *node,ZT_NodeStatus *status); * @param node Node instance * @return List of known peers or NULL on failure */ -ZT_SDK_API ZT_PeerList *ZT_Node_peers(ZT_Node *node); +ZT_SDK_API ZT_PeerList* ZT_Node_peers(ZT_Node* node); /** * Get the status of a virtual network @@ -2008,7 +1971,7 @@ ZT_SDK_API ZT_PeerList *ZT_Node_peers(ZT_Node *node); * @param nwid 64-bit network ID * @return Network configuration or NULL if we are not a member of this network */ -ZT_SDK_API ZT_VirtualNetworkConfig *ZT_Node_networkConfig(ZT_Node *node,uint64_t nwid); +ZT_SDK_API ZT_VirtualNetworkConfig* ZT_Node_networkConfig(ZT_Node* node, uint64_t nwid); /** * Enumerate and get status of all networks @@ -2016,7 +1979,7 @@ ZT_SDK_API ZT_VirtualNetworkConfig *ZT_Node_networkConfig(ZT_Node *node,uint64_t * @param node Node instance * @return List of networks or NULL on failure */ -ZT_SDK_API ZT_VirtualNetworkList *ZT_Node_networks(ZT_Node *node); +ZT_SDK_API ZT_VirtualNetworkList* ZT_Node_networks(ZT_Node* node); /** * Free a query result buffer @@ -2026,7 +1989,7 @@ ZT_SDK_API ZT_VirtualNetworkList *ZT_Node_networks(ZT_Node *node); * @param node Node instance * @param qr Query result buffer */ -ZT_SDK_API void ZT_Node_freeQueryResult(ZT_Node *node,void *qr); +ZT_SDK_API void ZT_Node_freeQueryResult(ZT_Node* node, void* qr); /** * Add a local interface address @@ -2050,12 +2013,12 @@ ZT_SDK_API void ZT_Node_freeQueryResult(ZT_Node *node,void *qr); * @param addr Local interface address * @return Boolean: non-zero if address was accepted and added */ -ZT_SDK_API int ZT_Node_addLocalInterfaceAddress(ZT_Node *node,const struct sockaddr_storage *addr); +ZT_SDK_API int ZT_Node_addLocalInterfaceAddress(ZT_Node* node, const struct sockaddr_storage* addr); /** * Clear local interface addresses */ -ZT_SDK_API void ZT_Node_clearLocalInterfaceAddresses(ZT_Node *node); +ZT_SDK_API void ZT_Node_clearLocalInterfaceAddresses(ZT_Node* node); /** * Send a VERB_USER_MESSAGE to another ZeroTier node @@ -2071,7 +2034,7 @@ ZT_SDK_API void ZT_Node_clearLocalInterfaceAddresses(ZT_Node *node); * @param len Length of data in bytes * @return Boolean: non-zero on success, zero on failure */ -ZT_SDK_API int ZT_Node_sendUserMessage(ZT_Node *node,void *tptr,uint64_t dest,uint64_t typeId,const void *data,unsigned int len); +ZT_SDK_API int ZT_Node_sendUserMessage(ZT_Node* node, void* tptr, uint64_t dest, uint64_t typeId, const void* data, unsigned int len); /** * Set a network configuration master instance for this node @@ -2088,7 +2051,7 @@ ZT_SDK_API int ZT_Node_sendUserMessage(ZT_Node *node,void *tptr,uint64_t dest,ui * @param networkConfigMasterInstance Instance of NetworkConfigMaster C++ class or NULL to disable * @return OK (0) or error code if a fatal error condition has occurred */ -ZT_SDK_API void ZT_Node_setNetconfMaster(ZT_Node *node,void *networkConfigMasterInstance); +ZT_SDK_API void ZT_Node_setNetconfMaster(ZT_Node* node, void* networkConfigMasterInstance); /** * Set configuration for a given physical path @@ -2098,7 +2061,7 @@ ZT_SDK_API void ZT_Node_setNetconfMaster(ZT_Node *node,void *networkConfigMaster * @param pathConfig Path configuration or NULL to erase this entry and therefore reset it to NULL * @return OK or error code */ -ZT_SDK_API enum ZT_ResultCode ZT_Node_setPhysicalPathConfiguration(ZT_Node *node,const struct sockaddr_storage *pathNetwork,const ZT_PhysicalPathConfiguration *pathConfig); +ZT_SDK_API enum ZT_ResultCode ZT_Node_setPhysicalPathConfiguration(ZT_Node* node, const struct sockaddr_storage* pathNetwork, const ZT_PhysicalPathConfiguration* pathConfig); /** * Get ZeroTier One version @@ -2107,7 +2070,7 @@ ZT_SDK_API enum ZT_ResultCode ZT_Node_setPhysicalPathConfiguration(ZT_Node *node * @param minor Result: minor version * @param revision Result: revision */ -ZT_SDK_API void ZT_version(int *major,int *minor,int *revision); +ZT_SDK_API void ZT_version(int* major, int* minor, int* revision); #ifdef __cplusplus } diff --git a/node/AES.cpp b/node/AES.cpp index 739e8889..5f757961 100644 --- a/node/AES.cpp +++ b/node/AES.cpp @@ -11,9 +11,10 @@ */ /****/ -#include "Constants.hpp" #include "AES.hpp" +#include "Constants.hpp" + #ifdef __GNUC__ #pragma GCC diagnostic ignored "-Wstrict-aliasing" #endif @@ -31,667 +32,696 @@ namespace ZeroTier { namespace { -#define s_bmul32(N, x, y, rh, rl) \ - uint32_t x0t_##N = (x) & 0x11111111U; \ - uint32_t x1t_##N = (x) & 0x22222222U; \ - uint32_t x2t_##N = (x) & 0x44444444U; \ - uint32_t x3t_##N = (x) & 0x88888888U; \ - uint32_t y0t_##N = (y) & 0x11111111U; \ - uint32_t y1t_##N = (y) & 0x22222222U; \ - uint32_t y2t_##N = (y) & 0x44444444U; \ - uint32_t y3t_##N = (y) & 0x88888888U; \ - uint64_t z0t_##N = (((uint64_t)x0t_##N * y0t_##N) ^ ((uint64_t)x1t_##N * y3t_##N) ^ ((uint64_t)x2t_##N * y2t_##N) ^ ((uint64_t)x3t_##N * y1t_##N)) & 0x1111111111111111ULL; \ - uint64_t z1t_##N = (((uint64_t)x0t_##N * y1t_##N) ^ ((uint64_t)x1t_##N * y0t_##N) ^ ((uint64_t)x2t_##N * y3t_##N) ^ ((uint64_t)x3t_##N * y2t_##N)) & 0x2222222222222222ULL; \ - uint64_t z2t_##N = (((uint64_t)x0t_##N * y2t_##N) ^ ((uint64_t)x1t_##N * y1t_##N) ^ ((uint64_t)x2t_##N * y0t_##N) ^ ((uint64_t)x3t_##N * y3t_##N)) & 0x4444444444444444ULL; \ - z0t_##N |= z1t_##N; \ - z2t_##N |= z0t_##N; \ - uint64_t zt_##N = z2t_##N | ((((uint64_t)x0t_##N * y3t_##N) ^ ((uint64_t)x1t_##N * y2t_##N) ^ ((uint64_t)x2t_##N * y1t_##N) ^ ((uint64_t)x3t_##N * y0t_##N)) & 0x8888888888888888ULL); \ - (rh) = (uint32_t)(zt_##N >> 32U); \ - (rl) = (uint32_t)zt_##N; +#define s_bmul32(N, x, y, rh, rl) \ + uint32_t x0t_##N = (x) & 0x11111111U; \ + uint32_t x1t_##N = (x) & 0x22222222U; \ + uint32_t x2t_##N = (x) & 0x44444444U; \ + uint32_t x3t_##N = (x) & 0x88888888U; \ + uint32_t y0t_##N = (y) & 0x11111111U; \ + uint32_t y1t_##N = (y) & 0x22222222U; \ + uint32_t y2t_##N = (y) & 0x44444444U; \ + uint32_t y3t_##N = (y) & 0x88888888U; \ + uint64_t z0t_##N = (((uint64_t)x0t_##N * y0t_##N) ^ ((uint64_t)x1t_##N * y3t_##N) ^ ((uint64_t)x2t_##N * y2t_##N) ^ ((uint64_t)x3t_##N * y1t_##N)) & 0x1111111111111111ULL; \ + uint64_t z1t_##N = (((uint64_t)x0t_##N * y1t_##N) ^ ((uint64_t)x1t_##N * y0t_##N) ^ ((uint64_t)x2t_##N * y3t_##N) ^ ((uint64_t)x3t_##N * y2t_##N)) & 0x2222222222222222ULL; \ + uint64_t z2t_##N = (((uint64_t)x0t_##N * y2t_##N) ^ ((uint64_t)x1t_##N * y1t_##N) ^ ((uint64_t)x2t_##N * y0t_##N) ^ ((uint64_t)x3t_##N * y3t_##N)) & 0x4444444444444444ULL; \ + z0t_##N |= z1t_##N; \ + z2t_##N |= z0t_##N; \ + uint64_t zt_##N = z2t_##N | ((((uint64_t)x0t_##N * y3t_##N) ^ ((uint64_t)x1t_##N * y2t_##N) ^ ((uint64_t)x2t_##N * y1t_##N) ^ ((uint64_t)x3t_##N * y0t_##N)) & 0x8888888888888888ULL); \ + (rh) = (uint32_t)(zt_##N >> 32U); \ + (rl) = (uint32_t)zt_##N; -void s_gfmul(const uint64_t hh, const uint64_t hl, uint64_t &y0, uint64_t &y1) noexcept +void s_gfmul(const uint64_t hh, const uint64_t hl, uint64_t& y0, uint64_t& y1) noexcept { - uint32_t hhh = (uint32_t)(hh >> 32U); - uint32_t hhl = (uint32_t)hh; - uint32_t hlh = (uint32_t)(hl >> 32U); - uint32_t hll = (uint32_t)hl; - uint32_t hhXlh = hhh ^hlh; - uint32_t hhXll = hhl ^hll; - uint64_t yl = Utils::ntoh(y0); - uint64_t yh = Utils::ntoh(y1); - uint32_t cilh = (uint32_t)(yh >> 32U); - uint32_t cill = (uint32_t)yh; - uint32_t cihh = (uint32_t)(yl >> 32U); - uint32_t cihl = (uint32_t)yl; - uint32_t cihXlh = cihh ^cilh; - uint32_t cihXll = cihl ^cill; - uint32_t aah, aal, abh, abl, ach, acl; - s_bmul32(M0, cihh, hhh, aah, aal); - s_bmul32(M1, cihl, hhl, abh, abl); - s_bmul32(M2, cihh ^ cihl, hhh ^ hhl, ach, acl); - ach ^= aah ^ abh; - acl ^= aal ^ abl; - aal ^= ach; - abh ^= acl; - uint32_t bah, bal, bbh, bbl, bch, bcl; - s_bmul32(M3, cilh, hlh, bah, bal); - s_bmul32(M4, cill, hll, bbh, bbl); - s_bmul32(M5, cilh ^ cill, hlh ^ hll, bch, bcl); - bch ^= bah ^ bbh; - bcl ^= bal ^ bbl; - bal ^= bch; - bbh ^= bcl; - uint32_t cah, cal, cbh, cbl, cch, ccl; - s_bmul32(M6, cihXlh, hhXlh, cah, cal); - s_bmul32(M7, cihXll, hhXll, cbh, cbl); - s_bmul32(M8, cihXlh ^ cihXll, hhXlh ^ hhXll, cch, ccl); - cch ^= cah ^ cbh; - ccl ^= cal ^ cbl; - cal ^= cch; - cbh ^= ccl; - cah ^= bah ^ aah; - cal ^= bal ^ aal; - cbh ^= bbh ^ abh; - cbl ^= bbl ^ abl; - uint64_t zhh = ((uint64_t)aah << 32U) | aal; - uint64_t zhl = (((uint64_t)abh << 32U) | abl) ^(((uint64_t)cah << 32U) | cal); - uint64_t zlh = (((uint64_t)bah << 32U) | bal) ^(((uint64_t)cbh << 32U) | cbl); - uint64_t zll = ((uint64_t)bbh << 32U) | bbl; - zhh = zhh << 1U | zhl >> 63U; - zhl = zhl << 1U | zlh >> 63U; - zlh = zlh << 1U | zll >> 63U; - zll <<= 1U; - zlh ^= (zll << 63U) ^ (zll << 62U) ^ (zll << 57U); - zhh ^= zlh ^ (zlh >> 1U) ^ (zlh >> 2U) ^ (zlh >> 7U); - zhl ^= zll ^ (zll >> 1U) ^ (zll >> 2U) ^ (zll >> 7U) ^ (zlh << 63U) ^ (zlh << 62U) ^ (zlh << 57U); - y0 = Utils::hton(zhh); - y1 = Utils::hton(zhl); + uint32_t hhh = (uint32_t)(hh >> 32U); + uint32_t hhl = (uint32_t)hh; + uint32_t hlh = (uint32_t)(hl >> 32U); + uint32_t hll = (uint32_t)hl; + uint32_t hhXlh = hhh ^ hlh; + uint32_t hhXll = hhl ^ hll; + uint64_t yl = Utils::ntoh(y0); + uint64_t yh = Utils::ntoh(y1); + uint32_t cilh = (uint32_t)(yh >> 32U); + uint32_t cill = (uint32_t)yh; + uint32_t cihh = (uint32_t)(yl >> 32U); + uint32_t cihl = (uint32_t)yl; + uint32_t cihXlh = cihh ^ cilh; + uint32_t cihXll = cihl ^ cill; + uint32_t aah, aal, abh, abl, ach, acl; + s_bmul32(M0, cihh, hhh, aah, aal); + s_bmul32(M1, cihl, hhl, abh, abl); + s_bmul32(M2, cihh ^ cihl, hhh ^ hhl, ach, acl); + ach ^= aah ^ abh; + acl ^= aal ^ abl; + aal ^= ach; + abh ^= acl; + uint32_t bah, bal, bbh, bbl, bch, bcl; + s_bmul32(M3, cilh, hlh, bah, bal); + s_bmul32(M4, cill, hll, bbh, bbl); + s_bmul32(M5, cilh ^ cill, hlh ^ hll, bch, bcl); + bch ^= bah ^ bbh; + bcl ^= bal ^ bbl; + bal ^= bch; + bbh ^= bcl; + uint32_t cah, cal, cbh, cbl, cch, ccl; + s_bmul32(M6, cihXlh, hhXlh, cah, cal); + s_bmul32(M7, cihXll, hhXll, cbh, cbl); + s_bmul32(M8, cihXlh ^ cihXll, hhXlh ^ hhXll, cch, ccl); + cch ^= cah ^ cbh; + ccl ^= cal ^ cbl; + cal ^= cch; + cbh ^= ccl; + cah ^= bah ^ aah; + cal ^= bal ^ aal; + cbh ^= bbh ^ abh; + cbl ^= bbl ^ abl; + uint64_t zhh = ((uint64_t)aah << 32U) | aal; + uint64_t zhl = (((uint64_t)abh << 32U) | abl) ^ (((uint64_t)cah << 32U) | cal); + uint64_t zlh = (((uint64_t)bah << 32U) | bal) ^ (((uint64_t)cbh << 32U) | cbl); + uint64_t zll = ((uint64_t)bbh << 32U) | bbl; + zhh = zhh << 1U | zhl >> 63U; + zhl = zhl << 1U | zlh >> 63U; + zlh = zlh << 1U | zll >> 63U; + zll <<= 1U; + zlh ^= (zll << 63U) ^ (zll << 62U) ^ (zll << 57U); + zhh ^= zlh ^ (zlh >> 1U) ^ (zlh >> 2U) ^ (zlh >> 7U); + zhl ^= zll ^ (zll >> 1U) ^ (zll >> 2U) ^ (zll >> 7U) ^ (zlh << 63U) ^ (zlh << 62U) ^ (zlh << 57U); + y0 = Utils::hton(zhh); + y1 = Utils::hton(zhl); } -} // anonymous namespace +} // anonymous namespace -void AES::GMAC::update(const void *const data, unsigned int len) noexcept +void AES::GMAC::update(const void* const data, unsigned int len) noexcept { - const uint8_t *in = reinterpret_cast(data); - _len += len; + const uint8_t* in = reinterpret_cast(data); + _len += len; #ifdef ZT_AES_AESNI - if (likely(Utils::CPUID.aes)) { - p_aesNIUpdate(in, len); - return; - } -#endif // ZT_AES_AESNI + if (likely(Utils::CPUID.aes)) { + p_aesNIUpdate(in, len); + return; + } +#endif // ZT_AES_AESNI #ifdef ZT_AES_NEON - if (Utils::ARMCAP.pmull) { - p_armUpdate(in, len); - return; - } -#endif // ZT_AES_NEON + if (Utils::ARMCAP.pmull) { + p_armUpdate(in, len); + return; + } +#endif // ZT_AES_NEON - const uint64_t h0 = _aes.p_k.sw.h[0]; - const uint64_t h1 = _aes.p_k.sw.h[1]; - uint64_t y0 = _y[0]; - uint64_t y1 = _y[1]; + const uint64_t h0 = _aes.p_k.sw.h[0]; + const uint64_t h1 = _aes.p_k.sw.h[1]; + uint64_t y0 = _y[0]; + uint64_t y1 = _y[1]; - if (_rp) { - for (;;) { - if (!len) { - return; - } - --len; - _r[_rp++] = *(in++); - if (_rp == 16) { - y0 ^= Utils::loadMachineEndian< uint64_t >(_r); - y1 ^= Utils::loadMachineEndian< uint64_t >(_r + 8); - s_gfmul(h0, h1, y0, y1); - break; - } - } - } + if (_rp) { + for (;;) { + if (! len) { + return; + } + --len; + _r[_rp++] = *(in++); + if (_rp == 16) { + y0 ^= Utils::loadMachineEndian(_r); + y1 ^= Utils::loadMachineEndian(_r + 8); + s_gfmul(h0, h1, y0, y1); + break; + } + } + } - while (len >= 16) { - y0 ^= Utils::loadMachineEndian< uint64_t >(in); - y1 ^= Utils::loadMachineEndian< uint64_t >(in + 8); - in += 16; - s_gfmul(h0, h1, y0, y1); - len -= 16; - } + while (len >= 16) { + y0 ^= Utils::loadMachineEndian(in); + y1 ^= Utils::loadMachineEndian(in + 8); + in += 16; + s_gfmul(h0, h1, y0, y1); + len -= 16; + } - _y[0] = y0; - _y[1] = y1; + _y[0] = y0; + _y[1] = y1; - for (unsigned int i = 0; i < len; ++i) { - _r[i] = in[i]; - } - _rp = len; // len is always less than 16 here + for (unsigned int i = 0; i < len; ++i) { + _r[i] = in[i]; + } + _rp = len; // len is always less than 16 here } void AES::GMAC::finish(uint8_t tag[16]) noexcept { #ifdef ZT_AES_AESNI - if (likely(Utils::CPUID.aes)) { - p_aesNIFinish(tag); - return; - } -#endif // ZT_AES_AESNI + if (likely(Utils::CPUID.aes)) { + p_aesNIFinish(tag); + return; + } +#endif // ZT_AES_AESNI #ifdef ZT_AES_NEON - if (Utils::ARMCAP.pmull) { - p_armFinish(tag); - return; - } -#endif // ZT_AES_NEON + if (Utils::ARMCAP.pmull) { + p_armFinish(tag); + return; + } +#endif // ZT_AES_NEON - const uint64_t h0 = _aes.p_k.sw.h[0]; - const uint64_t h1 = _aes.p_k.sw.h[1]; - uint64_t y0 = _y[0]; - uint64_t y1 = _y[1]; + const uint64_t h0 = _aes.p_k.sw.h[0]; + const uint64_t h1 = _aes.p_k.sw.h[1]; + uint64_t y0 = _y[0]; + uint64_t y1 = _y[1]; - if (_rp) { - while (_rp < 16) { - _r[_rp++] = 0; - } - y0 ^= Utils::loadMachineEndian< uint64_t >(_r); - y1 ^= Utils::loadMachineEndian< uint64_t >(_r + 8); - s_gfmul(h0, h1, y0, y1); - } + if (_rp) { + while (_rp < 16) { + _r[_rp++] = 0; + } + y0 ^= Utils::loadMachineEndian(_r); + y1 ^= Utils::loadMachineEndian(_r + 8); + s_gfmul(h0, h1, y0, y1); + } - y0 ^= Utils::hton((uint64_t)_len << 3U); - s_gfmul(h0, h1, y0, y1); + y0 ^= Utils::hton((uint64_t)_len << 3U); + s_gfmul(h0, h1, y0, y1); - uint64_t iv2[2]; - Utils::copy< 12 >(iv2, _iv); + uint64_t iv2[2]; + Utils::copy<12>(iv2, _iv); #if __BYTE_ORDER == __BIG_ENDIAN - reinterpret_cast(iv2)[3] = 0x00000001; + reinterpret_cast(iv2)[3] = 0x00000001; #else - reinterpret_cast(iv2)[3] = 0x01000000; + reinterpret_cast(iv2)[3] = 0x01000000; #endif - _aes.encrypt(iv2, iv2); + _aes.encrypt(iv2, iv2); - Utils::storeMachineEndian< uint64_t >(tag, iv2[0] ^ y0); - Utils::storeMachineEndian< uint64_t >(tag + 8, iv2[1] ^ y1); + Utils::storeMachineEndian(tag, iv2[0] ^ y0); + Utils::storeMachineEndian(tag + 8, iv2[1] ^ y1); } // AES-CTR ------------------------------------------------------------------------------------------------------------ -void AES::CTR::crypt(const void *const input, unsigned int len) noexcept +void AES::CTR::crypt(const void* const input, unsigned int len) noexcept { - const uint8_t *in = reinterpret_cast(input); - uint8_t *out = _out; + const uint8_t* in = reinterpret_cast(input); + uint8_t* out = _out; #ifdef ZT_AES_AESNI - if (likely(Utils::CPUID.aes)) { - p_aesNICrypt(in, out, len); - return; - } -#endif // ZT_AES_AESNI + if (likely(Utils::CPUID.aes)) { + p_aesNICrypt(in, out, len); + return; + } +#endif // ZT_AES_AESNI #ifdef ZT_AES_NEON - if (Utils::ARMCAP.aes) { - p_armCrypt(in, out, len); - return; - } -#endif // ZT_AES_NEON + if (Utils::ARMCAP.aes) { + p_armCrypt(in, out, len); + return; + } +#endif // ZT_AES_NEON - uint64_t keyStream[2]; - uint32_t ctr = Utils::ntoh(reinterpret_cast(_ctr)[3]); + uint64_t keyStream[2]; + uint32_t ctr = Utils::ntoh(reinterpret_cast(_ctr)[3]); - unsigned int totalLen = _len; - if ((totalLen & 15U)) { - for (;;) { - if (!len) { - _len = (totalLen + len); - return; - } - --len; - out[totalLen++] = *(in++); - if (!(totalLen & 15U)) { - _aes.p_encryptSW(reinterpret_cast(_ctr), reinterpret_cast(keyStream)); - reinterpret_cast(_ctr)[3] = Utils::hton(++ctr); - uint8_t *outblk = out + (totalLen - 16); - for (int i = 0; i < 16; ++i) { - outblk[i] ^= reinterpret_cast(keyStream)[i]; - } - break; - } - } - } + unsigned int totalLen = _len; + if ((totalLen & 15U)) { + for (;;) { + if (! len) { + _len = (totalLen + len); + return; + } + --len; + out[totalLen++] = *(in++); + if (! (totalLen & 15U)) { + _aes.p_encryptSW(reinterpret_cast(_ctr), reinterpret_cast(keyStream)); + reinterpret_cast(_ctr)[3] = Utils::hton(++ctr); + uint8_t* outblk = out + (totalLen - 16); + for (int i = 0; i < 16; ++i) { + outblk[i] ^= reinterpret_cast(keyStream)[i]; + } + break; + } + } + } - out += totalLen; - _len = (totalLen + len); + out += totalLen; + _len = (totalLen + len); - if (likely(len >= 16)) { - const uint32_t *const restrict rk = _aes.p_k.sw.ek; - const uint32_t ctr0rk0 = Utils::ntoh(reinterpret_cast(_ctr)[0]) ^rk[0]; - const uint32_t ctr1rk1 = Utils::ntoh(reinterpret_cast(_ctr)[1]) ^rk[1]; - const uint32_t ctr2rk2 = Utils::ntoh(reinterpret_cast(_ctr)[2]) ^rk[2]; - const uint32_t m8 = 0x000000ff; - const uint32_t m8_8 = 0x0000ff00; - const uint32_t m8_16 = 0x00ff0000; - const uint32_t m8_24 = 0xff000000; - if (likely((((uintptr_t)out & 7U) == 0U) && (((uintptr_t)in & 7U) == 0U))) { - do { - uint32_t s0, s1, s2, s3, t0, t1, t2, t3; - s0 = ctr0rk0; - s1 = ctr1rk1; - s2 = ctr2rk2; - s3 = ctr++ ^ rk[3]; + if (likely(len >= 16)) { + const uint32_t* const restrict rk = _aes.p_k.sw.ek; + const uint32_t ctr0rk0 = Utils::ntoh(reinterpret_cast(_ctr)[0]) ^ rk[0]; + const uint32_t ctr1rk1 = Utils::ntoh(reinterpret_cast(_ctr)[1]) ^ rk[1]; + const uint32_t ctr2rk2 = Utils::ntoh(reinterpret_cast(_ctr)[2]) ^ rk[2]; + const uint32_t m8 = 0x000000ff; + const uint32_t m8_8 = 0x0000ff00; + const uint32_t m8_16 = 0x00ff0000; + const uint32_t m8_24 = 0xff000000; + if (likely((((uintptr_t)out & 7U) == 0U) && (((uintptr_t)in & 7U) == 0U))) { + do { + uint32_t s0, s1, s2, s3, t0, t1, t2, t3; + s0 = ctr0rk0; + s1 = ctr1rk1; + s2 = ctr2rk2; + s3 = ctr++ ^ rk[3]; - const uint64_t in0 = *reinterpret_cast(in); - const uint64_t in1 = *reinterpret_cast(in + 8); - in += 16; + const uint64_t in0 = *reinterpret_cast(in); + const uint64_t in1 = *reinterpret_cast(in + 8); + in += 16; - t0 = Te0[s0 >> 24U] ^ Te1_r((s1 >> 16U) & m8) ^ Te2_r((s2 >> 8U) & m8) ^ Te3_r(s3 & m8) ^ rk[4]; - t1 = Te0[s1 >> 24U] ^ Te1_r((s2 >> 16U) & m8) ^ Te2_r((s3 >> 8U) & m8) ^ Te3_r(s0 & m8) ^ rk[5]; - t2 = Te0[s2 >> 24U] ^ Te1_r((s3 >> 16U) & m8) ^ Te2_r((s0 >> 8U) & m8) ^ Te3_r(s1 & m8) ^ rk[6]; - t3 = Te0[s3 >> 24U] ^ Te1_r((s0 >> 16U) & m8) ^ Te2_r((s1 >> 8U) & m8) ^ Te3_r(s2 & m8) ^ rk[7]; - s0 = Te0[t0 >> 24U] ^ Te1_r((t1 >> 16U) & m8) ^ Te2_r((t2 >> 8U) & m8) ^ Te3_r(t3 & m8) ^ rk[8]; - s1 = Te0[t1 >> 24U] ^ Te1_r((t2 >> 16U) & m8) ^ Te2_r((t3 >> 8U) & m8) ^ Te3_r(t0 & m8) ^ rk[9]; - s2 = Te0[t2 >> 24U] ^ Te1_r((t3 >> 16U) & m8) ^ Te2_r((t0 >> 8U) & m8) ^ Te3_r(t1 & m8) ^ rk[10]; - s3 = Te0[t3 >> 24U] ^ Te1_r((t0 >> 16U) & m8) ^ Te2_r((t1 >> 8U) & m8) ^ Te3_r(t2 & m8) ^ rk[11]; - t0 = Te0[s0 >> 24U] ^ Te1_r((s1 >> 16U) & m8) ^ Te2_r((s2 >> 8U) & m8) ^ Te3_r(s3 & m8) ^ rk[12]; - t1 = Te0[s1 >> 24U] ^ Te1_r((s2 >> 16U) & m8) ^ Te2_r((s3 >> 8U) & m8) ^ Te3_r(s0 & m8) ^ rk[13]; - t2 = Te0[s2 >> 24U] ^ Te1_r((s3 >> 16U) & m8) ^ Te2_r((s0 >> 8U) & m8) ^ Te3_r(s1 & m8) ^ rk[14]; - t3 = Te0[s3 >> 24U] ^ Te1_r((s0 >> 16U) & m8) ^ Te2_r((s1 >> 8U) & m8) ^ Te3_r(s2 & m8) ^ rk[15]; - s0 = Te0[t0 >> 24U] ^ Te1_r((t1 >> 16U) & m8) ^ Te2_r((t2 >> 8U) & m8) ^ Te3_r(t3 & m8) ^ rk[16]; - s1 = Te0[t1 >> 24U] ^ Te1_r((t2 >> 16U) & m8) ^ Te2_r((t3 >> 8U) & m8) ^ Te3_r(t0 & m8) ^ rk[17]; - s2 = Te0[t2 >> 24U] ^ Te1_r((t3 >> 16U) & m8) ^ Te2_r((t0 >> 8U) & m8) ^ Te3_r(t1 & m8) ^ rk[18]; - s3 = Te0[t3 >> 24U] ^ Te1_r((t0 >> 16U) & m8) ^ Te2_r((t1 >> 8U) & m8) ^ Te3_r(t2 & m8) ^ rk[19]; - t0 = Te0[s0 >> 24U] ^ Te1_r((s1 >> 16U) & m8) ^ Te2_r((s2 >> 8U) & m8) ^ Te3_r(s3 & m8) ^ rk[20]; - t1 = Te0[s1 >> 24U] ^ Te1_r((s2 >> 16U) & m8) ^ Te2_r((s3 >> 8U) & m8) ^ Te3_r(s0 & m8) ^ rk[21]; - t2 = Te0[s2 >> 24U] ^ Te1_r((s3 >> 16U) & m8) ^ Te2_r((s0 >> 8U) & m8) ^ Te3_r(s1 & m8) ^ rk[22]; - t3 = Te0[s3 >> 24U] ^ Te1_r((s0 >> 16U) & m8) ^ Te2_r((s1 >> 8U) & m8) ^ Te3_r(s2 & m8) ^ rk[23]; - s0 = Te0[t0 >> 24U] ^ Te1_r((t1 >> 16U) & m8) ^ Te2_r((t2 >> 8U) & m8) ^ Te3_r(t3 & m8) ^ rk[24]; - s1 = Te0[t1 >> 24U] ^ Te1_r((t2 >> 16U) & m8) ^ Te2_r((t3 >> 8U) & m8) ^ Te3_r(t0 & m8) ^ rk[25]; - s2 = Te0[t2 >> 24U] ^ Te1_r((t3 >> 16U) & m8) ^ Te2_r((t0 >> 8U) & m8) ^ Te3_r(t1 & m8) ^ rk[26]; - s3 = Te0[t3 >> 24U] ^ Te1_r((t0 >> 16U) & m8) ^ Te2_r((t1 >> 8U) & m8) ^ Te3_r(t2 & m8) ^ rk[27]; - t0 = Te0[s0 >> 24U] ^ Te1_r((s1 >> 16U) & m8) ^ Te2_r((s2 >> 8U) & m8) ^ Te3_r(s3 & m8) ^ rk[28]; - t1 = Te0[s1 >> 24U] ^ Te1_r((s2 >> 16U) & m8) ^ Te2_r((s3 >> 8U) & m8) ^ Te3_r(s0 & m8) ^ rk[29]; - t2 = Te0[s2 >> 24U] ^ Te1_r((s3 >> 16U) & m8) ^ Te2_r((s0 >> 8U) & m8) ^ Te3_r(s1 & m8) ^ rk[30]; - t3 = Te0[s3 >> 24U] ^ Te1_r((s0 >> 16U) & m8) ^ Te2_r((s1 >> 8U) & m8) ^ Te3_r(s2 & m8) ^ rk[31]; - s0 = Te0[t0 >> 24U] ^ Te1_r((t1 >> 16U) & m8) ^ Te2_r((t2 >> 8U) & m8) ^ Te3_r(t3 & m8) ^ rk[32]; - s1 = Te0[t1 >> 24U] ^ Te1_r((t2 >> 16U) & m8) ^ Te2_r((t3 >> 8U) & m8) ^ Te3_r(t0 & m8) ^ rk[33]; - s2 = Te0[t2 >> 24U] ^ Te1_r((t3 >> 16U) & m8) ^ Te2_r((t0 >> 8U) & m8) ^ Te3_r(t1 & m8) ^ rk[34]; - s3 = Te0[t3 >> 24U] ^ Te1_r((t0 >> 16U) & m8) ^ Te2_r((t1 >> 8U) & m8) ^ Te3_r(t2 & m8) ^ rk[35]; - t0 = Te0[s0 >> 24U] ^ Te1_r((s1 >> 16U) & m8) ^ Te2_r((s2 >> 8U) & m8) ^ Te3_r(s3 & m8) ^ rk[36]; - t1 = Te0[s1 >> 24U] ^ Te1_r((s2 >> 16U) & m8) ^ Te2_r((s3 >> 8U) & m8) ^ Te3_r(s0 & m8) ^ rk[37]; - t2 = Te0[s2 >> 24U] ^ Te1_r((s3 >> 16U) & m8) ^ Te2_r((s0 >> 8U) & m8) ^ Te3_r(s1 & m8) ^ rk[38]; - t3 = Te0[s3 >> 24U] ^ Te1_r((s0 >> 16U) & m8) ^ Te2_r((s1 >> 8U) & m8) ^ Te3_r(s2 & m8) ^ rk[39]; - s0 = Te0[t0 >> 24U] ^ Te1_r((t1 >> 16U) & m8) ^ Te2_r((t2 >> 8U) & m8) ^ Te3_r(t3 & m8) ^ rk[40]; - s1 = Te0[t1 >> 24U] ^ Te1_r((t2 >> 16U) & m8) ^ Te2_r((t3 >> 8U) & m8) ^ Te3_r(t0 & m8) ^ rk[41]; - s2 = Te0[t2 >> 24U] ^ Te1_r((t3 >> 16U) & m8) ^ Te2_r((t0 >> 8U) & m8) ^ Te3_r(t1 & m8) ^ rk[42]; - s3 = Te0[t3 >> 24U] ^ Te1_r((t0 >> 16U) & m8) ^ Te2_r((t1 >> 8U) & m8) ^ Te3_r(t2 & m8) ^ rk[43]; - t0 = Te0[s0 >> 24U] ^ Te1_r((s1 >> 16U) & m8) ^ Te2_r((s2 >> 8U) & m8) ^ Te3_r(s3 & m8) ^ rk[44]; - t1 = Te0[s1 >> 24U] ^ Te1_r((s2 >> 16U) & m8) ^ Te2_r((s3 >> 8U) & m8) ^ Te3_r(s0 & m8) ^ rk[45]; - t2 = Te0[s2 >> 24U] ^ Te1_r((s3 >> 16U) & m8) ^ Te2_r((s0 >> 8U) & m8) ^ Te3_r(s1 & m8) ^ rk[46]; - t3 = Te0[s3 >> 24U] ^ Te1_r((s0 >> 16U) & m8) ^ Te2_r((s1 >> 8U) & m8) ^ Te3_r(s2 & m8) ^ rk[47]; - s0 = Te0[t0 >> 24U] ^ Te1_r((t1 >> 16U) & m8) ^ Te2_r((t2 >> 8U) & m8) ^ Te3_r(t3 & m8) ^ rk[48]; - s1 = Te0[t1 >> 24U] ^ Te1_r((t2 >> 16U) & m8) ^ Te2_r((t3 >> 8U) & m8) ^ Te3_r(t0 & m8) ^ rk[49]; - s2 = Te0[t2 >> 24U] ^ Te1_r((t3 >> 16U) & m8) ^ Te2_r((t0 >> 8U) & m8) ^ Te3_r(t1 & m8) ^ rk[50]; - s3 = Te0[t3 >> 24U] ^ Te1_r((t0 >> 16U) & m8) ^ Te2_r((t1 >> 8U) & m8) ^ Te3_r(t2 & m8) ^ rk[51]; - t0 = Te0[s0 >> 24U] ^ Te1_r((s1 >> 16U) & m8) ^ Te2_r((s2 >> 8U) & m8) ^ Te3_r(s3 & m8) ^ rk[52]; - t1 = Te0[s1 >> 24U] ^ Te1_r((s2 >> 16U) & m8) ^ Te2_r((s3 >> 8U) & m8) ^ Te3_r(s0 & m8) ^ rk[53]; - t2 = Te0[s2 >> 24U] ^ Te1_r((s3 >> 16U) & m8) ^ Te2_r((s0 >> 8U) & m8) ^ Te3_r(s1 & m8) ^ rk[54]; - t3 = Te0[s3 >> 24U] ^ Te1_r((s0 >> 16U) & m8) ^ Te2_r((s1 >> 8U) & m8) ^ Te3_r(s2 & m8) ^ rk[55]; - s0 = (Te2_r(t0 >> 24U) & m8_24) ^ (Te3_r((t1 >> 16U) & m8) & m8_16) ^ (Te0[(t2 >> 8U) & m8] & m8_8) ^ (Te1_r(t3 & m8) & m8) ^ rk[56]; - s1 = (Te2_r(t1 >> 24U) & m8_24) ^ (Te3_r((t2 >> 16U) & m8) & m8_16) ^ (Te0[(t3 >> 8U) & m8] & m8_8) ^ (Te1_r(t0 & m8) & m8) ^ rk[57]; - s2 = (Te2_r(t2 >> 24U) & m8_24) ^ (Te3_r((t3 >> 16U) & m8) & m8_16) ^ (Te0[(t0 >> 8U) & m8] & m8_8) ^ (Te1_r(t1 & m8) & m8) ^ rk[58]; - s3 = (Te2_r(t3 >> 24U) & m8_24) ^ (Te3_r((t0 >> 16U) & m8) & m8_16) ^ (Te0[(t1 >> 8U) & m8] & m8_8) ^ (Te1_r(t2 & m8) & m8) ^ rk[59]; + t0 = Te0[s0 >> 24U] ^ Te1_r((s1 >> 16U) & m8) ^ Te2_r((s2 >> 8U) & m8) ^ Te3_r(s3 & m8) ^ rk[4]; + t1 = Te0[s1 >> 24U] ^ Te1_r((s2 >> 16U) & m8) ^ Te2_r((s3 >> 8U) & m8) ^ Te3_r(s0 & m8) ^ rk[5]; + t2 = Te0[s2 >> 24U] ^ Te1_r((s3 >> 16U) & m8) ^ Te2_r((s0 >> 8U) & m8) ^ Te3_r(s1 & m8) ^ rk[6]; + t3 = Te0[s3 >> 24U] ^ Te1_r((s0 >> 16U) & m8) ^ Te2_r((s1 >> 8U) & m8) ^ Te3_r(s2 & m8) ^ rk[7]; + s0 = Te0[t0 >> 24U] ^ Te1_r((t1 >> 16U) & m8) ^ Te2_r((t2 >> 8U) & m8) ^ Te3_r(t3 & m8) ^ rk[8]; + s1 = Te0[t1 >> 24U] ^ Te1_r((t2 >> 16U) & m8) ^ Te2_r((t3 >> 8U) & m8) ^ Te3_r(t0 & m8) ^ rk[9]; + s2 = Te0[t2 >> 24U] ^ Te1_r((t3 >> 16U) & m8) ^ Te2_r((t0 >> 8U) & m8) ^ Te3_r(t1 & m8) ^ rk[10]; + s3 = Te0[t3 >> 24U] ^ Te1_r((t0 >> 16U) & m8) ^ Te2_r((t1 >> 8U) & m8) ^ Te3_r(t2 & m8) ^ rk[11]; + t0 = Te0[s0 >> 24U] ^ Te1_r((s1 >> 16U) & m8) ^ Te2_r((s2 >> 8U) & m8) ^ Te3_r(s3 & m8) ^ rk[12]; + t1 = Te0[s1 >> 24U] ^ Te1_r((s2 >> 16U) & m8) ^ Te2_r((s3 >> 8U) & m8) ^ Te3_r(s0 & m8) ^ rk[13]; + t2 = Te0[s2 >> 24U] ^ Te1_r((s3 >> 16U) & m8) ^ Te2_r((s0 >> 8U) & m8) ^ Te3_r(s1 & m8) ^ rk[14]; + t3 = Te0[s3 >> 24U] ^ Te1_r((s0 >> 16U) & m8) ^ Te2_r((s1 >> 8U) & m8) ^ Te3_r(s2 & m8) ^ rk[15]; + s0 = Te0[t0 >> 24U] ^ Te1_r((t1 >> 16U) & m8) ^ Te2_r((t2 >> 8U) & m8) ^ Te3_r(t3 & m8) ^ rk[16]; + s1 = Te0[t1 >> 24U] ^ Te1_r((t2 >> 16U) & m8) ^ Te2_r((t3 >> 8U) & m8) ^ Te3_r(t0 & m8) ^ rk[17]; + s2 = Te0[t2 >> 24U] ^ Te1_r((t3 >> 16U) & m8) ^ Te2_r((t0 >> 8U) & m8) ^ Te3_r(t1 & m8) ^ rk[18]; + s3 = Te0[t3 >> 24U] ^ Te1_r((t0 >> 16U) & m8) ^ Te2_r((t1 >> 8U) & m8) ^ Te3_r(t2 & m8) ^ rk[19]; + t0 = Te0[s0 >> 24U] ^ Te1_r((s1 >> 16U) & m8) ^ Te2_r((s2 >> 8U) & m8) ^ Te3_r(s3 & m8) ^ rk[20]; + t1 = Te0[s1 >> 24U] ^ Te1_r((s2 >> 16U) & m8) ^ Te2_r((s3 >> 8U) & m8) ^ Te3_r(s0 & m8) ^ rk[21]; + t2 = Te0[s2 >> 24U] ^ Te1_r((s3 >> 16U) & m8) ^ Te2_r((s0 >> 8U) & m8) ^ Te3_r(s1 & m8) ^ rk[22]; + t3 = Te0[s3 >> 24U] ^ Te1_r((s0 >> 16U) & m8) ^ Te2_r((s1 >> 8U) & m8) ^ Te3_r(s2 & m8) ^ rk[23]; + s0 = Te0[t0 >> 24U] ^ Te1_r((t1 >> 16U) & m8) ^ Te2_r((t2 >> 8U) & m8) ^ Te3_r(t3 & m8) ^ rk[24]; + s1 = Te0[t1 >> 24U] ^ Te1_r((t2 >> 16U) & m8) ^ Te2_r((t3 >> 8U) & m8) ^ Te3_r(t0 & m8) ^ rk[25]; + s2 = Te0[t2 >> 24U] ^ Te1_r((t3 >> 16U) & m8) ^ Te2_r((t0 >> 8U) & m8) ^ Te3_r(t1 & m8) ^ rk[26]; + s3 = Te0[t3 >> 24U] ^ Te1_r((t0 >> 16U) & m8) ^ Te2_r((t1 >> 8U) & m8) ^ Te3_r(t2 & m8) ^ rk[27]; + t0 = Te0[s0 >> 24U] ^ Te1_r((s1 >> 16U) & m8) ^ Te2_r((s2 >> 8U) & m8) ^ Te3_r(s3 & m8) ^ rk[28]; + t1 = Te0[s1 >> 24U] ^ Te1_r((s2 >> 16U) & m8) ^ Te2_r((s3 >> 8U) & m8) ^ Te3_r(s0 & m8) ^ rk[29]; + t2 = Te0[s2 >> 24U] ^ Te1_r((s3 >> 16U) & m8) ^ Te2_r((s0 >> 8U) & m8) ^ Te3_r(s1 & m8) ^ rk[30]; + t3 = Te0[s3 >> 24U] ^ Te1_r((s0 >> 16U) & m8) ^ Te2_r((s1 >> 8U) & m8) ^ Te3_r(s2 & m8) ^ rk[31]; + s0 = Te0[t0 >> 24U] ^ Te1_r((t1 >> 16U) & m8) ^ Te2_r((t2 >> 8U) & m8) ^ Te3_r(t3 & m8) ^ rk[32]; + s1 = Te0[t1 >> 24U] ^ Te1_r((t2 >> 16U) & m8) ^ Te2_r((t3 >> 8U) & m8) ^ Te3_r(t0 & m8) ^ rk[33]; + s2 = Te0[t2 >> 24U] ^ Te1_r((t3 >> 16U) & m8) ^ Te2_r((t0 >> 8U) & m8) ^ Te3_r(t1 & m8) ^ rk[34]; + s3 = Te0[t3 >> 24U] ^ Te1_r((t0 >> 16U) & m8) ^ Te2_r((t1 >> 8U) & m8) ^ Te3_r(t2 & m8) ^ rk[35]; + t0 = Te0[s0 >> 24U] ^ Te1_r((s1 >> 16U) & m8) ^ Te2_r((s2 >> 8U) & m8) ^ Te3_r(s3 & m8) ^ rk[36]; + t1 = Te0[s1 >> 24U] ^ Te1_r((s2 >> 16U) & m8) ^ Te2_r((s3 >> 8U) & m8) ^ Te3_r(s0 & m8) ^ rk[37]; + t2 = Te0[s2 >> 24U] ^ Te1_r((s3 >> 16U) & m8) ^ Te2_r((s0 >> 8U) & m8) ^ Te3_r(s1 & m8) ^ rk[38]; + t3 = Te0[s3 >> 24U] ^ Te1_r((s0 >> 16U) & m8) ^ Te2_r((s1 >> 8U) & m8) ^ Te3_r(s2 & m8) ^ rk[39]; + s0 = Te0[t0 >> 24U] ^ Te1_r((t1 >> 16U) & m8) ^ Te2_r((t2 >> 8U) & m8) ^ Te3_r(t3 & m8) ^ rk[40]; + s1 = Te0[t1 >> 24U] ^ Te1_r((t2 >> 16U) & m8) ^ Te2_r((t3 >> 8U) & m8) ^ Te3_r(t0 & m8) ^ rk[41]; + s2 = Te0[t2 >> 24U] ^ Te1_r((t3 >> 16U) & m8) ^ Te2_r((t0 >> 8U) & m8) ^ Te3_r(t1 & m8) ^ rk[42]; + s3 = Te0[t3 >> 24U] ^ Te1_r((t0 >> 16U) & m8) ^ Te2_r((t1 >> 8U) & m8) ^ Te3_r(t2 & m8) ^ rk[43]; + t0 = Te0[s0 >> 24U] ^ Te1_r((s1 >> 16U) & m8) ^ Te2_r((s2 >> 8U) & m8) ^ Te3_r(s3 & m8) ^ rk[44]; + t1 = Te0[s1 >> 24U] ^ Te1_r((s2 >> 16U) & m8) ^ Te2_r((s3 >> 8U) & m8) ^ Te3_r(s0 & m8) ^ rk[45]; + t2 = Te0[s2 >> 24U] ^ Te1_r((s3 >> 16U) & m8) ^ Te2_r((s0 >> 8U) & m8) ^ Te3_r(s1 & m8) ^ rk[46]; + t3 = Te0[s3 >> 24U] ^ Te1_r((s0 >> 16U) & m8) ^ Te2_r((s1 >> 8U) & m8) ^ Te3_r(s2 & m8) ^ rk[47]; + s0 = Te0[t0 >> 24U] ^ Te1_r((t1 >> 16U) & m8) ^ Te2_r((t2 >> 8U) & m8) ^ Te3_r(t3 & m8) ^ rk[48]; + s1 = Te0[t1 >> 24U] ^ Te1_r((t2 >> 16U) & m8) ^ Te2_r((t3 >> 8U) & m8) ^ Te3_r(t0 & m8) ^ rk[49]; + s2 = Te0[t2 >> 24U] ^ Te1_r((t3 >> 16U) & m8) ^ Te2_r((t0 >> 8U) & m8) ^ Te3_r(t1 & m8) ^ rk[50]; + s3 = Te0[t3 >> 24U] ^ Te1_r((t0 >> 16U) & m8) ^ Te2_r((t1 >> 8U) & m8) ^ Te3_r(t2 & m8) ^ rk[51]; + t0 = Te0[s0 >> 24U] ^ Te1_r((s1 >> 16U) & m8) ^ Te2_r((s2 >> 8U) & m8) ^ Te3_r(s3 & m8) ^ rk[52]; + t1 = Te0[s1 >> 24U] ^ Te1_r((s2 >> 16U) & m8) ^ Te2_r((s3 >> 8U) & m8) ^ Te3_r(s0 & m8) ^ rk[53]; + t2 = Te0[s2 >> 24U] ^ Te1_r((s3 >> 16U) & m8) ^ Te2_r((s0 >> 8U) & m8) ^ Te3_r(s1 & m8) ^ rk[54]; + t3 = Te0[s3 >> 24U] ^ Te1_r((s0 >> 16U) & m8) ^ Te2_r((s1 >> 8U) & m8) ^ Te3_r(s2 & m8) ^ rk[55]; + s0 = (Te2_r(t0 >> 24U) & m8_24) ^ (Te3_r((t1 >> 16U) & m8) & m8_16) ^ (Te0[(t2 >> 8U) & m8] & m8_8) ^ (Te1_r(t3 & m8) & m8) ^ rk[56]; + s1 = (Te2_r(t1 >> 24U) & m8_24) ^ (Te3_r((t2 >> 16U) & m8) & m8_16) ^ (Te0[(t3 >> 8U) & m8] & m8_8) ^ (Te1_r(t0 & m8) & m8) ^ rk[57]; + s2 = (Te2_r(t2 >> 24U) & m8_24) ^ (Te3_r((t3 >> 16U) & m8) & m8_16) ^ (Te0[(t0 >> 8U) & m8] & m8_8) ^ (Te1_r(t1 & m8) & m8) ^ rk[58]; + s3 = (Te2_r(t3 >> 24U) & m8_24) ^ (Te3_r((t0 >> 16U) & m8) & m8_16) ^ (Te0[(t1 >> 8U) & m8] & m8_8) ^ (Te1_r(t2 & m8) & m8) ^ rk[59]; - *reinterpret_cast(out) = in0 ^ Utils::hton(((uint64_t)s0 << 32U) | (uint64_t)s1); - *reinterpret_cast(out + 8) = in1 ^ Utils::hton(((uint64_t)s2 << 32U) | (uint64_t)s3); - out += 16; - } while ((len -= 16) >= 16); - } else { - do { - uint32_t s0, s1, s2, s3, t0, t1, t2, t3; - s0 = ctr0rk0; - s1 = ctr1rk1; - s2 = ctr2rk2; - s3 = ctr++ ^ rk[3]; + *reinterpret_cast(out) = in0 ^ Utils::hton(((uint64_t)s0 << 32U) | (uint64_t)s1); + *reinterpret_cast(out + 8) = in1 ^ Utils::hton(((uint64_t)s2 << 32U) | (uint64_t)s3); + out += 16; + } while ((len -= 16) >= 16); + } + else { + do { + uint32_t s0, s1, s2, s3, t0, t1, t2, t3; + s0 = ctr0rk0; + s1 = ctr1rk1; + s2 = ctr2rk2; + s3 = ctr++ ^ rk[3]; - t0 = Te0[s0 >> 24U] ^ Te1_r((s1 >> 16U) & m8) ^ Te2_r((s2 >> 8U) & m8) ^ Te3_r(s3 & m8) ^ rk[4]; - t1 = Te0[s1 >> 24U] ^ Te1_r((s2 >> 16U) & m8) ^ Te2_r((s3 >> 8U) & m8) ^ Te3_r(s0 & m8) ^ rk[5]; - t2 = Te0[s2 >> 24U] ^ Te1_r((s3 >> 16U) & m8) ^ Te2_r((s0 >> 8U) & m8) ^ Te3_r(s1 & m8) ^ rk[6]; - t3 = Te0[s3 >> 24U] ^ Te1_r((s0 >> 16U) & m8) ^ Te2_r((s1 >> 8U) & m8) ^ Te3_r(s2 & m8) ^ rk[7]; - s0 = Te0[t0 >> 24U] ^ Te1_r((t1 >> 16U) & m8) ^ Te2_r((t2 >> 8U) & m8) ^ Te3_r(t3 & m8) ^ rk[8]; - s1 = Te0[t1 >> 24U] ^ Te1_r((t2 >> 16U) & m8) ^ Te2_r((t3 >> 8U) & m8) ^ Te3_r(t0 & m8) ^ rk[9]; - s2 = Te0[t2 >> 24U] ^ Te1_r((t3 >> 16U) & m8) ^ Te2_r((t0 >> 8U) & m8) ^ Te3_r(t1 & m8) ^ rk[10]; - s3 = Te0[t3 >> 24U] ^ Te1_r((t0 >> 16U) & m8) ^ Te2_r((t1 >> 8U) & m8) ^ Te3_r(t2 & m8) ^ rk[11]; - t0 = Te0[s0 >> 24U] ^ Te1_r((s1 >> 16U) & m8) ^ Te2_r((s2 >> 8U) & m8) ^ Te3_r(s3 & m8) ^ rk[12]; - t1 = Te0[s1 >> 24U] ^ Te1_r((s2 >> 16U) & m8) ^ Te2_r((s3 >> 8U) & m8) ^ Te3_r(s0 & m8) ^ rk[13]; - t2 = Te0[s2 >> 24U] ^ Te1_r((s3 >> 16U) & m8) ^ Te2_r((s0 >> 8U) & m8) ^ Te3_r(s1 & m8) ^ rk[14]; - t3 = Te0[s3 >> 24U] ^ Te1_r((s0 >> 16U) & m8) ^ Te2_r((s1 >> 8U) & m8) ^ Te3_r(s2 & m8) ^ rk[15]; - s0 = Te0[t0 >> 24U] ^ Te1_r((t1 >> 16U) & m8) ^ Te2_r((t2 >> 8U) & m8) ^ Te3_r(t3 & m8) ^ rk[16]; - s1 = Te0[t1 >> 24U] ^ Te1_r((t2 >> 16U) & m8) ^ Te2_r((t3 >> 8U) & m8) ^ Te3_r(t0 & m8) ^ rk[17]; - s2 = Te0[t2 >> 24U] ^ Te1_r((t3 >> 16U) & m8) ^ Te2_r((t0 >> 8U) & m8) ^ Te3_r(t1 & m8) ^ rk[18]; - s3 = Te0[t3 >> 24U] ^ Te1_r((t0 >> 16U) & m8) ^ Te2_r((t1 >> 8U) & m8) ^ Te3_r(t2 & m8) ^ rk[19]; - t0 = Te0[s0 >> 24U] ^ Te1_r((s1 >> 16U) & m8) ^ Te2_r((s2 >> 8U) & m8) ^ Te3_r(s3 & m8) ^ rk[20]; - t1 = Te0[s1 >> 24U] ^ Te1_r((s2 >> 16U) & m8) ^ Te2_r((s3 >> 8U) & m8) ^ Te3_r(s0 & m8) ^ rk[21]; - t2 = Te0[s2 >> 24U] ^ Te1_r((s3 >> 16U) & m8) ^ Te2_r((s0 >> 8U) & m8) ^ Te3_r(s1 & m8) ^ rk[22]; - t3 = Te0[s3 >> 24U] ^ Te1_r((s0 >> 16U) & m8) ^ Te2_r((s1 >> 8U) & m8) ^ Te3_r(s2 & m8) ^ rk[23]; - s0 = Te0[t0 >> 24U] ^ Te1_r((t1 >> 16U) & m8) ^ Te2_r((t2 >> 8U) & m8) ^ Te3_r(t3 & m8) ^ rk[24]; - s1 = Te0[t1 >> 24U] ^ Te1_r((t2 >> 16U) & m8) ^ Te2_r((t3 >> 8U) & m8) ^ Te3_r(t0 & m8) ^ rk[25]; - s2 = Te0[t2 >> 24U] ^ Te1_r((t3 >> 16U) & m8) ^ Te2_r((t0 >> 8U) & m8) ^ Te3_r(t1 & m8) ^ rk[26]; - s3 = Te0[t3 >> 24U] ^ Te1_r((t0 >> 16U) & m8) ^ Te2_r((t1 >> 8U) & m8) ^ Te3_r(t2 & m8) ^ rk[27]; - t0 = Te0[s0 >> 24U] ^ Te1_r((s1 >> 16U) & m8) ^ Te2_r((s2 >> 8U) & m8) ^ Te3_r(s3 & m8) ^ rk[28]; - t1 = Te0[s1 >> 24U] ^ Te1_r((s2 >> 16U) & m8) ^ Te2_r((s3 >> 8U) & m8) ^ Te3_r(s0 & m8) ^ rk[29]; - t2 = Te0[s2 >> 24U] ^ Te1_r((s3 >> 16U) & m8) ^ Te2_r((s0 >> 8U) & m8) ^ Te3_r(s1 & m8) ^ rk[30]; - t3 = Te0[s3 >> 24U] ^ Te1_r((s0 >> 16U) & m8) ^ Te2_r((s1 >> 8U) & m8) ^ Te3_r(s2 & m8) ^ rk[31]; - s0 = Te0[t0 >> 24U] ^ Te1_r((t1 >> 16U) & m8) ^ Te2_r((t2 >> 8U) & m8) ^ Te3_r(t3 & m8) ^ rk[32]; - s1 = Te0[t1 >> 24U] ^ Te1_r((t2 >> 16U) & m8) ^ Te2_r((t3 >> 8U) & m8) ^ Te3_r(t0 & m8) ^ rk[33]; - s2 = Te0[t2 >> 24U] ^ Te1_r((t3 >> 16U) & m8) ^ Te2_r((t0 >> 8U) & m8) ^ Te3_r(t1 & m8) ^ rk[34]; - s3 = Te0[t3 >> 24U] ^ Te1_r((t0 >> 16U) & m8) ^ Te2_r((t1 >> 8U) & m8) ^ Te3_r(t2 & m8) ^ rk[35]; - t0 = Te0[s0 >> 24U] ^ Te1_r((s1 >> 16U) & m8) ^ Te2_r((s2 >> 8U) & m8) ^ Te3_r(s3 & m8) ^ rk[36]; - t1 = Te0[s1 >> 24U] ^ Te1_r((s2 >> 16U) & m8) ^ Te2_r((s3 >> 8U) & m8) ^ Te3_r(s0 & m8) ^ rk[37]; - t2 = Te0[s2 >> 24U] ^ Te1_r((s3 >> 16U) & m8) ^ Te2_r((s0 >> 8U) & m8) ^ Te3_r(s1 & m8) ^ rk[38]; - t3 = Te0[s3 >> 24U] ^ Te1_r((s0 >> 16U) & m8) ^ Te2_r((s1 >> 8U) & m8) ^ Te3_r(s2 & m8) ^ rk[39]; - s0 = Te0[t0 >> 24U] ^ Te1_r((t1 >> 16U) & m8) ^ Te2_r((t2 >> 8U) & m8) ^ Te3_r(t3 & m8) ^ rk[40]; - s1 = Te0[t1 >> 24U] ^ Te1_r((t2 >> 16U) & m8) ^ Te2_r((t3 >> 8U) & m8) ^ Te3_r(t0 & m8) ^ rk[41]; - s2 = Te0[t2 >> 24U] ^ Te1_r((t3 >> 16U) & m8) ^ Te2_r((t0 >> 8U) & m8) ^ Te3_r(t1 & m8) ^ rk[42]; - s3 = Te0[t3 >> 24U] ^ Te1_r((t0 >> 16U) & m8) ^ Te2_r((t1 >> 8U) & m8) ^ Te3_r(t2 & m8) ^ rk[43]; - t0 = Te0[s0 >> 24U] ^ Te1_r((s1 >> 16U) & m8) ^ Te2_r((s2 >> 8U) & m8) ^ Te3_r(s3 & m8) ^ rk[44]; - t1 = Te0[s1 >> 24U] ^ Te1_r((s2 >> 16U) & m8) ^ Te2_r((s3 >> 8U) & m8) ^ Te3_r(s0 & m8) ^ rk[45]; - t2 = Te0[s2 >> 24U] ^ Te1_r((s3 >> 16U) & m8) ^ Te2_r((s0 >> 8U) & m8) ^ Te3_r(s1 & m8) ^ rk[46]; - t3 = Te0[s3 >> 24U] ^ Te1_r((s0 >> 16U) & m8) ^ Te2_r((s1 >> 8U) & m8) ^ Te3_r(s2 & m8) ^ rk[47]; - s0 = Te0[t0 >> 24U] ^ Te1_r((t1 >> 16U) & m8) ^ Te2_r((t2 >> 8U) & m8) ^ Te3_r(t3 & m8) ^ rk[48]; - s1 = Te0[t1 >> 24U] ^ Te1_r((t2 >> 16U) & m8) ^ Te2_r((t3 >> 8U) & m8) ^ Te3_r(t0 & m8) ^ rk[49]; - s2 = Te0[t2 >> 24U] ^ Te1_r((t3 >> 16U) & m8) ^ Te2_r((t0 >> 8U) & m8) ^ Te3_r(t1 & m8) ^ rk[50]; - s3 = Te0[t3 >> 24U] ^ Te1_r((t0 >> 16U) & m8) ^ Te2_r((t1 >> 8U) & m8) ^ Te3_r(t2 & m8) ^ rk[51]; - t0 = Te0[s0 >> 24U] ^ Te1_r((s1 >> 16U) & m8) ^ Te2_r((s2 >> 8U) & m8) ^ Te3_r(s3 & m8) ^ rk[52]; - t1 = Te0[s1 >> 24U] ^ Te1_r((s2 >> 16U) & m8) ^ Te2_r((s3 >> 8U) & m8) ^ Te3_r(s0 & m8) ^ rk[53]; - t2 = Te0[s2 >> 24U] ^ Te1_r((s3 >> 16U) & m8) ^ Te2_r((s0 >> 8U) & m8) ^ Te3_r(s1 & m8) ^ rk[54]; - t3 = Te0[s3 >> 24U] ^ Te1_r((s0 >> 16U) & m8) ^ Te2_r((s1 >> 8U) & m8) ^ Te3_r(s2 & m8) ^ rk[55]; - s0 = (Te2_r(t0 >> 24U) & m8_24) ^ (Te3_r((t1 >> 16U) & m8) & m8_16) ^ (Te0[(t2 >> 8U) & m8] & m8_8) ^ (Te1_r(t3 & m8) & m8) ^ rk[56]; - s1 = (Te2_r(t1 >> 24U) & m8_24) ^ (Te3_r((t2 >> 16U) & m8) & m8_16) ^ (Te0[(t3 >> 8U) & m8] & m8_8) ^ (Te1_r(t0 & m8) & m8) ^ rk[57]; - s2 = (Te2_r(t2 >> 24U) & m8_24) ^ (Te3_r((t3 >> 16U) & m8) & m8_16) ^ (Te0[(t0 >> 8U) & m8] & m8_8) ^ (Te1_r(t1 & m8) & m8) ^ rk[58]; - s3 = (Te2_r(t3 >> 24U) & m8_24) ^ (Te3_r((t0 >> 16U) & m8) & m8_16) ^ (Te0[(t1 >> 8U) & m8] & m8_8) ^ (Te1_r(t2 & m8) & m8) ^ rk[59]; + t0 = Te0[s0 >> 24U] ^ Te1_r((s1 >> 16U) & m8) ^ Te2_r((s2 >> 8U) & m8) ^ Te3_r(s3 & m8) ^ rk[4]; + t1 = Te0[s1 >> 24U] ^ Te1_r((s2 >> 16U) & m8) ^ Te2_r((s3 >> 8U) & m8) ^ Te3_r(s0 & m8) ^ rk[5]; + t2 = Te0[s2 >> 24U] ^ Te1_r((s3 >> 16U) & m8) ^ Te2_r((s0 >> 8U) & m8) ^ Te3_r(s1 & m8) ^ rk[6]; + t3 = Te0[s3 >> 24U] ^ Te1_r((s0 >> 16U) & m8) ^ Te2_r((s1 >> 8U) & m8) ^ Te3_r(s2 & m8) ^ rk[7]; + s0 = Te0[t0 >> 24U] ^ Te1_r((t1 >> 16U) & m8) ^ Te2_r((t2 >> 8U) & m8) ^ Te3_r(t3 & m8) ^ rk[8]; + s1 = Te0[t1 >> 24U] ^ Te1_r((t2 >> 16U) & m8) ^ Te2_r((t3 >> 8U) & m8) ^ Te3_r(t0 & m8) ^ rk[9]; + s2 = Te0[t2 >> 24U] ^ Te1_r((t3 >> 16U) & m8) ^ Te2_r((t0 >> 8U) & m8) ^ Te3_r(t1 & m8) ^ rk[10]; + s3 = Te0[t3 >> 24U] ^ Te1_r((t0 >> 16U) & m8) ^ Te2_r((t1 >> 8U) & m8) ^ Te3_r(t2 & m8) ^ rk[11]; + t0 = Te0[s0 >> 24U] ^ Te1_r((s1 >> 16U) & m8) ^ Te2_r((s2 >> 8U) & m8) ^ Te3_r(s3 & m8) ^ rk[12]; + t1 = Te0[s1 >> 24U] ^ Te1_r((s2 >> 16U) & m8) ^ Te2_r((s3 >> 8U) & m8) ^ Te3_r(s0 & m8) ^ rk[13]; + t2 = Te0[s2 >> 24U] ^ Te1_r((s3 >> 16U) & m8) ^ Te2_r((s0 >> 8U) & m8) ^ Te3_r(s1 & m8) ^ rk[14]; + t3 = Te0[s3 >> 24U] ^ Te1_r((s0 >> 16U) & m8) ^ Te2_r((s1 >> 8U) & m8) ^ Te3_r(s2 & m8) ^ rk[15]; + s0 = Te0[t0 >> 24U] ^ Te1_r((t1 >> 16U) & m8) ^ Te2_r((t2 >> 8U) & m8) ^ Te3_r(t3 & m8) ^ rk[16]; + s1 = Te0[t1 >> 24U] ^ Te1_r((t2 >> 16U) & m8) ^ Te2_r((t3 >> 8U) & m8) ^ Te3_r(t0 & m8) ^ rk[17]; + s2 = Te0[t2 >> 24U] ^ Te1_r((t3 >> 16U) & m8) ^ Te2_r((t0 >> 8U) & m8) ^ Te3_r(t1 & m8) ^ rk[18]; + s3 = Te0[t3 >> 24U] ^ Te1_r((t0 >> 16U) & m8) ^ Te2_r((t1 >> 8U) & m8) ^ Te3_r(t2 & m8) ^ rk[19]; + t0 = Te0[s0 >> 24U] ^ Te1_r((s1 >> 16U) & m8) ^ Te2_r((s2 >> 8U) & m8) ^ Te3_r(s3 & m8) ^ rk[20]; + t1 = Te0[s1 >> 24U] ^ Te1_r((s2 >> 16U) & m8) ^ Te2_r((s3 >> 8U) & m8) ^ Te3_r(s0 & m8) ^ rk[21]; + t2 = Te0[s2 >> 24U] ^ Te1_r((s3 >> 16U) & m8) ^ Te2_r((s0 >> 8U) & m8) ^ Te3_r(s1 & m8) ^ rk[22]; + t3 = Te0[s3 >> 24U] ^ Te1_r((s0 >> 16U) & m8) ^ Te2_r((s1 >> 8U) & m8) ^ Te3_r(s2 & m8) ^ rk[23]; + s0 = Te0[t0 >> 24U] ^ Te1_r((t1 >> 16U) & m8) ^ Te2_r((t2 >> 8U) & m8) ^ Te3_r(t3 & m8) ^ rk[24]; + s1 = Te0[t1 >> 24U] ^ Te1_r((t2 >> 16U) & m8) ^ Te2_r((t3 >> 8U) & m8) ^ Te3_r(t0 & m8) ^ rk[25]; + s2 = Te0[t2 >> 24U] ^ Te1_r((t3 >> 16U) & m8) ^ Te2_r((t0 >> 8U) & m8) ^ Te3_r(t1 & m8) ^ rk[26]; + s3 = Te0[t3 >> 24U] ^ Te1_r((t0 >> 16U) & m8) ^ Te2_r((t1 >> 8U) & m8) ^ Te3_r(t2 & m8) ^ rk[27]; + t0 = Te0[s0 >> 24U] ^ Te1_r((s1 >> 16U) & m8) ^ Te2_r((s2 >> 8U) & m8) ^ Te3_r(s3 & m8) ^ rk[28]; + t1 = Te0[s1 >> 24U] ^ Te1_r((s2 >> 16U) & m8) ^ Te2_r((s3 >> 8U) & m8) ^ Te3_r(s0 & m8) ^ rk[29]; + t2 = Te0[s2 >> 24U] ^ Te1_r((s3 >> 16U) & m8) ^ Te2_r((s0 >> 8U) & m8) ^ Te3_r(s1 & m8) ^ rk[30]; + t3 = Te0[s3 >> 24U] ^ Te1_r((s0 >> 16U) & m8) ^ Te2_r((s1 >> 8U) & m8) ^ Te3_r(s2 & m8) ^ rk[31]; + s0 = Te0[t0 >> 24U] ^ Te1_r((t1 >> 16U) & m8) ^ Te2_r((t2 >> 8U) & m8) ^ Te3_r(t3 & m8) ^ rk[32]; + s1 = Te0[t1 >> 24U] ^ Te1_r((t2 >> 16U) & m8) ^ Te2_r((t3 >> 8U) & m8) ^ Te3_r(t0 & m8) ^ rk[33]; + s2 = Te0[t2 >> 24U] ^ Te1_r((t3 >> 16U) & m8) ^ Te2_r((t0 >> 8U) & m8) ^ Te3_r(t1 & m8) ^ rk[34]; + s3 = Te0[t3 >> 24U] ^ Te1_r((t0 >> 16U) & m8) ^ Te2_r((t1 >> 8U) & m8) ^ Te3_r(t2 & m8) ^ rk[35]; + t0 = Te0[s0 >> 24U] ^ Te1_r((s1 >> 16U) & m8) ^ Te2_r((s2 >> 8U) & m8) ^ Te3_r(s3 & m8) ^ rk[36]; + t1 = Te0[s1 >> 24U] ^ Te1_r((s2 >> 16U) & m8) ^ Te2_r((s3 >> 8U) & m8) ^ Te3_r(s0 & m8) ^ rk[37]; + t2 = Te0[s2 >> 24U] ^ Te1_r((s3 >> 16U) & m8) ^ Te2_r((s0 >> 8U) & m8) ^ Te3_r(s1 & m8) ^ rk[38]; + t3 = Te0[s3 >> 24U] ^ Te1_r((s0 >> 16U) & m8) ^ Te2_r((s1 >> 8U) & m8) ^ Te3_r(s2 & m8) ^ rk[39]; + s0 = Te0[t0 >> 24U] ^ Te1_r((t1 >> 16U) & m8) ^ Te2_r((t2 >> 8U) & m8) ^ Te3_r(t3 & m8) ^ rk[40]; + s1 = Te0[t1 >> 24U] ^ Te1_r((t2 >> 16U) & m8) ^ Te2_r((t3 >> 8U) & m8) ^ Te3_r(t0 & m8) ^ rk[41]; + s2 = Te0[t2 >> 24U] ^ Te1_r((t3 >> 16U) & m8) ^ Te2_r((t0 >> 8U) & m8) ^ Te3_r(t1 & m8) ^ rk[42]; + s3 = Te0[t3 >> 24U] ^ Te1_r((t0 >> 16U) & m8) ^ Te2_r((t1 >> 8U) & m8) ^ Te3_r(t2 & m8) ^ rk[43]; + t0 = Te0[s0 >> 24U] ^ Te1_r((s1 >> 16U) & m8) ^ Te2_r((s2 >> 8U) & m8) ^ Te3_r(s3 & m8) ^ rk[44]; + t1 = Te0[s1 >> 24U] ^ Te1_r((s2 >> 16U) & m8) ^ Te2_r((s3 >> 8U) & m8) ^ Te3_r(s0 & m8) ^ rk[45]; + t2 = Te0[s2 >> 24U] ^ Te1_r((s3 >> 16U) & m8) ^ Te2_r((s0 >> 8U) & m8) ^ Te3_r(s1 & m8) ^ rk[46]; + t3 = Te0[s3 >> 24U] ^ Te1_r((s0 >> 16U) & m8) ^ Te2_r((s1 >> 8U) & m8) ^ Te3_r(s2 & m8) ^ rk[47]; + s0 = Te0[t0 >> 24U] ^ Te1_r((t1 >> 16U) & m8) ^ Te2_r((t2 >> 8U) & m8) ^ Te3_r(t3 & m8) ^ rk[48]; + s1 = Te0[t1 >> 24U] ^ Te1_r((t2 >> 16U) & m8) ^ Te2_r((t3 >> 8U) & m8) ^ Te3_r(t0 & m8) ^ rk[49]; + s2 = Te0[t2 >> 24U] ^ Te1_r((t3 >> 16U) & m8) ^ Te2_r((t0 >> 8U) & m8) ^ Te3_r(t1 & m8) ^ rk[50]; + s3 = Te0[t3 >> 24U] ^ Te1_r((t0 >> 16U) & m8) ^ Te2_r((t1 >> 8U) & m8) ^ Te3_r(t2 & m8) ^ rk[51]; + t0 = Te0[s0 >> 24U] ^ Te1_r((s1 >> 16U) & m8) ^ Te2_r((s2 >> 8U) & m8) ^ Te3_r(s3 & m8) ^ rk[52]; + t1 = Te0[s1 >> 24U] ^ Te1_r((s2 >> 16U) & m8) ^ Te2_r((s3 >> 8U) & m8) ^ Te3_r(s0 & m8) ^ rk[53]; + t2 = Te0[s2 >> 24U] ^ Te1_r((s3 >> 16U) & m8) ^ Te2_r((s0 >> 8U) & m8) ^ Te3_r(s1 & m8) ^ rk[54]; + t3 = Te0[s3 >> 24U] ^ Te1_r((s0 >> 16U) & m8) ^ Te2_r((s1 >> 8U) & m8) ^ Te3_r(s2 & m8) ^ rk[55]; + s0 = (Te2_r(t0 >> 24U) & m8_24) ^ (Te3_r((t1 >> 16U) & m8) & m8_16) ^ (Te0[(t2 >> 8U) & m8] & m8_8) ^ (Te1_r(t3 & m8) & m8) ^ rk[56]; + s1 = (Te2_r(t1 >> 24U) & m8_24) ^ (Te3_r((t2 >> 16U) & m8) & m8_16) ^ (Te0[(t3 >> 8U) & m8] & m8_8) ^ (Te1_r(t0 & m8) & m8) ^ rk[57]; + s2 = (Te2_r(t2 >> 24U) & m8_24) ^ (Te3_r((t3 >> 16U) & m8) & m8_16) ^ (Te0[(t0 >> 8U) & m8] & m8_8) ^ (Te1_r(t1 & m8) & m8) ^ rk[58]; + s3 = (Te2_r(t3 >> 24U) & m8_24) ^ (Te3_r((t0 >> 16U) & m8) & m8_16) ^ (Te0[(t1 >> 8U) & m8] & m8_8) ^ (Te1_r(t2 & m8) & m8) ^ rk[59]; - out[0] = in[0] ^ (uint8_t)(s0 >> 24U); - out[1] = in[1] ^ (uint8_t)(s0 >> 16U); - out[2] = in[2] ^ (uint8_t)(s0 >> 8U); - out[3] = in[3] ^ (uint8_t)s0; - out[4] = in[4] ^ (uint8_t)(s1 >> 24U); - out[5] = in[5] ^ (uint8_t)(s1 >> 16U); - out[6] = in[6] ^ (uint8_t)(s1 >> 8U); - out[7] = in[7] ^ (uint8_t)s1; - out[8] = in[8] ^ (uint8_t)(s2 >> 24U); - out[9] = in[9] ^ (uint8_t)(s2 >> 16U); - out[10] = in[10] ^ (uint8_t)(s2 >> 8U); - out[11] = in[11] ^ (uint8_t)s2; - out[12] = in[12] ^ (uint8_t)(s3 >> 24U); - out[13] = in[13] ^ (uint8_t)(s3 >> 16U); - out[14] = in[14] ^ (uint8_t)(s3 >> 8U); - out[15] = in[15] ^ (uint8_t)s3; - out += 16; - in += 16; - } while ((len -= 16) >= 16); - } - reinterpret_cast(_ctr)[3] = Utils::hton(ctr); - } + out[0] = in[0] ^ (uint8_t)(s0 >> 24U); + out[1] = in[1] ^ (uint8_t)(s0 >> 16U); + out[2] = in[2] ^ (uint8_t)(s0 >> 8U); + out[3] = in[3] ^ (uint8_t)s0; + out[4] = in[4] ^ (uint8_t)(s1 >> 24U); + out[5] = in[5] ^ (uint8_t)(s1 >> 16U); + out[6] = in[6] ^ (uint8_t)(s1 >> 8U); + out[7] = in[7] ^ (uint8_t)s1; + out[8] = in[8] ^ (uint8_t)(s2 >> 24U); + out[9] = in[9] ^ (uint8_t)(s2 >> 16U); + out[10] = in[10] ^ (uint8_t)(s2 >> 8U); + out[11] = in[11] ^ (uint8_t)s2; + out[12] = in[12] ^ (uint8_t)(s3 >> 24U); + out[13] = in[13] ^ (uint8_t)(s3 >> 16U); + out[14] = in[14] ^ (uint8_t)(s3 >> 8U); + out[15] = in[15] ^ (uint8_t)s3; + out += 16; + in += 16; + } while ((len -= 16) >= 16); + } + reinterpret_cast(_ctr)[3] = Utils::hton(ctr); + } - // Any remaining input is placed in _out. This will be picked up and crypted - // on subsequent calls to crypt() or finish() as it'll mean _len will not be - // an even multiple of 16. - while (len) { - --len; - *(out++) = *(in++); - } + // Any remaining input is placed in _out. This will be picked up and crypted + // on subsequent calls to crypt() or finish() as it'll mean _len will not be + // an even multiple of 16. + while (len) { + --len; + *(out++) = *(in++); + } } void AES::CTR::finish() noexcept { - uint8_t tmp[16]; - const unsigned int rem = _len & 15U; - if (rem) { - _aes.encrypt(_ctr, tmp); - for (unsigned int i = 0, j = _len - rem; i < rem; ++i) { - _out[j + i] ^= tmp[i]; - } - } + uint8_t tmp[16]; + const unsigned int rem = _len & 15U; + if (rem) { + _aes.encrypt(_ctr, tmp); + for (unsigned int i = 0, j = _len - rem; i < rem; ++i) { + _out[j + i] ^= tmp[i]; + } + } } // Software AES and AES key expansion --------------------------------------------------------------------------------- -const uint32_t AES::Te0[256] = {0xc66363a5, 0xf87c7c84, 0xee777799, 0xf67b7b8d, 0xfff2f20d, 0xd66b6bbd, 0xde6f6fb1, 0x91c5c554, 0x60303050, 0x02010103, 0xce6767a9, 0x562b2b7d, 0xe7fefe19, 0xb5d7d762, 0x4dababe6, 0xec76769a, 0x8fcaca45, 0x1f82829d, 0x89c9c940, 0xfa7d7d87, 0xeffafa15, 0xb25959eb, 0x8e4747c9, 0xfbf0f00b, 0x41adadec, 0xb3d4d467, 0x5fa2a2fd, 0x45afafea, 0x239c9cbf, 0x53a4a4f7, 0xe4727296, 0x9bc0c05b, 0x75b7b7c2, 0xe1fdfd1c, 0x3d9393ae, 0x4c26266a, 0x6c36365a, 0x7e3f3f41, 0xf5f7f702, 0x83cccc4f, 0x6834345c, 0x51a5a5f4, 0xd1e5e534, 0xf9f1f108, 0xe2717193, 0xabd8d873, 0x62313153, - 0x2a15153f, 0x0804040c, 0x95c7c752, 0x46232365, 0x9dc3c35e, 0x30181828, 0x379696a1, 0x0a05050f, 0x2f9a9ab5, 0x0e070709, 0x24121236, 0x1b80809b, 0xdfe2e23d, 0xcdebeb26, 0x4e272769, 0x7fb2b2cd, 0xea75759f, - 0x1209091b, 0x1d83839e, 0x582c2c74, 0x341a1a2e, 0x361b1b2d, 0xdc6e6eb2, 0xb45a5aee, 0x5ba0a0fb, 0xa45252f6, 0x763b3b4d, 0xb7d6d661, 0x7db3b3ce, 0x5229297b, 0xdde3e33e, 0x5e2f2f71, 0x13848497, 0xa65353f5, 0xb9d1d168, 0x00000000, 0xc1eded2c, 0x40202060, 0xe3fcfc1f, 0x79b1b1c8, 0xb65b5bed, 0xd46a6abe, 0x8dcbcb46, 0x67bebed9, 0x7239394b, 0x944a4ade, 0x984c4cd4, 0xb05858e8, 0x85cfcf4a, 0xbbd0d06b, 0xc5efef2a, 0x4faaaae5, 0xedfbfb16, 0x864343c5, 0x9a4d4dd7, 0x66333355, 0x11858594, 0x8a4545cf, 0xe9f9f910, 0x04020206, 0xfe7f7f81, 0xa05050f0, 0x783c3c44, 0x259f9fba, - 0x4ba8a8e3, 0xa25151f3, 0x5da3a3fe, 0x804040c0, 0x058f8f8a, 0x3f9292ad, 0x219d9dbc, 0x70383848, 0xf1f5f504, 0x63bcbcdf, 0x77b6b6c1, 0xafdada75, 0x42212163, 0x20101030, 0xe5ffff1a, 0xfdf3f30e, 0xbfd2d26d, - 0x81cdcd4c, 0x180c0c14, 0x26131335, 0xc3ecec2f, 0xbe5f5fe1, 0x359797a2, 0x884444cc, 0x2e171739, 0x93c4c457, 0x55a7a7f2, 0xfc7e7e82, 0x7a3d3d47, 0xc86464ac, 0xba5d5de7, 0x3219192b, 0xe6737395, 0xc06060a0, 0x19818198, 0x9e4f4fd1, 0xa3dcdc7f, 0x44222266, 0x542a2a7e, 0x3b9090ab, 0x0b888883, 0x8c4646ca, 0xc7eeee29, 0x6bb8b8d3, 0x2814143c, 0xa7dede79, 0xbc5e5ee2, 0x160b0b1d, 0xaddbdb76, 0xdbe0e03b, 0x64323256, 0x743a3a4e, 0x140a0a1e, 0x924949db, 0x0c06060a, 0x4824246c, 0xb85c5ce4, 0x9fc2c25d, 0xbdd3d36e, 0x43acacef, 0xc46262a6, 0x399191a8, 0x319595a4, 0xd3e4e437, - 0xf279798b, 0xd5e7e732, 0x8bc8c843, 0x6e373759, 0xda6d6db7, 0x018d8d8c, 0xb1d5d564, 0x9c4e4ed2, 0x49a9a9e0, 0xd86c6cb4, 0xac5656fa, 0xf3f4f407, 0xcfeaea25, 0xca6565af, 0xf47a7a8e, 0x47aeaee9, 0x10080818, - 0x6fbabad5, 0xf0787888, 0x4a25256f, 0x5c2e2e72, 0x381c1c24, 0x57a6a6f1, 0x73b4b4c7, 0x97c6c651, 0xcbe8e823, 0xa1dddd7c, 0xe874749c, 0x3e1f1f21, 0x964b4bdd, 0x61bdbddc, 0x0d8b8b86, 0x0f8a8a85, 0xe0707090, 0x7c3e3e42, 0x71b5b5c4, 0xcc6666aa, 0x904848d8, 0x06030305, 0xf7f6f601, 0x1c0e0e12, 0xc26161a3, 0x6a35355f, 0xae5757f9, 0x69b9b9d0, 0x17868691, 0x99c1c158, 0x3a1d1d27, 0x279e9eb9, 0xd9e1e138, 0xebf8f813, 0x2b9898b3, 0x22111133, 0xd26969bb, 0xa9d9d970, 0x078e8e89, 0x339494a7, 0x2d9b9bb6, 0x3c1e1e22, 0x15878792, 0xc9e9e920, 0x87cece49, 0xaa5555ff, 0x50282878, - 0xa5dfdf7a, 0x038c8c8f, 0x59a1a1f8, 0x09898980, 0x1a0d0d17, 0x65bfbfda, 0xd7e6e631, 0x844242c6, 0xd06868b8, 0x824141c3, 0x299999b0, 0x5a2d2d77, 0x1e0f0f11, 0x7bb0b0cb, 0xa85454fc, 0x6dbbbbd6, 0x2c16163a}; -const uint32_t AES::Te4[256] = {0x63636363, 0x7c7c7c7c, 0x77777777, 0x7b7b7b7b, 0xf2f2f2f2, 0x6b6b6b6b, 0x6f6f6f6f, 0xc5c5c5c5, 0x30303030, 0x01010101, 0x67676767, 0x2b2b2b2b, 0xfefefefe, 0xd7d7d7d7, 0xabababab, 0x76767676, 0xcacacaca, 0x82828282, 0xc9c9c9c9, 0x7d7d7d7d, 0xfafafafa, 0x59595959, 0x47474747, 0xf0f0f0f0, 0xadadadad, 0xd4d4d4d4, 0xa2a2a2a2, 0xafafafaf, 0x9c9c9c9c, 0xa4a4a4a4, 0x72727272, 0xc0c0c0c0, 0xb7b7b7b7, 0xfdfdfdfd, 0x93939393, 0x26262626, 0x36363636, 0x3f3f3f3f, 0xf7f7f7f7, 0xcccccccc, 0x34343434, 0xa5a5a5a5, 0xe5e5e5e5, 0xf1f1f1f1, 0x71717171, 0xd8d8d8d8, 0x31313131, - 0x15151515, 0x04040404, 0xc7c7c7c7, 0x23232323, 0xc3c3c3c3, 0x18181818, 0x96969696, 0x05050505, 0x9a9a9a9a, 0x07070707, 0x12121212, 0x80808080, 0xe2e2e2e2, 0xebebebeb, 0x27272727, 0xb2b2b2b2, 0x75757575, - 0x09090909, 0x83838383, 0x2c2c2c2c, 0x1a1a1a1a, 0x1b1b1b1b, 0x6e6e6e6e, 0x5a5a5a5a, 0xa0a0a0a0, 0x52525252, 0x3b3b3b3b, 0xd6d6d6d6, 0xb3b3b3b3, 0x29292929, 0xe3e3e3e3, 0x2f2f2f2f, 0x84848484, 0x53535353, 0xd1d1d1d1, 0x00000000, 0xedededed, 0x20202020, 0xfcfcfcfc, 0xb1b1b1b1, 0x5b5b5b5b, 0x6a6a6a6a, 0xcbcbcbcb, 0xbebebebe, 0x39393939, 0x4a4a4a4a, 0x4c4c4c4c, 0x58585858, 0xcfcfcfcf, 0xd0d0d0d0, 0xefefefef, 0xaaaaaaaa, 0xfbfbfbfb, 0x43434343, 0x4d4d4d4d, 0x33333333, 0x85858585, 0x45454545, 0xf9f9f9f9, 0x02020202, 0x7f7f7f7f, 0x50505050, 0x3c3c3c3c, 0x9f9f9f9f, - 0xa8a8a8a8, 0x51515151, 0xa3a3a3a3, 0x40404040, 0x8f8f8f8f, 0x92929292, 0x9d9d9d9d, 0x38383838, 0xf5f5f5f5, 0xbcbcbcbc, 0xb6b6b6b6, 0xdadadada, 0x21212121, 0x10101010, 0xffffffff, 0xf3f3f3f3, 0xd2d2d2d2, - 0xcdcdcdcd, 0x0c0c0c0c, 0x13131313, 0xecececec, 0x5f5f5f5f, 0x97979797, 0x44444444, 0x17171717, 0xc4c4c4c4, 0xa7a7a7a7, 0x7e7e7e7e, 0x3d3d3d3d, 0x64646464, 0x5d5d5d5d, 0x19191919, 0x73737373, 0x60606060, 0x81818181, 0x4f4f4f4f, 0xdcdcdcdc, 0x22222222, 0x2a2a2a2a, 0x90909090, 0x88888888, 0x46464646, 0xeeeeeeee, 0xb8b8b8b8, 0x14141414, 0xdededede, 0x5e5e5e5e, 0x0b0b0b0b, 0xdbdbdbdb, 0xe0e0e0e0, 0x32323232, 0x3a3a3a3a, 0x0a0a0a0a, 0x49494949, 0x06060606, 0x24242424, 0x5c5c5c5c, 0xc2c2c2c2, 0xd3d3d3d3, 0xacacacac, 0x62626262, 0x91919191, 0x95959595, 0xe4e4e4e4, - 0x79797979, 0xe7e7e7e7, 0xc8c8c8c8, 0x37373737, 0x6d6d6d6d, 0x8d8d8d8d, 0xd5d5d5d5, 0x4e4e4e4e, 0xa9a9a9a9, 0x6c6c6c6c, 0x56565656, 0xf4f4f4f4, 0xeaeaeaea, 0x65656565, 0x7a7a7a7a, 0xaeaeaeae, 0x08080808, - 0xbabababa, 0x78787878, 0x25252525, 0x2e2e2e2e, 0x1c1c1c1c, 0xa6a6a6a6, 0xb4b4b4b4, 0xc6c6c6c6, 0xe8e8e8e8, 0xdddddddd, 0x74747474, 0x1f1f1f1f, 0x4b4b4b4b, 0xbdbdbdbd, 0x8b8b8b8b, 0x8a8a8a8a, 0x70707070, 0x3e3e3e3e, 0xb5b5b5b5, 0x66666666, 0x48484848, 0x03030303, 0xf6f6f6f6, 0x0e0e0e0e, 0x61616161, 0x35353535, 0x57575757, 0xb9b9b9b9, 0x86868686, 0xc1c1c1c1, 0x1d1d1d1d, 0x9e9e9e9e, 0xe1e1e1e1, 0xf8f8f8f8, 0x98989898, 0x11111111, 0x69696969, 0xd9d9d9d9, 0x8e8e8e8e, 0x94949494, 0x9b9b9b9b, 0x1e1e1e1e, 0x87878787, 0xe9e9e9e9, 0xcececece, 0x55555555, 0x28282828, - 0xdfdfdfdf, 0x8c8c8c8c, 0xa1a1a1a1, 0x89898989, 0x0d0d0d0d, 0xbfbfbfbf, 0xe6e6e6e6, 0x42424242, 0x68686868, 0x41414141, 0x99999999, 0x2d2d2d2d, 0x0f0f0f0f, 0xb0b0b0b0, 0x54545454, 0xbbbbbbbb, 0x16161616}; -const uint32_t AES::Td0[256] = {0x51f4a750, 0x7e416553, 0x1a17a4c3, 0x3a275e96, 0x3bab6bcb, 0x1f9d45f1, 0xacfa58ab, 0x4be30393, 0x2030fa55, 0xad766df6, 0x88cc7691, 0xf5024c25, 0x4fe5d7fc, 0xc52acbd7, 0x26354480, 0xb562a38f, 0xdeb15a49, 0x25ba1b67, 0x45ea0e98, 0x5dfec0e1, 0xc32f7502, 0x814cf012, 0x8d4697a3, 0x6bd3f9c6, 0x038f5fe7, 0x15929c95, 0xbf6d7aeb, 0x955259da, 0xd4be832d, 0x587421d3, 0x49e06929, 0x8ec9c844, 0x75c2896a, 0xf48e7978, 0x99583e6b, 0x27b971dd, 0xbee14fb6, 0xf088ad17, 0xc920ac66, 0x7dce3ab4, 0x63df4a18, 0xe51a3182, 0x97513360, 0x62537f45, 0xb16477e0, 0xbb6bae84, 0xfe81a01c, - 0xf9082b94, 0x70486858, 0x8f45fd19, 0x94de6c87, 0x527bf8b7, 0xab73d323, 0x724b02e2, 0xe31f8f57, 0x6655ab2a, 0xb2eb2807, 0x2fb5c203, 0x86c57b9a, 0xd33708a5, 0x302887f2, 0x23bfa5b2, 0x02036aba, 0xed16825c, - 0x8acf1c2b, 0xa779b492, 0xf307f2f0, 0x4e69e2a1, 0x65daf4cd, 0x0605bed5, 0xd134621f, 0xc4a6fe8a, 0x342e539d, 0xa2f355a0, 0x058ae132, 0xa4f6eb75, 0x0b83ec39, 0x4060efaa, 0x5e719f06, 0xbd6e1051, 0x3e218af9, 0x96dd063d, 0xdd3e05ae, 0x4de6bd46, 0x91548db5, 0x71c45d05, 0x0406d46f, 0x605015ff, 0x1998fb24, 0xd6bde997, 0x894043cc, 0x67d99e77, 0xb0e842bd, 0x07898b88, 0xe7195b38, 0x79c8eedb, 0xa17c0a47, 0x7c420fe9, 0xf8841ec9, 0x00000000, 0x09808683, 0x322bed48, 0x1e1170ac, 0x6c5a724e, 0xfd0efffb, 0x0f853856, 0x3daed51e, 0x362d3927, 0x0a0fd964, 0x685ca621, 0x9b5b54d1, - 0x24362e3a, 0x0c0a67b1, 0x9357e70f, 0xb4ee96d2, 0x1b9b919e, 0x80c0c54f, 0x61dc20a2, 0x5a774b69, 0x1c121a16, 0xe293ba0a, 0xc0a02ae5, 0x3c22e043, 0x121b171d, 0x0e090d0b, 0xf28bc7ad, 0x2db6a8b9, 0x141ea9c8, - 0x57f11985, 0xaf75074c, 0xee99ddbb, 0xa37f60fd, 0xf701269f, 0x5c72f5bc, 0x44663bc5, 0x5bfb7e34, 0x8b432976, 0xcb23c6dc, 0xb6edfc68, 0xb8e4f163, 0xd731dcca, 0x42638510, 0x13972240, 0x84c61120, 0x854a247d, 0xd2bb3df8, 0xaef93211, 0xc729a16d, 0x1d9e2f4b, 0xdcb230f3, 0x0d8652ec, 0x77c1e3d0, 0x2bb3166c, 0xa970b999, 0x119448fa, 0x47e96422, 0xa8fc8cc4, 0xa0f03f1a, 0x567d2cd8, 0x223390ef, 0x87494ec7, 0xd938d1c1, 0x8ccaa2fe, 0x98d40b36, 0xa6f581cf, 0xa57ade28, 0xdab78e26, 0x3fadbfa4, 0x2c3a9de4, 0x5078920d, 0x6a5fcc9b, 0x547e4662, 0xf68d13c2, 0x90d8b8e8, 0x2e39f75e, - 0x82c3aff5, 0x9f5d80be, 0x69d0937c, 0x6fd52da9, 0xcf2512b3, 0xc8ac993b, 0x10187da7, 0xe89c636e, 0xdb3bbb7b, 0xcd267809, 0x6e5918f4, 0xec9ab701, 0x834f9aa8, 0xe6956e65, 0xaaffe67e, 0x21bccf08, 0xef15e8e6, - 0xbae79bd9, 0x4a6f36ce, 0xea9f09d4, 0x29b07cd6, 0x31a4b2af, 0x2a3f2331, 0xc6a59430, 0x35a266c0, 0x744ebc37, 0xfc82caa6, 0xe090d0b0, 0x33a7d815, 0xf104984a, 0x41ecdaf7, 0x7fcd500e, 0x1791f62f, 0x764dd68d, 0x43efb04d, 0xccaa4d54, 0xe49604df, 0x9ed1b5e3, 0x4c6a881b, 0xc12c1fb8, 0x4665517f, 0x9d5eea04, 0x018c355d, 0xfa877473, 0xfb0b412e, 0xb3671d5a, 0x92dbd252, 0xe9105633, 0x6dd64713, 0x9ad7618c, 0x37a10c7a, 0x59f8148e, 0xeb133c89, 0xcea927ee, 0xb761c935, 0xe11ce5ed, 0x7a47b13c, 0x9cd2df59, 0x55f2733f, 0x1814ce79, 0x73c737bf, 0x53f7cdea, 0x5ffdaa5b, 0xdf3d6f14, - 0x7844db86, 0xcaaff381, 0xb968c43e, 0x3824342c, 0xc2a3405f, 0x161dc372, 0xbce2250c, 0x283c498b, 0xff0d9541, 0x39a80171, 0x080cb3de, 0xd8b4e49c, 0x6456c190, 0x7bcb8461, 0xd532b670, 0x486c5c74, 0xd0b85742}; -const uint8_t AES::Td4[256] = {0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb, 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb, 0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e, 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25, 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92, 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, - 0x84, 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06, 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b, - 0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73, 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e, 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b, 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4, 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f, 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, - 0xef, 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61, 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d}; -const uint32_t AES::rcon[15] = {0x01000000, 0x02000000, 0x04000000, 0x08000000, 0x10000000, 0x20000000, 0x40000000, 0x80000000, 0x1B000000, 0x36000000, 0x6c000000, 0xd8000000, 0xab000000, 0x4d000000, 0x9a000000}; +const uint32_t AES::Te0[256] = { 0xc66363a5, 0xf87c7c84, 0xee777799, 0xf67b7b8d, 0xfff2f20d, 0xd66b6bbd, 0xde6f6fb1, 0x91c5c554, 0x60303050, 0x02010103, 0xce6767a9, 0x562b2b7d, 0xe7fefe19, 0xb5d7d762, 0x4dababe6, 0xec76769a, + 0x8fcaca45, 0x1f82829d, 0x89c9c940, 0xfa7d7d87, 0xeffafa15, 0xb25959eb, 0x8e4747c9, 0xfbf0f00b, 0x41adadec, 0xb3d4d467, 0x5fa2a2fd, 0x45afafea, 0x239c9cbf, 0x53a4a4f7, 0xe4727296, 0x9bc0c05b, + 0x75b7b7c2, 0xe1fdfd1c, 0x3d9393ae, 0x4c26266a, 0x6c36365a, 0x7e3f3f41, 0xf5f7f702, 0x83cccc4f, 0x6834345c, 0x51a5a5f4, 0xd1e5e534, 0xf9f1f108, 0xe2717193, 0xabd8d873, 0x62313153, 0x2a15153f, + 0x0804040c, 0x95c7c752, 0x46232365, 0x9dc3c35e, 0x30181828, 0x379696a1, 0x0a05050f, 0x2f9a9ab5, 0x0e070709, 0x24121236, 0x1b80809b, 0xdfe2e23d, 0xcdebeb26, 0x4e272769, 0x7fb2b2cd, 0xea75759f, + 0x1209091b, 0x1d83839e, 0x582c2c74, 0x341a1a2e, 0x361b1b2d, 0xdc6e6eb2, 0xb45a5aee, 0x5ba0a0fb, 0xa45252f6, 0x763b3b4d, 0xb7d6d661, 0x7db3b3ce, 0x5229297b, 0xdde3e33e, 0x5e2f2f71, 0x13848497, + 0xa65353f5, 0xb9d1d168, 0x00000000, 0xc1eded2c, 0x40202060, 0xe3fcfc1f, 0x79b1b1c8, 0xb65b5bed, 0xd46a6abe, 0x8dcbcb46, 0x67bebed9, 0x7239394b, 0x944a4ade, 0x984c4cd4, 0xb05858e8, 0x85cfcf4a, + 0xbbd0d06b, 0xc5efef2a, 0x4faaaae5, 0xedfbfb16, 0x864343c5, 0x9a4d4dd7, 0x66333355, 0x11858594, 0x8a4545cf, 0xe9f9f910, 0x04020206, 0xfe7f7f81, 0xa05050f0, 0x783c3c44, 0x259f9fba, 0x4ba8a8e3, + 0xa25151f3, 0x5da3a3fe, 0x804040c0, 0x058f8f8a, 0x3f9292ad, 0x219d9dbc, 0x70383848, 0xf1f5f504, 0x63bcbcdf, 0x77b6b6c1, 0xafdada75, 0x42212163, 0x20101030, 0xe5ffff1a, 0xfdf3f30e, 0xbfd2d26d, + 0x81cdcd4c, 0x180c0c14, 0x26131335, 0xc3ecec2f, 0xbe5f5fe1, 0x359797a2, 0x884444cc, 0x2e171739, 0x93c4c457, 0x55a7a7f2, 0xfc7e7e82, 0x7a3d3d47, 0xc86464ac, 0xba5d5de7, 0x3219192b, 0xe6737395, + 0xc06060a0, 0x19818198, 0x9e4f4fd1, 0xa3dcdc7f, 0x44222266, 0x542a2a7e, 0x3b9090ab, 0x0b888883, 0x8c4646ca, 0xc7eeee29, 0x6bb8b8d3, 0x2814143c, 0xa7dede79, 0xbc5e5ee2, 0x160b0b1d, 0xaddbdb76, + 0xdbe0e03b, 0x64323256, 0x743a3a4e, 0x140a0a1e, 0x924949db, 0x0c06060a, 0x4824246c, 0xb85c5ce4, 0x9fc2c25d, 0xbdd3d36e, 0x43acacef, 0xc46262a6, 0x399191a8, 0x319595a4, 0xd3e4e437, 0xf279798b, + 0xd5e7e732, 0x8bc8c843, 0x6e373759, 0xda6d6db7, 0x018d8d8c, 0xb1d5d564, 0x9c4e4ed2, 0x49a9a9e0, 0xd86c6cb4, 0xac5656fa, 0xf3f4f407, 0xcfeaea25, 0xca6565af, 0xf47a7a8e, 0x47aeaee9, 0x10080818, + 0x6fbabad5, 0xf0787888, 0x4a25256f, 0x5c2e2e72, 0x381c1c24, 0x57a6a6f1, 0x73b4b4c7, 0x97c6c651, 0xcbe8e823, 0xa1dddd7c, 0xe874749c, 0x3e1f1f21, 0x964b4bdd, 0x61bdbddc, 0x0d8b8b86, 0x0f8a8a85, + 0xe0707090, 0x7c3e3e42, 0x71b5b5c4, 0xcc6666aa, 0x904848d8, 0x06030305, 0xf7f6f601, 0x1c0e0e12, 0xc26161a3, 0x6a35355f, 0xae5757f9, 0x69b9b9d0, 0x17868691, 0x99c1c158, 0x3a1d1d27, 0x279e9eb9, + 0xd9e1e138, 0xebf8f813, 0x2b9898b3, 0x22111133, 0xd26969bb, 0xa9d9d970, 0x078e8e89, 0x339494a7, 0x2d9b9bb6, 0x3c1e1e22, 0x15878792, 0xc9e9e920, 0x87cece49, 0xaa5555ff, 0x50282878, 0xa5dfdf7a, + 0x038c8c8f, 0x59a1a1f8, 0x09898980, 0x1a0d0d17, 0x65bfbfda, 0xd7e6e631, 0x844242c6, 0xd06868b8, 0x824141c3, 0x299999b0, 0x5a2d2d77, 0x1e0f0f11, 0x7bb0b0cb, 0xa85454fc, 0x6dbbbbd6, 0x2c16163a }; +const uint32_t AES::Te4[256] = { 0x63636363, 0x7c7c7c7c, 0x77777777, 0x7b7b7b7b, 0xf2f2f2f2, 0x6b6b6b6b, 0x6f6f6f6f, 0xc5c5c5c5, 0x30303030, 0x01010101, 0x67676767, 0x2b2b2b2b, 0xfefefefe, 0xd7d7d7d7, 0xabababab, 0x76767676, + 0xcacacaca, 0x82828282, 0xc9c9c9c9, 0x7d7d7d7d, 0xfafafafa, 0x59595959, 0x47474747, 0xf0f0f0f0, 0xadadadad, 0xd4d4d4d4, 0xa2a2a2a2, 0xafafafaf, 0x9c9c9c9c, 0xa4a4a4a4, 0x72727272, 0xc0c0c0c0, + 0xb7b7b7b7, 0xfdfdfdfd, 0x93939393, 0x26262626, 0x36363636, 0x3f3f3f3f, 0xf7f7f7f7, 0xcccccccc, 0x34343434, 0xa5a5a5a5, 0xe5e5e5e5, 0xf1f1f1f1, 0x71717171, 0xd8d8d8d8, 0x31313131, 0x15151515, + 0x04040404, 0xc7c7c7c7, 0x23232323, 0xc3c3c3c3, 0x18181818, 0x96969696, 0x05050505, 0x9a9a9a9a, 0x07070707, 0x12121212, 0x80808080, 0xe2e2e2e2, 0xebebebeb, 0x27272727, 0xb2b2b2b2, 0x75757575, + 0x09090909, 0x83838383, 0x2c2c2c2c, 0x1a1a1a1a, 0x1b1b1b1b, 0x6e6e6e6e, 0x5a5a5a5a, 0xa0a0a0a0, 0x52525252, 0x3b3b3b3b, 0xd6d6d6d6, 0xb3b3b3b3, 0x29292929, 0xe3e3e3e3, 0x2f2f2f2f, 0x84848484, + 0x53535353, 0xd1d1d1d1, 0x00000000, 0xedededed, 0x20202020, 0xfcfcfcfc, 0xb1b1b1b1, 0x5b5b5b5b, 0x6a6a6a6a, 0xcbcbcbcb, 0xbebebebe, 0x39393939, 0x4a4a4a4a, 0x4c4c4c4c, 0x58585858, 0xcfcfcfcf, + 0xd0d0d0d0, 0xefefefef, 0xaaaaaaaa, 0xfbfbfbfb, 0x43434343, 0x4d4d4d4d, 0x33333333, 0x85858585, 0x45454545, 0xf9f9f9f9, 0x02020202, 0x7f7f7f7f, 0x50505050, 0x3c3c3c3c, 0x9f9f9f9f, 0xa8a8a8a8, + 0x51515151, 0xa3a3a3a3, 0x40404040, 0x8f8f8f8f, 0x92929292, 0x9d9d9d9d, 0x38383838, 0xf5f5f5f5, 0xbcbcbcbc, 0xb6b6b6b6, 0xdadadada, 0x21212121, 0x10101010, 0xffffffff, 0xf3f3f3f3, 0xd2d2d2d2, + 0xcdcdcdcd, 0x0c0c0c0c, 0x13131313, 0xecececec, 0x5f5f5f5f, 0x97979797, 0x44444444, 0x17171717, 0xc4c4c4c4, 0xa7a7a7a7, 0x7e7e7e7e, 0x3d3d3d3d, 0x64646464, 0x5d5d5d5d, 0x19191919, 0x73737373, + 0x60606060, 0x81818181, 0x4f4f4f4f, 0xdcdcdcdc, 0x22222222, 0x2a2a2a2a, 0x90909090, 0x88888888, 0x46464646, 0xeeeeeeee, 0xb8b8b8b8, 0x14141414, 0xdededede, 0x5e5e5e5e, 0x0b0b0b0b, 0xdbdbdbdb, + 0xe0e0e0e0, 0x32323232, 0x3a3a3a3a, 0x0a0a0a0a, 0x49494949, 0x06060606, 0x24242424, 0x5c5c5c5c, 0xc2c2c2c2, 0xd3d3d3d3, 0xacacacac, 0x62626262, 0x91919191, 0x95959595, 0xe4e4e4e4, 0x79797979, + 0xe7e7e7e7, 0xc8c8c8c8, 0x37373737, 0x6d6d6d6d, 0x8d8d8d8d, 0xd5d5d5d5, 0x4e4e4e4e, 0xa9a9a9a9, 0x6c6c6c6c, 0x56565656, 0xf4f4f4f4, 0xeaeaeaea, 0x65656565, 0x7a7a7a7a, 0xaeaeaeae, 0x08080808, + 0xbabababa, 0x78787878, 0x25252525, 0x2e2e2e2e, 0x1c1c1c1c, 0xa6a6a6a6, 0xb4b4b4b4, 0xc6c6c6c6, 0xe8e8e8e8, 0xdddddddd, 0x74747474, 0x1f1f1f1f, 0x4b4b4b4b, 0xbdbdbdbd, 0x8b8b8b8b, 0x8a8a8a8a, + 0x70707070, 0x3e3e3e3e, 0xb5b5b5b5, 0x66666666, 0x48484848, 0x03030303, 0xf6f6f6f6, 0x0e0e0e0e, 0x61616161, 0x35353535, 0x57575757, 0xb9b9b9b9, 0x86868686, 0xc1c1c1c1, 0x1d1d1d1d, 0x9e9e9e9e, + 0xe1e1e1e1, 0xf8f8f8f8, 0x98989898, 0x11111111, 0x69696969, 0xd9d9d9d9, 0x8e8e8e8e, 0x94949494, 0x9b9b9b9b, 0x1e1e1e1e, 0x87878787, 0xe9e9e9e9, 0xcececece, 0x55555555, 0x28282828, 0xdfdfdfdf, + 0x8c8c8c8c, 0xa1a1a1a1, 0x89898989, 0x0d0d0d0d, 0xbfbfbfbf, 0xe6e6e6e6, 0x42424242, 0x68686868, 0x41414141, 0x99999999, 0x2d2d2d2d, 0x0f0f0f0f, 0xb0b0b0b0, 0x54545454, 0xbbbbbbbb, 0x16161616 }; +const uint32_t AES::Td0[256] = { 0x51f4a750, 0x7e416553, 0x1a17a4c3, 0x3a275e96, 0x3bab6bcb, 0x1f9d45f1, 0xacfa58ab, 0x4be30393, 0x2030fa55, 0xad766df6, 0x88cc7691, 0xf5024c25, 0x4fe5d7fc, 0xc52acbd7, 0x26354480, 0xb562a38f, + 0xdeb15a49, 0x25ba1b67, 0x45ea0e98, 0x5dfec0e1, 0xc32f7502, 0x814cf012, 0x8d4697a3, 0x6bd3f9c6, 0x038f5fe7, 0x15929c95, 0xbf6d7aeb, 0x955259da, 0xd4be832d, 0x587421d3, 0x49e06929, 0x8ec9c844, + 0x75c2896a, 0xf48e7978, 0x99583e6b, 0x27b971dd, 0xbee14fb6, 0xf088ad17, 0xc920ac66, 0x7dce3ab4, 0x63df4a18, 0xe51a3182, 0x97513360, 0x62537f45, 0xb16477e0, 0xbb6bae84, 0xfe81a01c, 0xf9082b94, + 0x70486858, 0x8f45fd19, 0x94de6c87, 0x527bf8b7, 0xab73d323, 0x724b02e2, 0xe31f8f57, 0x6655ab2a, 0xb2eb2807, 0x2fb5c203, 0x86c57b9a, 0xd33708a5, 0x302887f2, 0x23bfa5b2, 0x02036aba, 0xed16825c, + 0x8acf1c2b, 0xa779b492, 0xf307f2f0, 0x4e69e2a1, 0x65daf4cd, 0x0605bed5, 0xd134621f, 0xc4a6fe8a, 0x342e539d, 0xa2f355a0, 0x058ae132, 0xa4f6eb75, 0x0b83ec39, 0x4060efaa, 0x5e719f06, 0xbd6e1051, + 0x3e218af9, 0x96dd063d, 0xdd3e05ae, 0x4de6bd46, 0x91548db5, 0x71c45d05, 0x0406d46f, 0x605015ff, 0x1998fb24, 0xd6bde997, 0x894043cc, 0x67d99e77, 0xb0e842bd, 0x07898b88, 0xe7195b38, 0x79c8eedb, + 0xa17c0a47, 0x7c420fe9, 0xf8841ec9, 0x00000000, 0x09808683, 0x322bed48, 0x1e1170ac, 0x6c5a724e, 0xfd0efffb, 0x0f853856, 0x3daed51e, 0x362d3927, 0x0a0fd964, 0x685ca621, 0x9b5b54d1, 0x24362e3a, + 0x0c0a67b1, 0x9357e70f, 0xb4ee96d2, 0x1b9b919e, 0x80c0c54f, 0x61dc20a2, 0x5a774b69, 0x1c121a16, 0xe293ba0a, 0xc0a02ae5, 0x3c22e043, 0x121b171d, 0x0e090d0b, 0xf28bc7ad, 0x2db6a8b9, 0x141ea9c8, + 0x57f11985, 0xaf75074c, 0xee99ddbb, 0xa37f60fd, 0xf701269f, 0x5c72f5bc, 0x44663bc5, 0x5bfb7e34, 0x8b432976, 0xcb23c6dc, 0xb6edfc68, 0xb8e4f163, 0xd731dcca, 0x42638510, 0x13972240, 0x84c61120, + 0x854a247d, 0xd2bb3df8, 0xaef93211, 0xc729a16d, 0x1d9e2f4b, 0xdcb230f3, 0x0d8652ec, 0x77c1e3d0, 0x2bb3166c, 0xa970b999, 0x119448fa, 0x47e96422, 0xa8fc8cc4, 0xa0f03f1a, 0x567d2cd8, 0x223390ef, + 0x87494ec7, 0xd938d1c1, 0x8ccaa2fe, 0x98d40b36, 0xa6f581cf, 0xa57ade28, 0xdab78e26, 0x3fadbfa4, 0x2c3a9de4, 0x5078920d, 0x6a5fcc9b, 0x547e4662, 0xf68d13c2, 0x90d8b8e8, 0x2e39f75e, 0x82c3aff5, + 0x9f5d80be, 0x69d0937c, 0x6fd52da9, 0xcf2512b3, 0xc8ac993b, 0x10187da7, 0xe89c636e, 0xdb3bbb7b, 0xcd267809, 0x6e5918f4, 0xec9ab701, 0x834f9aa8, 0xe6956e65, 0xaaffe67e, 0x21bccf08, 0xef15e8e6, + 0xbae79bd9, 0x4a6f36ce, 0xea9f09d4, 0x29b07cd6, 0x31a4b2af, 0x2a3f2331, 0xc6a59430, 0x35a266c0, 0x744ebc37, 0xfc82caa6, 0xe090d0b0, 0x33a7d815, 0xf104984a, 0x41ecdaf7, 0x7fcd500e, 0x1791f62f, + 0x764dd68d, 0x43efb04d, 0xccaa4d54, 0xe49604df, 0x9ed1b5e3, 0x4c6a881b, 0xc12c1fb8, 0x4665517f, 0x9d5eea04, 0x018c355d, 0xfa877473, 0xfb0b412e, 0xb3671d5a, 0x92dbd252, 0xe9105633, 0x6dd64713, + 0x9ad7618c, 0x37a10c7a, 0x59f8148e, 0xeb133c89, 0xcea927ee, 0xb761c935, 0xe11ce5ed, 0x7a47b13c, 0x9cd2df59, 0x55f2733f, 0x1814ce79, 0x73c737bf, 0x53f7cdea, 0x5ffdaa5b, 0xdf3d6f14, 0x7844db86, + 0xcaaff381, 0xb968c43e, 0x3824342c, 0xc2a3405f, 0x161dc372, 0xbce2250c, 0x283c498b, 0xff0d9541, 0x39a80171, 0x080cb3de, 0xd8b4e49c, 0x6456c190, 0x7bcb8461, 0xd532b670, 0x486c5c74, 0xd0b85742 }; +const uint8_t AES::Td4[256] = { 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb, 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb, + 0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e, 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25, + 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92, 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84, + 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06, 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b, + 0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73, 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e, + 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b, 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4, + 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f, 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef, + 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61, 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d }; +const uint32_t AES::rcon[15] = { 0x01000000, 0x02000000, 0x04000000, 0x08000000, 0x10000000, 0x20000000, 0x40000000, 0x80000000, 0x1B000000, 0x36000000, 0x6c000000, 0xd8000000, 0xab000000, 0x4d000000, 0x9a000000 }; -void AES::p_initSW(const uint8_t *key) noexcept +void AES::p_initSW(const uint8_t* key) noexcept { - uint32_t *rk = p_k.sw.ek; + uint32_t* rk = p_k.sw.ek; - rk[0] = Utils::loadBigEndian< uint32_t >(key); - rk[1] = Utils::loadBigEndian< uint32_t >(key + 4); - rk[2] = Utils::loadBigEndian< uint32_t >(key + 8); - rk[3] = Utils::loadBigEndian< uint32_t >(key + 12); - rk[4] = Utils::loadBigEndian< uint32_t >(key + 16); - rk[5] = Utils::loadBigEndian< uint32_t >(key + 20); - rk[6] = Utils::loadBigEndian< uint32_t >(key + 24); - rk[7] = Utils::loadBigEndian< uint32_t >(key + 28); - for (int i = 0;;) { - uint32_t temp = rk[7]; - rk[8] = rk[0] ^ (Te2_r((temp >> 16U) & 0xffU) & 0xff000000U) ^ (Te3_r((temp >> 8U) & 0xffU) & 0x00ff0000U) ^ (Te0[(temp) & 0xffU] & 0x0000ff00U) ^ (Te1_r(temp >> 24U) & 0x000000ffU) ^ rcon[i]; - rk[9] = rk[1] ^ rk[8]; - rk[10] = rk[2] ^ rk[9]; - rk[11] = rk[3] ^ rk[10]; - if (++i == 7) { - break; - } - temp = rk[11]; - rk[12] = rk[4] ^ (Te2_r(temp >> 24U) & 0xff000000U) ^ (Te3_r((temp >> 16U) & 0xffU) & 0x00ff0000U) ^ (Te0[(temp >> 8U) & 0xffU] & 0x0000ff00U) ^ (Te1_r((temp) & 0xffU) & 0x000000ffU); - rk[13] = rk[5] ^ rk[12]; - rk[14] = rk[6] ^ rk[13]; - rk[15] = rk[7] ^ rk[14]; - rk += 8; - } + rk[0] = Utils::loadBigEndian(key); + rk[1] = Utils::loadBigEndian(key + 4); + rk[2] = Utils::loadBigEndian(key + 8); + rk[3] = Utils::loadBigEndian(key + 12); + rk[4] = Utils::loadBigEndian(key + 16); + rk[5] = Utils::loadBigEndian(key + 20); + rk[6] = Utils::loadBigEndian(key + 24); + rk[7] = Utils::loadBigEndian(key + 28); + for (int i = 0;;) { + uint32_t temp = rk[7]; + rk[8] = rk[0] ^ (Te2_r((temp >> 16U) & 0xffU) & 0xff000000U) ^ (Te3_r((temp >> 8U) & 0xffU) & 0x00ff0000U) ^ (Te0[(temp) & 0xffU] & 0x0000ff00U) ^ (Te1_r(temp >> 24U) & 0x000000ffU) ^ rcon[i]; + rk[9] = rk[1] ^ rk[8]; + rk[10] = rk[2] ^ rk[9]; + rk[11] = rk[3] ^ rk[10]; + if (++i == 7) { + break; + } + temp = rk[11]; + rk[12] = rk[4] ^ (Te2_r(temp >> 24U) & 0xff000000U) ^ (Te3_r((temp >> 16U) & 0xffU) & 0x00ff0000U) ^ (Te0[(temp >> 8U) & 0xffU] & 0x0000ff00U) ^ (Te1_r((temp) & 0xffU) & 0x000000ffU); + rk[13] = rk[5] ^ rk[12]; + rk[14] = rk[6] ^ rk[13]; + rk[15] = rk[7] ^ rk[14]; + rk += 8; + } - p_encryptSW((const uint8_t *)Utils::ZERO256, (uint8_t *)p_k.sw.h); - p_k.sw.h[0] = Utils::ntoh(p_k.sw.h[0]); - p_k.sw.h[1] = Utils::ntoh(p_k.sw.h[1]); + p_encryptSW((const uint8_t*)Utils::ZERO256, (uint8_t*)p_k.sw.h); + p_k.sw.h[0] = Utils::ntoh(p_k.sw.h[0]); + p_k.sw.h[1] = Utils::ntoh(p_k.sw.h[1]); - for (int i = 0; i < 60; ++i) { - p_k.sw.dk[i] = p_k.sw.ek[i]; - } - rk = p_k.sw.dk; + for (int i = 0; i < 60; ++i) { + p_k.sw.dk[i] = p_k.sw.ek[i]; + } + rk = p_k.sw.dk; - for (int i = 0, j = 56; i < j; i += 4, j -= 4) { - uint32_t temp = rk[i]; - rk[i] = rk[j]; - rk[j] = temp; - temp = rk[i + 1]; - rk[i + 1] = rk[j + 1]; - rk[j + 1] = temp; - temp = rk[i + 2]; - rk[i + 2] = rk[j + 2]; - rk[j + 2] = temp; - temp = rk[i + 3]; - rk[i + 3] = rk[j + 3]; - rk[j + 3] = temp; - } - for (int i = 1; i < 14; ++i) { - rk += 4; - rk[0] = Td0[Te4[(rk[0] >> 24U)] & 0xffU] ^ Td1_r(Te4[(rk[0] >> 16U) & 0xffU] & 0xffU) ^ Td2_r(Te4[(rk[0] >> 8U) & 0xffU] & 0xffU) ^ Td3_r(Te4[(rk[0]) & 0xffU] & 0xffU); - rk[1] = Td0[Te4[(rk[1] >> 24U)] & 0xffU] ^ Td1_r(Te4[(rk[1] >> 16U) & 0xffU] & 0xffU) ^ Td2_r(Te4[(rk[1] >> 8U) & 0xffU] & 0xffU) ^ Td3_r(Te4[(rk[1]) & 0xffU] & 0xffU); - rk[2] = Td0[Te4[(rk[2] >> 24U)] & 0xffU] ^ Td1_r(Te4[(rk[2] >> 16U) & 0xffU] & 0xffU) ^ Td2_r(Te4[(rk[2] >> 8U) & 0xffU] & 0xffU) ^ Td3_r(Te4[(rk[2]) & 0xffU] & 0xffU); - rk[3] = Td0[Te4[(rk[3] >> 24U)] & 0xffU] ^ Td1_r(Te4[(rk[3] >> 16U) & 0xffU] & 0xffU) ^ Td2_r(Te4[(rk[3] >> 8U) & 0xffU] & 0xffU) ^ Td3_r(Te4[(rk[3]) & 0xffU] & 0xffU); - } + for (int i = 0, j = 56; i < j; i += 4, j -= 4) { + uint32_t temp = rk[i]; + rk[i] = rk[j]; + rk[j] = temp; + temp = rk[i + 1]; + rk[i + 1] = rk[j + 1]; + rk[j + 1] = temp; + temp = rk[i + 2]; + rk[i + 2] = rk[j + 2]; + rk[j + 2] = temp; + temp = rk[i + 3]; + rk[i + 3] = rk[j + 3]; + rk[j + 3] = temp; + } + for (int i = 1; i < 14; ++i) { + rk += 4; + rk[0] = Td0[Te4[(rk[0] >> 24U)] & 0xffU] ^ Td1_r(Te4[(rk[0] >> 16U) & 0xffU] & 0xffU) ^ Td2_r(Te4[(rk[0] >> 8U) & 0xffU] & 0xffU) ^ Td3_r(Te4[(rk[0]) & 0xffU] & 0xffU); + rk[1] = Td0[Te4[(rk[1] >> 24U)] & 0xffU] ^ Td1_r(Te4[(rk[1] >> 16U) & 0xffU] & 0xffU) ^ Td2_r(Te4[(rk[1] >> 8U) & 0xffU] & 0xffU) ^ Td3_r(Te4[(rk[1]) & 0xffU] & 0xffU); + rk[2] = Td0[Te4[(rk[2] >> 24U)] & 0xffU] ^ Td1_r(Te4[(rk[2] >> 16U) & 0xffU] & 0xffU) ^ Td2_r(Te4[(rk[2] >> 8U) & 0xffU] & 0xffU) ^ Td3_r(Te4[(rk[2]) & 0xffU] & 0xffU); + rk[3] = Td0[Te4[(rk[3] >> 24U)] & 0xffU] ^ Td1_r(Te4[(rk[3] >> 16U) & 0xffU] & 0xffU) ^ Td2_r(Te4[(rk[3] >> 8U) & 0xffU] & 0xffU) ^ Td3_r(Te4[(rk[3]) & 0xffU] & 0xffU); + } } -void AES::p_encryptSW(const uint8_t *in, uint8_t *out) const noexcept +void AES::p_encryptSW(const uint8_t* in, uint8_t* out) const noexcept { - const uint32_t *const restrict rk = p_k.sw.ek; - const uint32_t m8 = 0x000000ff; - const uint32_t m8_8 = 0x0000ff00; - const uint32_t m8_16 = 0x00ff0000; - const uint32_t m8_24 = 0xff000000; - uint32_t s0 = Utils::loadBigEndian< uint32_t >(in) ^rk[0]; - uint32_t s1 = Utils::loadBigEndian< uint32_t >(in + 4) ^rk[1]; - uint32_t s2 = Utils::loadBigEndian< uint32_t >(in + 8) ^rk[2]; - uint32_t s3 = Utils::loadBigEndian< uint32_t >(in + 12) ^rk[3]; + const uint32_t* const restrict rk = p_k.sw.ek; + const uint32_t m8 = 0x000000ff; + const uint32_t m8_8 = 0x0000ff00; + const uint32_t m8_16 = 0x00ff0000; + const uint32_t m8_24 = 0xff000000; + uint32_t s0 = Utils::loadBigEndian(in) ^ rk[0]; + uint32_t s1 = Utils::loadBigEndian(in + 4) ^ rk[1]; + uint32_t s2 = Utils::loadBigEndian(in + 8) ^ rk[2]; + uint32_t s3 = Utils::loadBigEndian(in + 12) ^ rk[3]; - uint32_t t0, t1, t2, t3; - t0 = Te0[s0 >> 24U] ^ Te1_r((s1 >> 16U) & m8) ^ Te2_r((s2 >> 8U) & m8) ^ Te3_r(s3 & m8) ^ rk[4]; - t1 = Te0[s1 >> 24U] ^ Te1_r((s2 >> 16U) & m8) ^ Te2_r((s3 >> 8U) & m8) ^ Te3_r(s0 & m8) ^ rk[5]; - t2 = Te0[s2 >> 24U] ^ Te1_r((s3 >> 16U) & m8) ^ Te2_r((s0 >> 8U) & m8) ^ Te3_r(s1 & m8) ^ rk[6]; - t3 = Te0[s3 >> 24U] ^ Te1_r((s0 >> 16U) & m8) ^ Te2_r((s1 >> 8U) & m8) ^ Te3_r(s2 & m8) ^ rk[7]; - s0 = Te0[t0 >> 24U] ^ Te1_r((t1 >> 16U) & m8) ^ Te2_r((t2 >> 8U) & m8) ^ Te3_r(t3 & m8) ^ rk[8]; - s1 = Te0[t1 >> 24U] ^ Te1_r((t2 >> 16U) & m8) ^ Te2_r((t3 >> 8U) & m8) ^ Te3_r(t0 & m8) ^ rk[9]; - s2 = Te0[t2 >> 24U] ^ Te1_r((t3 >> 16U) & m8) ^ Te2_r((t0 >> 8U) & m8) ^ Te3_r(t1 & m8) ^ rk[10]; - s3 = Te0[t3 >> 24U] ^ Te1_r((t0 >> 16U) & m8) ^ Te2_r((t1 >> 8U) & m8) ^ Te3_r(t2 & m8) ^ rk[11]; - t0 = Te0[s0 >> 24U] ^ Te1_r((s1 >> 16U) & m8) ^ Te2_r((s2 >> 8U) & m8) ^ Te3_r(s3 & m8) ^ rk[12]; - t1 = Te0[s1 >> 24U] ^ Te1_r((s2 >> 16U) & m8) ^ Te2_r((s3 >> 8U) & m8) ^ Te3_r(s0 & m8) ^ rk[13]; - t2 = Te0[s2 >> 24U] ^ Te1_r((s3 >> 16U) & m8) ^ Te2_r((s0 >> 8U) & m8) ^ Te3_r(s1 & m8) ^ rk[14]; - t3 = Te0[s3 >> 24U] ^ Te1_r((s0 >> 16U) & m8) ^ Te2_r((s1 >> 8U) & m8) ^ Te3_r(s2 & m8) ^ rk[15]; - s0 = Te0[t0 >> 24U] ^ Te1_r((t1 >> 16U) & m8) ^ Te2_r((t2 >> 8U) & m8) ^ Te3_r(t3 & m8) ^ rk[16]; - s1 = Te0[t1 >> 24U] ^ Te1_r((t2 >> 16U) & m8) ^ Te2_r((t3 >> 8U) & m8) ^ Te3_r(t0 & m8) ^ rk[17]; - s2 = Te0[t2 >> 24U] ^ Te1_r((t3 >> 16U) & m8) ^ Te2_r((t0 >> 8U) & m8) ^ Te3_r(t1 & m8) ^ rk[18]; - s3 = Te0[t3 >> 24U] ^ Te1_r((t0 >> 16U) & m8) ^ Te2_r((t1 >> 8U) & m8) ^ Te3_r(t2 & m8) ^ rk[19]; - t0 = Te0[s0 >> 24U] ^ Te1_r((s1 >> 16U) & m8) ^ Te2_r((s2 >> 8U) & m8) ^ Te3_r(s3 & m8) ^ rk[20]; - t1 = Te0[s1 >> 24U] ^ Te1_r((s2 >> 16U) & m8) ^ Te2_r((s3 >> 8U) & m8) ^ Te3_r(s0 & m8) ^ rk[21]; - t2 = Te0[s2 >> 24U] ^ Te1_r((s3 >> 16U) & m8) ^ Te2_r((s0 >> 8U) & m8) ^ Te3_r(s1 & m8) ^ rk[22]; - t3 = Te0[s3 >> 24U] ^ Te1_r((s0 >> 16U) & m8) ^ Te2_r((s1 >> 8U) & m8) ^ Te3_r(s2 & m8) ^ rk[23]; - s0 = Te0[t0 >> 24U] ^ Te1_r((t1 >> 16U) & m8) ^ Te2_r((t2 >> 8U) & m8) ^ Te3_r(t3 & m8) ^ rk[24]; - s1 = Te0[t1 >> 24U] ^ Te1_r((t2 >> 16U) & m8) ^ Te2_r((t3 >> 8U) & m8) ^ Te3_r(t0 & m8) ^ rk[25]; - s2 = Te0[t2 >> 24U] ^ Te1_r((t3 >> 16U) & m8) ^ Te2_r((t0 >> 8U) & m8) ^ Te3_r(t1 & m8) ^ rk[26]; - s3 = Te0[t3 >> 24U] ^ Te1_r((t0 >> 16U) & m8) ^ Te2_r((t1 >> 8U) & m8) ^ Te3_r(t2 & m8) ^ rk[27]; - t0 = Te0[s0 >> 24U] ^ Te1_r((s1 >> 16U) & m8) ^ Te2_r((s2 >> 8U) & m8) ^ Te3_r(s3 & m8) ^ rk[28]; - t1 = Te0[s1 >> 24U] ^ Te1_r((s2 >> 16U) & m8) ^ Te2_r((s3 >> 8U) & m8) ^ Te3_r(s0 & m8) ^ rk[29]; - t2 = Te0[s2 >> 24U] ^ Te1_r((s3 >> 16U) & m8) ^ Te2_r((s0 >> 8U) & m8) ^ Te3_r(s1 & m8) ^ rk[30]; - t3 = Te0[s3 >> 24U] ^ Te1_r((s0 >> 16U) & m8) ^ Te2_r((s1 >> 8U) & m8) ^ Te3_r(s2 & m8) ^ rk[31]; - s0 = Te0[t0 >> 24U] ^ Te1_r((t1 >> 16U) & m8) ^ Te2_r((t2 >> 8U) & m8) ^ Te3_r(t3 & m8) ^ rk[32]; - s1 = Te0[t1 >> 24U] ^ Te1_r((t2 >> 16U) & m8) ^ Te2_r((t3 >> 8U) & m8) ^ Te3_r(t0 & m8) ^ rk[33]; - s2 = Te0[t2 >> 24U] ^ Te1_r((t3 >> 16U) & m8) ^ Te2_r((t0 >> 8U) & m8) ^ Te3_r(t1 & m8) ^ rk[34]; - s3 = Te0[t3 >> 24U] ^ Te1_r((t0 >> 16U) & m8) ^ Te2_r((t1 >> 8U) & m8) ^ Te3_r(t2 & m8) ^ rk[35]; - t0 = Te0[s0 >> 24U] ^ Te1_r((s1 >> 16U) & m8) ^ Te2_r((s2 >> 8U) & m8) ^ Te3_r(s3 & m8) ^ rk[36]; - t1 = Te0[s1 >> 24U] ^ Te1_r((s2 >> 16U) & m8) ^ Te2_r((s3 >> 8U) & m8) ^ Te3_r(s0 & m8) ^ rk[37]; - t2 = Te0[s2 >> 24U] ^ Te1_r((s3 >> 16U) & m8) ^ Te2_r((s0 >> 8U) & m8) ^ Te3_r(s1 & m8) ^ rk[38]; - t3 = Te0[s3 >> 24U] ^ Te1_r((s0 >> 16U) & m8) ^ Te2_r((s1 >> 8U) & m8) ^ Te3_r(s2 & m8) ^ rk[39]; - s0 = Te0[t0 >> 24U] ^ Te1_r((t1 >> 16U) & m8) ^ Te2_r((t2 >> 8U) & m8) ^ Te3_r(t3 & m8) ^ rk[40]; - s1 = Te0[t1 >> 24U] ^ Te1_r((t2 >> 16U) & m8) ^ Te2_r((t3 >> 8U) & m8) ^ Te3_r(t0 & m8) ^ rk[41]; - s2 = Te0[t2 >> 24U] ^ Te1_r((t3 >> 16U) & m8) ^ Te2_r((t0 >> 8U) & m8) ^ Te3_r(t1 & m8) ^ rk[42]; - s3 = Te0[t3 >> 24U] ^ Te1_r((t0 >> 16U) & m8) ^ Te2_r((t1 >> 8U) & m8) ^ Te3_r(t2 & m8) ^ rk[43]; - t0 = Te0[s0 >> 24U] ^ Te1_r((s1 >> 16U) & m8) ^ Te2_r((s2 >> 8U) & m8) ^ Te3_r(s3 & m8) ^ rk[44]; - t1 = Te0[s1 >> 24U] ^ Te1_r((s2 >> 16U) & m8) ^ Te2_r((s3 >> 8U) & m8) ^ Te3_r(s0 & m8) ^ rk[45]; - t2 = Te0[s2 >> 24U] ^ Te1_r((s3 >> 16U) & m8) ^ Te2_r((s0 >> 8U) & m8) ^ Te3_r(s1 & m8) ^ rk[46]; - t3 = Te0[s3 >> 24U] ^ Te1_r((s0 >> 16U) & m8) ^ Te2_r((s1 >> 8U) & m8) ^ Te3_r(s2 & m8) ^ rk[47]; - s0 = Te0[t0 >> 24U] ^ Te1_r((t1 >> 16U) & m8) ^ Te2_r((t2 >> 8U) & m8) ^ Te3_r(t3 & m8) ^ rk[48]; - s1 = Te0[t1 >> 24U] ^ Te1_r((t2 >> 16U) & m8) ^ Te2_r((t3 >> 8U) & m8) ^ Te3_r(t0 & m8) ^ rk[49]; - s2 = Te0[t2 >> 24U] ^ Te1_r((t3 >> 16U) & m8) ^ Te2_r((t0 >> 8U) & m8) ^ Te3_r(t1 & m8) ^ rk[50]; - s3 = Te0[t3 >> 24U] ^ Te1_r((t0 >> 16U) & m8) ^ Te2_r((t1 >> 8U) & m8) ^ Te3_r(t2 & m8) ^ rk[51]; - t0 = Te0[s0 >> 24U] ^ Te1_r((s1 >> 16U) & m8) ^ Te2_r((s2 >> 8U) & m8) ^ Te3_r(s3 & m8) ^ rk[52]; - t1 = Te0[s1 >> 24U] ^ Te1_r((s2 >> 16U) & m8) ^ Te2_r((s3 >> 8U) & m8) ^ Te3_r(s0 & m8) ^ rk[53]; - t2 = Te0[s2 >> 24U] ^ Te1_r((s3 >> 16U) & m8) ^ Te2_r((s0 >> 8U) & m8) ^ Te3_r(s1 & m8) ^ rk[54]; - t3 = Te0[s3 >> 24U] ^ Te1_r((s0 >> 16U) & m8) ^ Te2_r((s1 >> 8U) & m8) ^ Te3_r(s2 & m8) ^ rk[55]; - s0 = (Te2_r(t0 >> 24U) & m8_24) ^ (Te3_r((t1 >> 16U) & m8) & m8_16) ^ (Te0[(t2 >> 8U) & m8] & m8_8) ^ (Te1_r(t3 & m8) & m8) ^ rk[56]; - s1 = (Te2_r(t1 >> 24U) & m8_24) ^ (Te3_r((t2 >> 16U) & m8) & m8_16) ^ (Te0[(t3 >> 8U) & m8] & m8_8) ^ (Te1_r(t0 & m8) & m8) ^ rk[57]; - s2 = (Te2_r(t2 >> 24U) & m8_24) ^ (Te3_r((t3 >> 16U) & m8) & m8_16) ^ (Te0[(t0 >> 8U) & m8] & m8_8) ^ (Te1_r(t1 & m8) & m8) ^ rk[58]; - s3 = (Te2_r(t3 >> 24U) & m8_24) ^ (Te3_r((t0 >> 16U) & m8) & m8_16) ^ (Te0[(t1 >> 8U) & m8] & m8_8) ^ (Te1_r(t2 & m8) & m8) ^ rk[59]; + uint32_t t0, t1, t2, t3; + t0 = Te0[s0 >> 24U] ^ Te1_r((s1 >> 16U) & m8) ^ Te2_r((s2 >> 8U) & m8) ^ Te3_r(s3 & m8) ^ rk[4]; + t1 = Te0[s1 >> 24U] ^ Te1_r((s2 >> 16U) & m8) ^ Te2_r((s3 >> 8U) & m8) ^ Te3_r(s0 & m8) ^ rk[5]; + t2 = Te0[s2 >> 24U] ^ Te1_r((s3 >> 16U) & m8) ^ Te2_r((s0 >> 8U) & m8) ^ Te3_r(s1 & m8) ^ rk[6]; + t3 = Te0[s3 >> 24U] ^ Te1_r((s0 >> 16U) & m8) ^ Te2_r((s1 >> 8U) & m8) ^ Te3_r(s2 & m8) ^ rk[7]; + s0 = Te0[t0 >> 24U] ^ Te1_r((t1 >> 16U) & m8) ^ Te2_r((t2 >> 8U) & m8) ^ Te3_r(t3 & m8) ^ rk[8]; + s1 = Te0[t1 >> 24U] ^ Te1_r((t2 >> 16U) & m8) ^ Te2_r((t3 >> 8U) & m8) ^ Te3_r(t0 & m8) ^ rk[9]; + s2 = Te0[t2 >> 24U] ^ Te1_r((t3 >> 16U) & m8) ^ Te2_r((t0 >> 8U) & m8) ^ Te3_r(t1 & m8) ^ rk[10]; + s3 = Te0[t3 >> 24U] ^ Te1_r((t0 >> 16U) & m8) ^ Te2_r((t1 >> 8U) & m8) ^ Te3_r(t2 & m8) ^ rk[11]; + t0 = Te0[s0 >> 24U] ^ Te1_r((s1 >> 16U) & m8) ^ Te2_r((s2 >> 8U) & m8) ^ Te3_r(s3 & m8) ^ rk[12]; + t1 = Te0[s1 >> 24U] ^ Te1_r((s2 >> 16U) & m8) ^ Te2_r((s3 >> 8U) & m8) ^ Te3_r(s0 & m8) ^ rk[13]; + t2 = Te0[s2 >> 24U] ^ Te1_r((s3 >> 16U) & m8) ^ Te2_r((s0 >> 8U) & m8) ^ Te3_r(s1 & m8) ^ rk[14]; + t3 = Te0[s3 >> 24U] ^ Te1_r((s0 >> 16U) & m8) ^ Te2_r((s1 >> 8U) & m8) ^ Te3_r(s2 & m8) ^ rk[15]; + s0 = Te0[t0 >> 24U] ^ Te1_r((t1 >> 16U) & m8) ^ Te2_r((t2 >> 8U) & m8) ^ Te3_r(t3 & m8) ^ rk[16]; + s1 = Te0[t1 >> 24U] ^ Te1_r((t2 >> 16U) & m8) ^ Te2_r((t3 >> 8U) & m8) ^ Te3_r(t0 & m8) ^ rk[17]; + s2 = Te0[t2 >> 24U] ^ Te1_r((t3 >> 16U) & m8) ^ Te2_r((t0 >> 8U) & m8) ^ Te3_r(t1 & m8) ^ rk[18]; + s3 = Te0[t3 >> 24U] ^ Te1_r((t0 >> 16U) & m8) ^ Te2_r((t1 >> 8U) & m8) ^ Te3_r(t2 & m8) ^ rk[19]; + t0 = Te0[s0 >> 24U] ^ Te1_r((s1 >> 16U) & m8) ^ Te2_r((s2 >> 8U) & m8) ^ Te3_r(s3 & m8) ^ rk[20]; + t1 = Te0[s1 >> 24U] ^ Te1_r((s2 >> 16U) & m8) ^ Te2_r((s3 >> 8U) & m8) ^ Te3_r(s0 & m8) ^ rk[21]; + t2 = Te0[s2 >> 24U] ^ Te1_r((s3 >> 16U) & m8) ^ Te2_r((s0 >> 8U) & m8) ^ Te3_r(s1 & m8) ^ rk[22]; + t3 = Te0[s3 >> 24U] ^ Te1_r((s0 >> 16U) & m8) ^ Te2_r((s1 >> 8U) & m8) ^ Te3_r(s2 & m8) ^ rk[23]; + s0 = Te0[t0 >> 24U] ^ Te1_r((t1 >> 16U) & m8) ^ Te2_r((t2 >> 8U) & m8) ^ Te3_r(t3 & m8) ^ rk[24]; + s1 = Te0[t1 >> 24U] ^ Te1_r((t2 >> 16U) & m8) ^ Te2_r((t3 >> 8U) & m8) ^ Te3_r(t0 & m8) ^ rk[25]; + s2 = Te0[t2 >> 24U] ^ Te1_r((t3 >> 16U) & m8) ^ Te2_r((t0 >> 8U) & m8) ^ Te3_r(t1 & m8) ^ rk[26]; + s3 = Te0[t3 >> 24U] ^ Te1_r((t0 >> 16U) & m8) ^ Te2_r((t1 >> 8U) & m8) ^ Te3_r(t2 & m8) ^ rk[27]; + t0 = Te0[s0 >> 24U] ^ Te1_r((s1 >> 16U) & m8) ^ Te2_r((s2 >> 8U) & m8) ^ Te3_r(s3 & m8) ^ rk[28]; + t1 = Te0[s1 >> 24U] ^ Te1_r((s2 >> 16U) & m8) ^ Te2_r((s3 >> 8U) & m8) ^ Te3_r(s0 & m8) ^ rk[29]; + t2 = Te0[s2 >> 24U] ^ Te1_r((s3 >> 16U) & m8) ^ Te2_r((s0 >> 8U) & m8) ^ Te3_r(s1 & m8) ^ rk[30]; + t3 = Te0[s3 >> 24U] ^ Te1_r((s0 >> 16U) & m8) ^ Te2_r((s1 >> 8U) & m8) ^ Te3_r(s2 & m8) ^ rk[31]; + s0 = Te0[t0 >> 24U] ^ Te1_r((t1 >> 16U) & m8) ^ Te2_r((t2 >> 8U) & m8) ^ Te3_r(t3 & m8) ^ rk[32]; + s1 = Te0[t1 >> 24U] ^ Te1_r((t2 >> 16U) & m8) ^ Te2_r((t3 >> 8U) & m8) ^ Te3_r(t0 & m8) ^ rk[33]; + s2 = Te0[t2 >> 24U] ^ Te1_r((t3 >> 16U) & m8) ^ Te2_r((t0 >> 8U) & m8) ^ Te3_r(t1 & m8) ^ rk[34]; + s3 = Te0[t3 >> 24U] ^ Te1_r((t0 >> 16U) & m8) ^ Te2_r((t1 >> 8U) & m8) ^ Te3_r(t2 & m8) ^ rk[35]; + t0 = Te0[s0 >> 24U] ^ Te1_r((s1 >> 16U) & m8) ^ Te2_r((s2 >> 8U) & m8) ^ Te3_r(s3 & m8) ^ rk[36]; + t1 = Te0[s1 >> 24U] ^ Te1_r((s2 >> 16U) & m8) ^ Te2_r((s3 >> 8U) & m8) ^ Te3_r(s0 & m8) ^ rk[37]; + t2 = Te0[s2 >> 24U] ^ Te1_r((s3 >> 16U) & m8) ^ Te2_r((s0 >> 8U) & m8) ^ Te3_r(s1 & m8) ^ rk[38]; + t3 = Te0[s3 >> 24U] ^ Te1_r((s0 >> 16U) & m8) ^ Te2_r((s1 >> 8U) & m8) ^ Te3_r(s2 & m8) ^ rk[39]; + s0 = Te0[t0 >> 24U] ^ Te1_r((t1 >> 16U) & m8) ^ Te2_r((t2 >> 8U) & m8) ^ Te3_r(t3 & m8) ^ rk[40]; + s1 = Te0[t1 >> 24U] ^ Te1_r((t2 >> 16U) & m8) ^ Te2_r((t3 >> 8U) & m8) ^ Te3_r(t0 & m8) ^ rk[41]; + s2 = Te0[t2 >> 24U] ^ Te1_r((t3 >> 16U) & m8) ^ Te2_r((t0 >> 8U) & m8) ^ Te3_r(t1 & m8) ^ rk[42]; + s3 = Te0[t3 >> 24U] ^ Te1_r((t0 >> 16U) & m8) ^ Te2_r((t1 >> 8U) & m8) ^ Te3_r(t2 & m8) ^ rk[43]; + t0 = Te0[s0 >> 24U] ^ Te1_r((s1 >> 16U) & m8) ^ Te2_r((s2 >> 8U) & m8) ^ Te3_r(s3 & m8) ^ rk[44]; + t1 = Te0[s1 >> 24U] ^ Te1_r((s2 >> 16U) & m8) ^ Te2_r((s3 >> 8U) & m8) ^ Te3_r(s0 & m8) ^ rk[45]; + t2 = Te0[s2 >> 24U] ^ Te1_r((s3 >> 16U) & m8) ^ Te2_r((s0 >> 8U) & m8) ^ Te3_r(s1 & m8) ^ rk[46]; + t3 = Te0[s3 >> 24U] ^ Te1_r((s0 >> 16U) & m8) ^ Te2_r((s1 >> 8U) & m8) ^ Te3_r(s2 & m8) ^ rk[47]; + s0 = Te0[t0 >> 24U] ^ Te1_r((t1 >> 16U) & m8) ^ Te2_r((t2 >> 8U) & m8) ^ Te3_r(t3 & m8) ^ rk[48]; + s1 = Te0[t1 >> 24U] ^ Te1_r((t2 >> 16U) & m8) ^ Te2_r((t3 >> 8U) & m8) ^ Te3_r(t0 & m8) ^ rk[49]; + s2 = Te0[t2 >> 24U] ^ Te1_r((t3 >> 16U) & m8) ^ Te2_r((t0 >> 8U) & m8) ^ Te3_r(t1 & m8) ^ rk[50]; + s3 = Te0[t3 >> 24U] ^ Te1_r((t0 >> 16U) & m8) ^ Te2_r((t1 >> 8U) & m8) ^ Te3_r(t2 & m8) ^ rk[51]; + t0 = Te0[s0 >> 24U] ^ Te1_r((s1 >> 16U) & m8) ^ Te2_r((s2 >> 8U) & m8) ^ Te3_r(s3 & m8) ^ rk[52]; + t1 = Te0[s1 >> 24U] ^ Te1_r((s2 >> 16U) & m8) ^ Te2_r((s3 >> 8U) & m8) ^ Te3_r(s0 & m8) ^ rk[53]; + t2 = Te0[s2 >> 24U] ^ Te1_r((s3 >> 16U) & m8) ^ Te2_r((s0 >> 8U) & m8) ^ Te3_r(s1 & m8) ^ rk[54]; + t3 = Te0[s3 >> 24U] ^ Te1_r((s0 >> 16U) & m8) ^ Te2_r((s1 >> 8U) & m8) ^ Te3_r(s2 & m8) ^ rk[55]; + s0 = (Te2_r(t0 >> 24U) & m8_24) ^ (Te3_r((t1 >> 16U) & m8) & m8_16) ^ (Te0[(t2 >> 8U) & m8] & m8_8) ^ (Te1_r(t3 & m8) & m8) ^ rk[56]; + s1 = (Te2_r(t1 >> 24U) & m8_24) ^ (Te3_r((t2 >> 16U) & m8) & m8_16) ^ (Te0[(t3 >> 8U) & m8] & m8_8) ^ (Te1_r(t0 & m8) & m8) ^ rk[57]; + s2 = (Te2_r(t2 >> 24U) & m8_24) ^ (Te3_r((t3 >> 16U) & m8) & m8_16) ^ (Te0[(t0 >> 8U) & m8] & m8_8) ^ (Te1_r(t1 & m8) & m8) ^ rk[58]; + s3 = (Te2_r(t3 >> 24U) & m8_24) ^ (Te3_r((t0 >> 16U) & m8) & m8_16) ^ (Te0[(t1 >> 8U) & m8] & m8_8) ^ (Te1_r(t2 & m8) & m8) ^ rk[59]; - Utils::storeBigEndian< uint32_t >(out, s0); - Utils::storeBigEndian< uint32_t >(out + 4, s1); - Utils::storeBigEndian< uint32_t >(out + 8, s2); - Utils::storeBigEndian< uint32_t >(out + 12, s3); + Utils::storeBigEndian(out, s0); + Utils::storeBigEndian(out + 4, s1); + Utils::storeBigEndian(out + 8, s2); + Utils::storeBigEndian(out + 12, s3); } -void AES::p_decryptSW(const uint8_t *in, uint8_t *out) const noexcept +void AES::p_decryptSW(const uint8_t* in, uint8_t* out) const noexcept { - const uint32_t *restrict rk = p_k.sw.dk; - const uint32_t m8 = 0x000000ff; - uint32_t s0 = Utils::loadBigEndian< uint32_t >(in) ^rk[0]; - uint32_t s1 = Utils::loadBigEndian< uint32_t >(in + 4) ^rk[1]; - uint32_t s2 = Utils::loadBigEndian< uint32_t >(in + 8) ^rk[2]; - uint32_t s3 = Utils::loadBigEndian< uint32_t >(in + 12) ^rk[3]; + const uint32_t* restrict rk = p_k.sw.dk; + const uint32_t m8 = 0x000000ff; + uint32_t s0 = Utils::loadBigEndian(in) ^ rk[0]; + uint32_t s1 = Utils::loadBigEndian(in + 4) ^ rk[1]; + uint32_t s2 = Utils::loadBigEndian(in + 8) ^ rk[2]; + uint32_t s3 = Utils::loadBigEndian(in + 12) ^ rk[3]; - uint32_t t0, t1, t2, t3; - t0 = Td0[s0 >> 24U] ^ Td1_r((s3 >> 16U) & m8) ^ Td2_r((s2 >> 8U) & m8) ^ Td3_r(s1 & m8) ^ rk[4]; - t1 = Td0[s1 >> 24U] ^ Td1_r((s0 >> 16U) & m8) ^ Td2_r((s3 >> 8U) & m8) ^ Td3_r(s2 & m8) ^ rk[5]; - t2 = Td0[s2 >> 24U] ^ Td1_r((s1 >> 16U) & m8) ^ Td2_r((s0 >> 8U) & m8) ^ Td3_r(s3 & m8) ^ rk[6]; - t3 = Td0[s3 >> 24U] ^ Td1_r((s2 >> 16U) & m8) ^ Td2_r((s1 >> 8U) & m8) ^ Td3_r(s0 & m8) ^ rk[7]; - s0 = Td0[t0 >> 24U] ^ Td1_r((t3 >> 16U) & m8) ^ Td2_r((t2 >> 8U) & m8) ^ Td3_r(t1 & m8) ^ rk[8]; - s1 = Td0[t1 >> 24U] ^ Td1_r((t0 >> 16U) & m8) ^ Td2_r((t3 >> 8U) & m8) ^ Td3_r(t2 & m8) ^ rk[9]; - s2 = Td0[t2 >> 24U] ^ Td1_r((t1 >> 16U) & m8) ^ Td2_r((t0 >> 8U) & m8) ^ Td3_r(t3 & m8) ^ rk[10]; - s3 = Td0[t3 >> 24U] ^ Td1_r((t2 >> 16U) & m8) ^ Td2_r((t1 >> 8U) & m8) ^ Td3_r(t0 & m8) ^ rk[11]; - t0 = Td0[s0 >> 24U] ^ Td1_r((s3 >> 16U) & m8) ^ Td2_r((s2 >> 8U) & m8) ^ Td3_r(s1 & m8) ^ rk[12]; - t1 = Td0[s1 >> 24U] ^ Td1_r((s0 >> 16U) & m8) ^ Td2_r((s3 >> 8U) & m8) ^ Td3_r(s2 & m8) ^ rk[13]; - t2 = Td0[s2 >> 24U] ^ Td1_r((s1 >> 16U) & m8) ^ Td2_r((s0 >> 8U) & m8) ^ Td3_r(s3 & m8) ^ rk[14]; - t3 = Td0[s3 >> 24U] ^ Td1_r((s2 >> 16U) & m8) ^ Td2_r((s1 >> 8U) & m8) ^ Td3_r(s0 & m8) ^ rk[15]; - s0 = Td0[t0 >> 24U] ^ Td1_r((t3 >> 16U) & m8) ^ Td2_r((t2 >> 8U) & m8) ^ Td3_r(t1 & m8) ^ rk[16]; - s1 = Td0[t1 >> 24U] ^ Td1_r((t0 >> 16U) & m8) ^ Td2_r((t3 >> 8U) & m8) ^ Td3_r(t2 & m8) ^ rk[17]; - s2 = Td0[t2 >> 24U] ^ Td1_r((t1 >> 16U) & m8) ^ Td2_r((t0 >> 8U) & m8) ^ Td3_r(t3 & m8) ^ rk[18]; - s3 = Td0[t3 >> 24U] ^ Td1_r((t2 >> 16U) & m8) ^ Td2_r((t1 >> 8U) & m8) ^ Td3_r(t0 & m8) ^ rk[19]; - t0 = Td0[s0 >> 24U] ^ Td1_r((s3 >> 16U) & m8) ^ Td2_r((s2 >> 8U) & m8) ^ Td3_r(s1 & m8) ^ rk[20]; - t1 = Td0[s1 >> 24U] ^ Td1_r((s0 >> 16U) & m8) ^ Td2_r((s3 >> 8U) & m8) ^ Td3_r(s2 & m8) ^ rk[21]; - t2 = Td0[s2 >> 24U] ^ Td1_r((s1 >> 16U) & m8) ^ Td2_r((s0 >> 8U) & m8) ^ Td3_r(s3 & m8) ^ rk[22]; - t3 = Td0[s3 >> 24U] ^ Td1_r((s2 >> 16U) & m8) ^ Td2_r((s1 >> 8U) & m8) ^ Td3_r(s0 & m8) ^ rk[23]; - s0 = Td0[t0 >> 24U] ^ Td1_r((t3 >> 16U) & m8) ^ Td2_r((t2 >> 8U) & m8) ^ Td3_r(t1 & m8) ^ rk[24]; - s1 = Td0[t1 >> 24U] ^ Td1_r((t0 >> 16U) & m8) ^ Td2_r((t3 >> 8U) & m8) ^ Td3_r(t2 & m8) ^ rk[25]; - s2 = Td0[t2 >> 24U] ^ Td1_r((t1 >> 16U) & m8) ^ Td2_r((t0 >> 8U) & m8) ^ Td3_r(t3 & m8) ^ rk[26]; - s3 = Td0[t3 >> 24U] ^ Td1_r((t2 >> 16U) & m8) ^ Td2_r((t1 >> 8U) & m8) ^ Td3_r(t0 & m8) ^ rk[27]; - t0 = Td0[s0 >> 24U] ^ Td1_r((s3 >> 16U) & m8) ^ Td2_r((s2 >> 8U) & m8) ^ Td3_r(s1 & m8) ^ rk[28]; - t1 = Td0[s1 >> 24U] ^ Td1_r((s0 >> 16U) & m8) ^ Td2_r((s3 >> 8U) & m8) ^ Td3_r(s2 & m8) ^ rk[29]; - t2 = Td0[s2 >> 24U] ^ Td1_r((s1 >> 16U) & m8) ^ Td2_r((s0 >> 8U) & m8) ^ Td3_r(s3 & m8) ^ rk[30]; - t3 = Td0[s3 >> 24U] ^ Td1_r((s2 >> 16U) & m8) ^ Td2_r((s1 >> 8U) & m8) ^ Td3_r(s0 & m8) ^ rk[31]; - s0 = Td0[t0 >> 24U] ^ Td1_r((t3 >> 16U) & m8) ^ Td2_r((t2 >> 8U) & m8) ^ Td3_r(t1 & m8) ^ rk[32]; - s1 = Td0[t1 >> 24U] ^ Td1_r((t0 >> 16U) & m8) ^ Td2_r((t3 >> 8U) & m8) ^ Td3_r(t2 & m8) ^ rk[33]; - s2 = Td0[t2 >> 24U] ^ Td1_r((t1 >> 16U) & m8) ^ Td2_r((t0 >> 8U) & m8) ^ Td3_r(t3 & m8) ^ rk[34]; - s3 = Td0[t3 >> 24U] ^ Td1_r((t2 >> 16U) & m8) ^ Td2_r((t1 >> 8U) & m8) ^ Td3_r(t0 & m8) ^ rk[35]; - t0 = Td0[s0 >> 24U] ^ Td1_r((s3 >> 16U) & m8) ^ Td2_r((s2 >> 8U) & m8) ^ Td3_r(s1 & m8) ^ rk[36]; - t1 = Td0[s1 >> 24U] ^ Td1_r((s0 >> 16U) & m8) ^ Td2_r((s3 >> 8U) & m8) ^ Td3_r(s2 & m8) ^ rk[37]; - t2 = Td0[s2 >> 24U] ^ Td1_r((s1 >> 16U) & m8) ^ Td2_r((s0 >> 8U) & m8) ^ Td3_r(s3 & m8) ^ rk[38]; - t3 = Td0[s3 >> 24U] ^ Td1_r((s2 >> 16U) & m8) ^ Td2_r((s1 >> 8U) & m8) ^ Td3_r(s0 & m8) ^ rk[39]; - s0 = Td0[t0 >> 24U] ^ Td1_r((t3 >> 16U) & m8) ^ Td2_r((t2 >> 8U) & m8) ^ Td3_r(t1 & m8) ^ rk[40]; - s1 = Td0[t1 >> 24U] ^ Td1_r((t0 >> 16U) & m8) ^ Td2_r((t3 >> 8U) & m8) ^ Td3_r(t2 & m8) ^ rk[41]; - s2 = Td0[t2 >> 24U] ^ Td1_r((t1 >> 16U) & m8) ^ Td2_r((t0 >> 8U) & m8) ^ Td3_r(t3 & m8) ^ rk[42]; - s3 = Td0[t3 >> 24U] ^ Td1_r((t2 >> 16U) & m8) ^ Td2_r((t1 >> 8U) & m8) ^ Td3_r(t0 & m8) ^ rk[43]; - t0 = Td0[s0 >> 24U] ^ Td1_r((s3 >> 16U) & m8) ^ Td2_r((s2 >> 8U) & m8) ^ Td3_r(s1 & m8) ^ rk[44]; - t1 = Td0[s1 >> 24U] ^ Td1_r((s0 >> 16U) & m8) ^ Td2_r((s3 >> 8U) & m8) ^ Td3_r(s2 & m8) ^ rk[45]; - t2 = Td0[s2 >> 24U] ^ Td1_r((s1 >> 16U) & m8) ^ Td2_r((s0 >> 8U) & m8) ^ Td3_r(s3 & m8) ^ rk[46]; - t3 = Td0[s3 >> 24U] ^ Td1_r((s2 >> 16U) & m8) ^ Td2_r((s1 >> 8U) & m8) ^ Td3_r(s0 & m8) ^ rk[47]; - s0 = Td0[t0 >> 24U] ^ Td1_r((t3 >> 16U) & m8) ^ Td2_r((t2 >> 8U) & m8) ^ Td3_r(t1 & m8) ^ rk[48]; - s1 = Td0[t1 >> 24U] ^ Td1_r((t0 >> 16U) & m8) ^ Td2_r((t3 >> 8U) & m8) ^ Td3_r(t2 & m8) ^ rk[49]; - s2 = Td0[t2 >> 24U] ^ Td1_r((t1 >> 16U) & m8) ^ Td2_r((t0 >> 8U) & m8) ^ Td3_r(t3 & m8) ^ rk[50]; - s3 = Td0[t3 >> 24U] ^ Td1_r((t2 >> 16U) & m8) ^ Td2_r((t1 >> 8U) & m8) ^ Td3_r(t0 & m8) ^ rk[51]; - t0 = Td0[s0 >> 24U] ^ Td1_r((s3 >> 16U) & m8) ^ Td2_r((s2 >> 8U) & m8) ^ Td3_r(s1 & m8) ^ rk[52]; - t1 = Td0[s1 >> 24U] ^ Td1_r((s0 >> 16U) & m8) ^ Td2_r((s3 >> 8U) & m8) ^ Td3_r(s2 & m8) ^ rk[53]; - t2 = Td0[s2 >> 24U] ^ Td1_r((s1 >> 16U) & m8) ^ Td2_r((s0 >> 8U) & m8) ^ Td3_r(s3 & m8) ^ rk[54]; - t3 = Td0[s3 >> 24U] ^ Td1_r((s2 >> 16U) & m8) ^ Td2_r((s1 >> 8U) & m8) ^ Td3_r(s0 & m8) ^ rk[55]; - s0 = (Td4[t0 >> 24U] << 24U) ^ (Td4[(t3 >> 16U) & m8] << 16U) ^ (Td4[(t2 >> 8U) & m8] << 8U) ^ (Td4[(t1) & m8]) ^ rk[56]; - s1 = (Td4[t1 >> 24U] << 24U) ^ (Td4[(t0 >> 16U) & m8] << 16U) ^ (Td4[(t3 >> 8U) & m8] << 8U) ^ (Td4[(t2) & m8]) ^ rk[57]; - s2 = (Td4[t2 >> 24U] << 24U) ^ (Td4[(t1 >> 16U) & m8] << 16U) ^ (Td4[(t0 >> 8U) & m8] << 8U) ^ (Td4[(t3) & m8]) ^ rk[58]; - s3 = (Td4[t3 >> 24U] << 24U) ^ (Td4[(t2 >> 16U) & m8] << 16U) ^ (Td4[(t1 >> 8U) & m8] << 8U) ^ (Td4[(t0) & m8]) ^ rk[59]; + uint32_t t0, t1, t2, t3; + t0 = Td0[s0 >> 24U] ^ Td1_r((s3 >> 16U) & m8) ^ Td2_r((s2 >> 8U) & m8) ^ Td3_r(s1 & m8) ^ rk[4]; + t1 = Td0[s1 >> 24U] ^ Td1_r((s0 >> 16U) & m8) ^ Td2_r((s3 >> 8U) & m8) ^ Td3_r(s2 & m8) ^ rk[5]; + t2 = Td0[s2 >> 24U] ^ Td1_r((s1 >> 16U) & m8) ^ Td2_r((s0 >> 8U) & m8) ^ Td3_r(s3 & m8) ^ rk[6]; + t3 = Td0[s3 >> 24U] ^ Td1_r((s2 >> 16U) & m8) ^ Td2_r((s1 >> 8U) & m8) ^ Td3_r(s0 & m8) ^ rk[7]; + s0 = Td0[t0 >> 24U] ^ Td1_r((t3 >> 16U) & m8) ^ Td2_r((t2 >> 8U) & m8) ^ Td3_r(t1 & m8) ^ rk[8]; + s1 = Td0[t1 >> 24U] ^ Td1_r((t0 >> 16U) & m8) ^ Td2_r((t3 >> 8U) & m8) ^ Td3_r(t2 & m8) ^ rk[9]; + s2 = Td0[t2 >> 24U] ^ Td1_r((t1 >> 16U) & m8) ^ Td2_r((t0 >> 8U) & m8) ^ Td3_r(t3 & m8) ^ rk[10]; + s3 = Td0[t3 >> 24U] ^ Td1_r((t2 >> 16U) & m8) ^ Td2_r((t1 >> 8U) & m8) ^ Td3_r(t0 & m8) ^ rk[11]; + t0 = Td0[s0 >> 24U] ^ Td1_r((s3 >> 16U) & m8) ^ Td2_r((s2 >> 8U) & m8) ^ Td3_r(s1 & m8) ^ rk[12]; + t1 = Td0[s1 >> 24U] ^ Td1_r((s0 >> 16U) & m8) ^ Td2_r((s3 >> 8U) & m8) ^ Td3_r(s2 & m8) ^ rk[13]; + t2 = Td0[s2 >> 24U] ^ Td1_r((s1 >> 16U) & m8) ^ Td2_r((s0 >> 8U) & m8) ^ Td3_r(s3 & m8) ^ rk[14]; + t3 = Td0[s3 >> 24U] ^ Td1_r((s2 >> 16U) & m8) ^ Td2_r((s1 >> 8U) & m8) ^ Td3_r(s0 & m8) ^ rk[15]; + s0 = Td0[t0 >> 24U] ^ Td1_r((t3 >> 16U) & m8) ^ Td2_r((t2 >> 8U) & m8) ^ Td3_r(t1 & m8) ^ rk[16]; + s1 = Td0[t1 >> 24U] ^ Td1_r((t0 >> 16U) & m8) ^ Td2_r((t3 >> 8U) & m8) ^ Td3_r(t2 & m8) ^ rk[17]; + s2 = Td0[t2 >> 24U] ^ Td1_r((t1 >> 16U) & m8) ^ Td2_r((t0 >> 8U) & m8) ^ Td3_r(t3 & m8) ^ rk[18]; + s3 = Td0[t3 >> 24U] ^ Td1_r((t2 >> 16U) & m8) ^ Td2_r((t1 >> 8U) & m8) ^ Td3_r(t0 & m8) ^ rk[19]; + t0 = Td0[s0 >> 24U] ^ Td1_r((s3 >> 16U) & m8) ^ Td2_r((s2 >> 8U) & m8) ^ Td3_r(s1 & m8) ^ rk[20]; + t1 = Td0[s1 >> 24U] ^ Td1_r((s0 >> 16U) & m8) ^ Td2_r((s3 >> 8U) & m8) ^ Td3_r(s2 & m8) ^ rk[21]; + t2 = Td0[s2 >> 24U] ^ Td1_r((s1 >> 16U) & m8) ^ Td2_r((s0 >> 8U) & m8) ^ Td3_r(s3 & m8) ^ rk[22]; + t3 = Td0[s3 >> 24U] ^ Td1_r((s2 >> 16U) & m8) ^ Td2_r((s1 >> 8U) & m8) ^ Td3_r(s0 & m8) ^ rk[23]; + s0 = Td0[t0 >> 24U] ^ Td1_r((t3 >> 16U) & m8) ^ Td2_r((t2 >> 8U) & m8) ^ Td3_r(t1 & m8) ^ rk[24]; + s1 = Td0[t1 >> 24U] ^ Td1_r((t0 >> 16U) & m8) ^ Td2_r((t3 >> 8U) & m8) ^ Td3_r(t2 & m8) ^ rk[25]; + s2 = Td0[t2 >> 24U] ^ Td1_r((t1 >> 16U) & m8) ^ Td2_r((t0 >> 8U) & m8) ^ Td3_r(t3 & m8) ^ rk[26]; + s3 = Td0[t3 >> 24U] ^ Td1_r((t2 >> 16U) & m8) ^ Td2_r((t1 >> 8U) & m8) ^ Td3_r(t0 & m8) ^ rk[27]; + t0 = Td0[s0 >> 24U] ^ Td1_r((s3 >> 16U) & m8) ^ Td2_r((s2 >> 8U) & m8) ^ Td3_r(s1 & m8) ^ rk[28]; + t1 = Td0[s1 >> 24U] ^ Td1_r((s0 >> 16U) & m8) ^ Td2_r((s3 >> 8U) & m8) ^ Td3_r(s2 & m8) ^ rk[29]; + t2 = Td0[s2 >> 24U] ^ Td1_r((s1 >> 16U) & m8) ^ Td2_r((s0 >> 8U) & m8) ^ Td3_r(s3 & m8) ^ rk[30]; + t3 = Td0[s3 >> 24U] ^ Td1_r((s2 >> 16U) & m8) ^ Td2_r((s1 >> 8U) & m8) ^ Td3_r(s0 & m8) ^ rk[31]; + s0 = Td0[t0 >> 24U] ^ Td1_r((t3 >> 16U) & m8) ^ Td2_r((t2 >> 8U) & m8) ^ Td3_r(t1 & m8) ^ rk[32]; + s1 = Td0[t1 >> 24U] ^ Td1_r((t0 >> 16U) & m8) ^ Td2_r((t3 >> 8U) & m8) ^ Td3_r(t2 & m8) ^ rk[33]; + s2 = Td0[t2 >> 24U] ^ Td1_r((t1 >> 16U) & m8) ^ Td2_r((t0 >> 8U) & m8) ^ Td3_r(t3 & m8) ^ rk[34]; + s3 = Td0[t3 >> 24U] ^ Td1_r((t2 >> 16U) & m8) ^ Td2_r((t1 >> 8U) & m8) ^ Td3_r(t0 & m8) ^ rk[35]; + t0 = Td0[s0 >> 24U] ^ Td1_r((s3 >> 16U) & m8) ^ Td2_r((s2 >> 8U) & m8) ^ Td3_r(s1 & m8) ^ rk[36]; + t1 = Td0[s1 >> 24U] ^ Td1_r((s0 >> 16U) & m8) ^ Td2_r((s3 >> 8U) & m8) ^ Td3_r(s2 & m8) ^ rk[37]; + t2 = Td0[s2 >> 24U] ^ Td1_r((s1 >> 16U) & m8) ^ Td2_r((s0 >> 8U) & m8) ^ Td3_r(s3 & m8) ^ rk[38]; + t3 = Td0[s3 >> 24U] ^ Td1_r((s2 >> 16U) & m8) ^ Td2_r((s1 >> 8U) & m8) ^ Td3_r(s0 & m8) ^ rk[39]; + s0 = Td0[t0 >> 24U] ^ Td1_r((t3 >> 16U) & m8) ^ Td2_r((t2 >> 8U) & m8) ^ Td3_r(t1 & m8) ^ rk[40]; + s1 = Td0[t1 >> 24U] ^ Td1_r((t0 >> 16U) & m8) ^ Td2_r((t3 >> 8U) & m8) ^ Td3_r(t2 & m8) ^ rk[41]; + s2 = Td0[t2 >> 24U] ^ Td1_r((t1 >> 16U) & m8) ^ Td2_r((t0 >> 8U) & m8) ^ Td3_r(t3 & m8) ^ rk[42]; + s3 = Td0[t3 >> 24U] ^ Td1_r((t2 >> 16U) & m8) ^ Td2_r((t1 >> 8U) & m8) ^ Td3_r(t0 & m8) ^ rk[43]; + t0 = Td0[s0 >> 24U] ^ Td1_r((s3 >> 16U) & m8) ^ Td2_r((s2 >> 8U) & m8) ^ Td3_r(s1 & m8) ^ rk[44]; + t1 = Td0[s1 >> 24U] ^ Td1_r((s0 >> 16U) & m8) ^ Td2_r((s3 >> 8U) & m8) ^ Td3_r(s2 & m8) ^ rk[45]; + t2 = Td0[s2 >> 24U] ^ Td1_r((s1 >> 16U) & m8) ^ Td2_r((s0 >> 8U) & m8) ^ Td3_r(s3 & m8) ^ rk[46]; + t3 = Td0[s3 >> 24U] ^ Td1_r((s2 >> 16U) & m8) ^ Td2_r((s1 >> 8U) & m8) ^ Td3_r(s0 & m8) ^ rk[47]; + s0 = Td0[t0 >> 24U] ^ Td1_r((t3 >> 16U) & m8) ^ Td2_r((t2 >> 8U) & m8) ^ Td3_r(t1 & m8) ^ rk[48]; + s1 = Td0[t1 >> 24U] ^ Td1_r((t0 >> 16U) & m8) ^ Td2_r((t3 >> 8U) & m8) ^ Td3_r(t2 & m8) ^ rk[49]; + s2 = Td0[t2 >> 24U] ^ Td1_r((t1 >> 16U) & m8) ^ Td2_r((t0 >> 8U) & m8) ^ Td3_r(t3 & m8) ^ rk[50]; + s3 = Td0[t3 >> 24U] ^ Td1_r((t2 >> 16U) & m8) ^ Td2_r((t1 >> 8U) & m8) ^ Td3_r(t0 & m8) ^ rk[51]; + t0 = Td0[s0 >> 24U] ^ Td1_r((s3 >> 16U) & m8) ^ Td2_r((s2 >> 8U) & m8) ^ Td3_r(s1 & m8) ^ rk[52]; + t1 = Td0[s1 >> 24U] ^ Td1_r((s0 >> 16U) & m8) ^ Td2_r((s3 >> 8U) & m8) ^ Td3_r(s2 & m8) ^ rk[53]; + t2 = Td0[s2 >> 24U] ^ Td1_r((s1 >> 16U) & m8) ^ Td2_r((s0 >> 8U) & m8) ^ Td3_r(s3 & m8) ^ rk[54]; + t3 = Td0[s3 >> 24U] ^ Td1_r((s2 >> 16U) & m8) ^ Td2_r((s1 >> 8U) & m8) ^ Td3_r(s0 & m8) ^ rk[55]; + s0 = (Td4[t0 >> 24U] << 24U) ^ (Td4[(t3 >> 16U) & m8] << 16U) ^ (Td4[(t2 >> 8U) & m8] << 8U) ^ (Td4[(t1)&m8]) ^ rk[56]; + s1 = (Td4[t1 >> 24U] << 24U) ^ (Td4[(t0 >> 16U) & m8] << 16U) ^ (Td4[(t3 >> 8U) & m8] << 8U) ^ (Td4[(t2)&m8]) ^ rk[57]; + s2 = (Td4[t2 >> 24U] << 24U) ^ (Td4[(t1 >> 16U) & m8] << 16U) ^ (Td4[(t0 >> 8U) & m8] << 8U) ^ (Td4[(t3)&m8]) ^ rk[58]; + s3 = (Td4[t3 >> 24U] << 24U) ^ (Td4[(t2 >> 16U) & m8] << 16U) ^ (Td4[(t1 >> 8U) & m8] << 8U) ^ (Td4[(t0)&m8]) ^ rk[59]; - Utils::storeBigEndian< uint32_t >(out, s0); - Utils::storeBigEndian< uint32_t >(out + 4, s1); - Utils::storeBigEndian< uint32_t >(out + 8, s2); - Utils::storeBigEndian< uint32_t >(out + 12, s3); + Utils::storeBigEndian(out, s0); + Utils::storeBigEndian(out + 4, s1); + Utils::storeBigEndian(out + 8, s2); + Utils::storeBigEndian(out + 12, s3); } -} // namespace ZeroTier +} // namespace ZeroTier diff --git a/node/AES.hpp b/node/AES.hpp index 70a68841..fdf5f189 100644 --- a/node/AES.hpp +++ b/node/AES.hpp @@ -15,16 +15,16 @@ #define ZT_AES_HPP #include "Constants.hpp" -#include "Utils.hpp" #include "SHA512.hpp" +#include "Utils.hpp" // Uncomment to disable all hardware acceleration (usually for testing) -//#define ZT_AES_NO_ACCEL +// #define ZT_AES_NO_ACCEL -#if !defined(ZT_AES_NO_ACCEL) && defined(ZT_ARCH_X64) +#if ! defined(ZT_AES_NO_ACCEL) && defined(ZT_ARCH_X64) #define ZT_AES_AESNI 1 #endif -#if !defined(ZT_AES_NO_ACCEL) && defined(ZT_ARCH_ARM_HAS_NEON) && defined(ZT_ARCH_ARM_HAS_CRYPTO) +#if ! defined(ZT_AES_NO_ACCEL) && defined(ZT_ARCH_ARM_HAS_NEON) && defined(ZT_ARCH_ARM_HAS_CRYPTO) #define ZT_AES_NEON 1 #endif @@ -40,558 +40,562 @@ namespace ZeroTier { * This includes hardware acceleration for certain processors. The software * mode is fallback and is significantly slower. */ -class AES -{ -public: - /** - * @return True if this system has hardware AES acceleration - */ - static ZT_INLINE bool accelerated() - { +class AES { + public: + /** + * @return True if this system has hardware AES acceleration + */ + static ZT_INLINE bool accelerated() + { #ifdef ZT_AES_AESNI - return Utils::CPUID.aes; + return Utils::CPUID.aes; #else #ifdef ZT_AES_NEON - return Utils::ARMCAP.aes; + return Utils::ARMCAP.aes; #else - return false; + return false; #endif #endif - } + } - /** - * Create an un-initialized AES instance (must call init() before use) - */ - ZT_INLINE AES() noexcept - {} + /** + * Create an un-initialized AES instance (must call init() before use) + */ + ZT_INLINE AES() noexcept + { + } - /** - * Create an AES instance with the given key - * - * @param key 256-bit key - */ - explicit ZT_INLINE AES(const void *const key) noexcept - { this->init(key); } + /** + * Create an AES instance with the given key + * + * @param key 256-bit key + */ + explicit ZT_INLINE AES(const void* const key) noexcept + { + this->init(key); + } - ZT_INLINE ~AES() - { Utils::burn(&p_k, sizeof(p_k)); } + ZT_INLINE ~AES() + { + Utils::burn(&p_k, sizeof(p_k)); + } - /** - * Set (or re-set) this AES256 cipher's key - * - * @param key 256-bit / 32-byte key - */ - ZT_INLINE void init(const void *const key) noexcept - { + /** + * Set (or re-set) this AES256 cipher's key + * + * @param key 256-bit / 32-byte key + */ + ZT_INLINE void init(const void* const key) noexcept + { #ifdef ZT_AES_AESNI - if (likely(Utils::CPUID.aes)) { - p_init_aesni(reinterpret_cast(key)); - return; - } + if (likely(Utils::CPUID.aes)) { + p_init_aesni(reinterpret_cast(key)); + return; + } #endif #ifdef ZT_AES_NEON - if (Utils::ARMCAP.aes) { - p_init_armneon_crypto(reinterpret_cast(key)); - return; - } + if (Utils::ARMCAP.aes) { + p_init_armneon_crypto(reinterpret_cast(key)); + return; + } #endif - p_initSW(reinterpret_cast(key)); - } + p_initSW(reinterpret_cast(key)); + } - /** - * Encrypt a single AES block - * - * @param in Input block - * @param out Output block (can be same as input) - */ - ZT_INLINE void encrypt(const void *const in, void *const out) const noexcept - { + /** + * Encrypt a single AES block + * + * @param in Input block + * @param out Output block (can be same as input) + */ + ZT_INLINE void encrypt(const void* const in, void* const out) const noexcept + { #ifdef ZT_AES_AESNI - if (likely(Utils::CPUID.aes)) { - p_encrypt_aesni(in, out); - return; - } + if (likely(Utils::CPUID.aes)) { + p_encrypt_aesni(in, out); + return; + } #endif #ifdef ZT_AES_NEON - if (Utils::ARMCAP.aes) { - p_encrypt_armneon_crypto(in, out); - return; - } + if (Utils::ARMCAP.aes) { + p_encrypt_armneon_crypto(in, out); + return; + } #endif - p_encryptSW(reinterpret_cast(in), reinterpret_cast(out)); - } + p_encryptSW(reinterpret_cast(in), reinterpret_cast(out)); + } - /** - * Decrypt a single AES block - * - * @param in Input block - * @param out Output block (can be same as input) - */ - ZT_INLINE void decrypt(const void *const in, void *const out) const noexcept - { + /** + * Decrypt a single AES block + * + * @param in Input block + * @param out Output block (can be same as input) + */ + ZT_INLINE void decrypt(const void* const in, void* const out) const noexcept + { #ifdef ZT_AES_AESNI - if (likely(Utils::CPUID.aes)) { - p_decrypt_aesni(in, out); - return; - } + if (likely(Utils::CPUID.aes)) { + p_decrypt_aesni(in, out); + return; + } #endif #ifdef ZT_AES_NEON - if (Utils::ARMCAP.aes) { - p_decrypt_armneon_crypto(in, out); - return; - } + if (Utils::ARMCAP.aes) { + p_decrypt_armneon_crypto(in, out); + return; + } #endif - p_decryptSW(reinterpret_cast(in), reinterpret_cast(out)); - } + p_decryptSW(reinterpret_cast(in), reinterpret_cast(out)); + } - class GMACSIVEncryptor; - class GMACSIVDecryptor; + class GMACSIVEncryptor; + class GMACSIVDecryptor; - /** - * Streaming GMAC calculator - */ - class GMAC - { - friend class GMACSIVEncryptor; - friend class GMACSIVDecryptor; + /** + * Streaming GMAC calculator + */ + class GMAC { + friend class GMACSIVEncryptor; + friend class GMACSIVDecryptor; - public: - /** - * @return True if this system has hardware GMAC acceleration - */ - static ZT_INLINE bool accelerated() - { + public: + /** + * @return True if this system has hardware GMAC acceleration + */ + static ZT_INLINE bool accelerated() + { #ifdef ZT_AES_AESNI - return Utils::CPUID.aes; + return Utils::CPUID.aes; #else #ifdef ZT_AES_NEON - return Utils::ARMCAP.pmull; + return Utils::ARMCAP.pmull; #else - return false; + return false; #endif #endif - } + } - /** - * Create a new instance of GMAC (must be initialized with init() before use) - * - * @param aes Keyed AES instance to use - */ - ZT_INLINE GMAC(const AES &aes) : _aes(aes) - {} + /** + * Create a new instance of GMAC (must be initialized with init() before use) + * + * @param aes Keyed AES instance to use + */ + ZT_INLINE GMAC(const AES& aes) : _aes(aes) + { + } - /** - * Reset and initialize for a new GMAC calculation - * - * @param iv 96-bit initialization vector (pad with zeroes if actual IV is shorter) - */ - ZT_INLINE void init(const uint8_t iv[12]) noexcept - { - _rp = 0; - _len = 0; - // We fill the least significant 32 bits in the _iv field with 1 since in GCM mode - // this would hold the counter, but we're not doing GCM. The counter is therefore - // always 1. -#ifdef ZT_AES_AESNI // also implies an x64 processor - *reinterpret_cast(_iv) = *reinterpret_cast(iv); - *reinterpret_cast(_iv + 8) = *reinterpret_cast(iv + 8); - *reinterpret_cast(_iv + 12) = 0x01000000; // 0x00000001 in big-endian byte order + /** + * Reset and initialize for a new GMAC calculation + * + * @param iv 96-bit initialization vector (pad with zeroes if actual IV is shorter) + */ + ZT_INLINE void init(const uint8_t iv[12]) noexcept + { + _rp = 0; + _len = 0; + // We fill the least significant 32 bits in the _iv field with 1 since in GCM mode + // this would hold the counter, but we're not doing GCM. The counter is therefore + // always 1. +#ifdef ZT_AES_AESNI // also implies an x64 processor + *reinterpret_cast(_iv) = *reinterpret_cast(iv); + *reinterpret_cast(_iv + 8) = *reinterpret_cast(iv + 8); + *reinterpret_cast(_iv + 12) = 0x01000000; // 0x00000001 in big-endian byte order #else - for(int i=0;i<12;++i) { - _iv[i] = iv[i]; - } - _iv[12] = 0; - _iv[13] = 0; - _iv[14] = 0; - _iv[15] = 1; + for (int i = 0; i < 12; ++i) { + _iv[i] = iv[i]; + } + _iv[12] = 0; + _iv[13] = 0; + _iv[14] = 0; + _iv[15] = 1; #endif - _y[0] = 0; - _y[1] = 0; - } + _y[0] = 0; + _y[1] = 0; + } - /** - * Process data through GMAC - * - * @param data Bytes to process - * @param len Length of input - */ - void update(const void *data, unsigned int len) noexcept; + /** + * Process data through GMAC + * + * @param data Bytes to process + * @param len Length of input + */ + void update(const void* data, unsigned int len) noexcept; - /** - * Process any remaining cached bytes and generate tag - * - * Don't call finish() more than once or you'll get an invalid result. - * - * @param tag 128-bit GMAC tag (can be truncated) - */ - void finish(uint8_t tag[16]) noexcept; + /** + * Process any remaining cached bytes and generate tag + * + * Don't call finish() more than once or you'll get an invalid result. + * + * @param tag 128-bit GMAC tag (can be truncated) + */ + void finish(uint8_t tag[16]) noexcept; - private: + private: #ifdef ZT_AES_AESNI - void p_aesNIUpdate(const uint8_t *in, unsigned int len) noexcept; - void p_aesNIFinish(uint8_t tag[16]) noexcept; + void p_aesNIUpdate(const uint8_t* in, unsigned int len) noexcept; + void p_aesNIFinish(uint8_t tag[16]) noexcept; #endif #ifdef ZT_AES_NEON - void p_armUpdate(const uint8_t *in, unsigned int len) noexcept; - void p_armFinish(uint8_t tag[16]) noexcept; + void p_armUpdate(const uint8_t* in, unsigned int len) noexcept; + void p_armFinish(uint8_t tag[16]) noexcept; #endif - const AES &_aes; - unsigned int _rp; - unsigned int _len; - uint8_t _r[16]; // remainder - uint8_t _iv[16]; - uint64_t _y[2]; - }; + const AES& _aes; + unsigned int _rp; + unsigned int _len; + uint8_t _r[16]; // remainder + uint8_t _iv[16]; + uint64_t _y[2]; + }; - /** - * Streaming AES-CTR encrypt/decrypt - * - * NOTE: this doesn't support overflow of the counter in the least significant 32 bits. - * AES-GMAC-CTR doesn't need this, so we don't support it as an optimization. - */ - class CTR - { - friend class GMACSIVEncryptor; - friend class GMACSIVDecryptor; + /** + * Streaming AES-CTR encrypt/decrypt + * + * NOTE: this doesn't support overflow of the counter in the least significant 32 bits. + * AES-GMAC-CTR doesn't need this, so we don't support it as an optimization. + */ + class CTR { + friend class GMACSIVEncryptor; + friend class GMACSIVDecryptor; - public: - ZT_INLINE CTR(const AES &aes) noexcept: _aes(aes) - {} + public: + ZT_INLINE CTR(const AES& aes) noexcept : _aes(aes) + { + } - /** - * Initialize this CTR instance to encrypt a new stream - * - * @param iv Unique initialization vector and initial 32-bit counter (least significant 32 bits, big-endian) - * @param output Buffer to which to store output (MUST be large enough for total bytes processed!) - */ - ZT_INLINE void init(const uint8_t iv[16], void *const output) noexcept - { - Utils::copy< 16 >(_ctr, iv); - _out = reinterpret_cast(output); - _len = 0; - } + /** + * Initialize this CTR instance to encrypt a new stream + * + * @param iv Unique initialization vector and initial 32-bit counter (least significant 32 bits, big-endian) + * @param output Buffer to which to store output (MUST be large enough for total bytes processed!) + */ + ZT_INLINE void init(const uint8_t iv[16], void* const output) noexcept + { + Utils::copy<16>(_ctr, iv); + _out = reinterpret_cast(output); + _len = 0; + } - /** - * Initialize this CTR instance to encrypt a new stream - * - * @param iv Unique initialization vector - * @param ic Initial counter (must be in big-endian byte order!) - * @param output Buffer to which to store output (MUST be large enough for total bytes processed!) - */ - ZT_INLINE void init(const uint8_t iv[12], const uint32_t ic, void *const output) noexcept - { - Utils::copy< 12 >(_ctr, iv); - reinterpret_cast(_ctr)[3] = ic; - _out = reinterpret_cast(output); - _len = 0; - } + /** + * Initialize this CTR instance to encrypt a new stream + * + * @param iv Unique initialization vector + * @param ic Initial counter (must be in big-endian byte order!) + * @param output Buffer to which to store output (MUST be large enough for total bytes processed!) + */ + ZT_INLINE void init(const uint8_t iv[12], const uint32_t ic, void* const output) noexcept + { + Utils::copy<12>(_ctr, iv); + reinterpret_cast(_ctr)[3] = ic; + _out = reinterpret_cast(output); + _len = 0; + } - /** - * Encrypt or decrypt data, writing result to the output provided to init() - * - * @param input Input data - * @param len Length of input - */ - void crypt(const void *input, unsigned int len) noexcept; + /** + * Encrypt or decrypt data, writing result to the output provided to init() + * + * @param input Input data + * @param len Length of input + */ + void crypt(const void* input, unsigned int len) noexcept; - /** - * Finish any remaining bytes if total bytes processed wasn't a multiple of 16 - * - * Don't call more than once for a given stream or data may be corrupted. - */ - void finish() noexcept; + /** + * Finish any remaining bytes if total bytes processed wasn't a multiple of 16 + * + * Don't call more than once for a given stream or data may be corrupted. + */ + void finish() noexcept; - private: + private: #ifdef ZT_AES_AESNI - void p_aesNICrypt(const uint8_t *in, uint8_t *out, unsigned int len) noexcept; + void p_aesNICrypt(const uint8_t* in, uint8_t* out, unsigned int len) noexcept; #endif #ifdef ZT_AES_NEON - void p_armCrypt(const uint8_t *in, uint8_t *out, unsigned int len) noexcept; + void p_armCrypt(const uint8_t* in, uint8_t* out, unsigned int len) noexcept; #endif - const AES &_aes; - uint64_t _ctr[2]; - uint8_t *_out; - unsigned int _len; - }; + const AES& _aes; + uint64_t _ctr[2]; + uint8_t* _out; + unsigned int _len; + }; - /** - * Encryptor for AES-GMAC-SIV. - * - * Encryption requires two passes. The first pass starts after init - * with aad (if any) followed by update1() and finish1(). Then the - * update2() and finish2() methods must be used over the same data - * (but NOT AAD) again. - * - * This supports encryption of a maximum of 2^31 bytes of data per - * call to init(). - */ - class GMACSIVEncryptor - { - public: - /** - * Create a new AES-GMAC-SIV encryptor keyed with the provided AES instances - * - * @param k0 First of two AES instances keyed with K0 - * @param k1 Second of two AES instances keyed with K1 - */ - ZT_INLINE GMACSIVEncryptor(const AES &k0, const AES &k1) noexcept : - _gmac(k0), - _ctr(k1) - {} + /** + * Encryptor for AES-GMAC-SIV. + * + * Encryption requires two passes. The first pass starts after init + * with aad (if any) followed by update1() and finish1(). Then the + * update2() and finish2() methods must be used over the same data + * (but NOT AAD) again. + * + * This supports encryption of a maximum of 2^31 bytes of data per + * call to init(). + */ + class GMACSIVEncryptor { + public: + /** + * Create a new AES-GMAC-SIV encryptor keyed with the provided AES instances + * + * @param k0 First of two AES instances keyed with K0 + * @param k1 Second of two AES instances keyed with K1 + */ + ZT_INLINE GMACSIVEncryptor(const AES& k0, const AES& k1) noexcept + : _gmac(k0) + , _ctr(k1) + { + } - /** - * Initialize AES-GMAC-SIV - * - * @param iv IV in network byte order (byte order in which it will appear on the wire) - * @param output Pointer to buffer to receive ciphertext, must be large enough for all to-be-processed data! - */ - ZT_INLINE void init(const uint64_t iv, void *const output) noexcept - { - // Output buffer to receive the result of AES-CTR encryption. - _output = output; + /** + * Initialize AES-GMAC-SIV + * + * @param iv IV in network byte order (byte order in which it will appear on the wire) + * @param output Pointer to buffer to receive ciphertext, must be large enough for all to-be-processed data! + */ + ZT_INLINE void init(const uint64_t iv, void* const output) noexcept + { + // Output buffer to receive the result of AES-CTR encryption. + _output = output; - // Initialize GMAC with 64-bit IV (and remaining 32 bits padded to zero). - _tag[0] = iv; - _tag[1] = 0; - _gmac.init(reinterpret_cast(_tag)); - } + // Initialize GMAC with 64-bit IV (and remaining 32 bits padded to zero). + _tag[0] = iv; + _tag[1] = 0; + _gmac.init(reinterpret_cast(_tag)); + } - /** - * Process AAD (additional authenticated data) that is not being encrypted. - * - * If such data exists this must be called before update1() and finish1(). - * - * Note: current code only supports one single chunk of AAD. Don't call this - * multiple times per message. - * - * @param aad Additional authenticated data - * @param len Length of AAD in bytes - */ - ZT_INLINE void aad(const void *const aad, unsigned int len) noexcept - { - // Feed ADD into GMAC first - _gmac.update(aad, len); + /** + * Process AAD (additional authenticated data) that is not being encrypted. + * + * If such data exists this must be called before update1() and finish1(). + * + * Note: current code only supports one single chunk of AAD. Don't call this + * multiple times per message. + * + * @param aad Additional authenticated data + * @param len Length of AAD in bytes + */ + ZT_INLINE void aad(const void* const aad, unsigned int len) noexcept + { + // Feed ADD into GMAC first + _gmac.update(aad, len); - // End of AAD is padded to a multiple of 16 bytes to ensure unique encoding. - len &= 0xfU; - if (len != 0) { - _gmac.update(Utils::ZERO256, 16 - len); - } - } + // End of AAD is padded to a multiple of 16 bytes to ensure unique encoding. + len &= 0xfU; + if (len != 0) { + _gmac.update(Utils::ZERO256, 16 - len); + } + } - /** - * First pass plaintext input function - * - * @param input Plaintext chunk - * @param len Length of plaintext chunk - */ - ZT_INLINE void update1(const void *const input, const unsigned int len) noexcept - { _gmac.update(input, len); } + /** + * First pass plaintext input function + * + * @param input Plaintext chunk + * @param len Length of plaintext chunk + */ + ZT_INLINE void update1(const void* const input, const unsigned int len) noexcept + { + _gmac.update(input, len); + } - /** - * Finish first pass, compute CTR IV, initialize second pass. - */ - ZT_INLINE void finish1() noexcept - { - // Compute 128-bit GMAC tag. - uint64_t tmp[2]; - _gmac.finish(reinterpret_cast(tmp)); + /** + * Finish first pass, compute CTR IV, initialize second pass. + */ + ZT_INLINE void finish1() noexcept + { + // Compute 128-bit GMAC tag. + uint64_t tmp[2]; + _gmac.finish(reinterpret_cast(tmp)); - // Shorten to 64 bits, concatenate with message IV, and encrypt with AES to - // yield the CTR IV and opaque IV/MAC blob. In ZeroTier's use of GMAC-SIV - // this get split into the packet ID (64 bits) and the MAC (64 bits) in each - // packet and then recombined on receipt for legacy reasons (but with no - // cryptographic or performance impact). - _tag[1] = tmp[0] ^ tmp[1]; - _ctr._aes.encrypt(_tag, _tag); + // Shorten to 64 bits, concatenate with message IV, and encrypt with AES to + // yield the CTR IV and opaque IV/MAC blob. In ZeroTier's use of GMAC-SIV + // this get split into the packet ID (64 bits) and the MAC (64 bits) in each + // packet and then recombined on receipt for legacy reasons (but with no + // cryptographic or performance impact). + _tag[1] = tmp[0] ^ tmp[1]; + _ctr._aes.encrypt(_tag, _tag); - // Initialize CTR with 96-bit CTR nonce and 32-bit counter. The counter - // incorporates 31 more bits of entropy which should raise our security margin - // a bit, but this is not included in the worst case analysis of GMAC-SIV. - // The most significant bit of the counter is masked to zero to allow up to - // 2^31 bytes to be encrypted before the counter loops. Some CTR implementations - // increment the whole big-endian 128-bit integer in which case this could be - // used for more than 2^31 bytes, but ours does not for performance reasons - // and so 2^31 should be considered the input limit. - tmp[0] = _tag[0]; - tmp[1] = _tag[1] & ZT_CONST_TO_BE_UINT64(0xffffffff7fffffffULL); - _ctr.init(reinterpret_cast(tmp), _output); - } + // Initialize CTR with 96-bit CTR nonce and 32-bit counter. The counter + // incorporates 31 more bits of entropy which should raise our security margin + // a bit, but this is not included in the worst case analysis of GMAC-SIV. + // The most significant bit of the counter is masked to zero to allow up to + // 2^31 bytes to be encrypted before the counter loops. Some CTR implementations + // increment the whole big-endian 128-bit integer in which case this could be + // used for more than 2^31 bytes, but ours does not for performance reasons + // and so 2^31 should be considered the input limit. + tmp[0] = _tag[0]; + tmp[1] = _tag[1] & ZT_CONST_TO_BE_UINT64(0xffffffff7fffffffULL); + _ctr.init(reinterpret_cast(tmp), _output); + } - /** - * Second pass plaintext input function - * - * The same plaintext must be fed in the second time in the same order, - * though chunk boundaries do not have to be the same. - * - * @param input Plaintext chunk - * @param len Length of plaintext chunk - */ - ZT_INLINE void update2(const void *const input, const unsigned int len) noexcept - { _ctr.crypt(input, len); } + /** + * Second pass plaintext input function + * + * The same plaintext must be fed in the second time in the same order, + * though chunk boundaries do not have to be the same. + * + * @param input Plaintext chunk + * @param len Length of plaintext chunk + */ + ZT_INLINE void update2(const void* const input, const unsigned int len) noexcept + { + _ctr.crypt(input, len); + } - /** - * Finish second pass and return a pointer to the opaque 128-bit IV+MAC block - * - * The returned pointer remains valid as long as this object exists and init() - * is not called again. - * - * @return Pointer to 128-bit opaque IV+MAC (packed into two 64-bit integers) - */ - ZT_INLINE const uint64_t *finish2() - { - _ctr.finish(); - return _tag; - } + /** + * Finish second pass and return a pointer to the opaque 128-bit IV+MAC block + * + * The returned pointer remains valid as long as this object exists and init() + * is not called again. + * + * @return Pointer to 128-bit opaque IV+MAC (packed into two 64-bit integers) + */ + ZT_INLINE const uint64_t* finish2() + { + _ctr.finish(); + return _tag; + } - private: - void *_output; - uint64_t _tag[2]; - AES::GMAC _gmac; - AES::CTR _ctr; - }; + private: + void* _output; + uint64_t _tag[2]; + AES::GMAC _gmac; + AES::CTR _ctr; + }; - /** - * Decryptor for AES-GMAC-SIV. - * - * GMAC-SIV decryption is single-pass. AAD (if any) must be processed first. - */ - class GMACSIVDecryptor - { - public: - ZT_INLINE GMACSIVDecryptor(const AES &k0, const AES &k1) noexcept: - _ctr(k1), - _gmac(k0) - {} + /** + * Decryptor for AES-GMAC-SIV. + * + * GMAC-SIV decryption is single-pass. AAD (if any) must be processed first. + */ + class GMACSIVDecryptor { + public: + ZT_INLINE GMACSIVDecryptor(const AES& k0, const AES& k1) noexcept + : _ctr(k1) + , _gmac(k0) + { + } - /** - * Initialize decryptor for a new message - * - * @param tag 128-bit combined IV/MAC originally created by GMAC-SIV encryption - * @param output Buffer in which to write output plaintext (must be large enough!) - */ - ZT_INLINE void init(const uint64_t tag[2], void *const output) noexcept - { - uint64_t tmp[2]; - tmp[0] = tag[0]; - tmp[1] = tag[1] & ZT_CONST_TO_BE_UINT64(0xffffffff7fffffffULL); - _ctr.init(reinterpret_cast(tmp), output); + /** + * Initialize decryptor for a new message + * + * @param tag 128-bit combined IV/MAC originally created by GMAC-SIV encryption + * @param output Buffer in which to write output plaintext (must be large enough!) + */ + ZT_INLINE void init(const uint64_t tag[2], void* const output) noexcept + { + uint64_t tmp[2]; + tmp[0] = tag[0]; + tmp[1] = tag[1] & ZT_CONST_TO_BE_UINT64(0xffffffff7fffffffULL); + _ctr.init(reinterpret_cast(tmp), output); - _ctr._aes.decrypt(tag, _ivMac); + _ctr._aes.decrypt(tag, _ivMac); - tmp[0] = _ivMac[0]; - tmp[1] = 0; - _gmac.init(reinterpret_cast(tmp)); + tmp[0] = _ivMac[0]; + tmp[1] = 0; + _gmac.init(reinterpret_cast(tmp)); - _output = output; - _decryptedLen = 0; - } + _output = output; + _decryptedLen = 0; + } - /** - * Process AAD (additional authenticated data) that wasn't encrypted - * - * @param aad Additional authenticated data - * @param len Length of AAD in bytes - */ - ZT_INLINE void aad(const void *const aad, unsigned int len) noexcept - { - _gmac.update(aad, len); - len &= 0xfU; - if (len != 0) { - _gmac.update(Utils::ZERO256, 16 - len); - } - } + /** + * Process AAD (additional authenticated data) that wasn't encrypted + * + * @param aad Additional authenticated data + * @param len Length of AAD in bytes + */ + ZT_INLINE void aad(const void* const aad, unsigned int len) noexcept + { + _gmac.update(aad, len); + len &= 0xfU; + if (len != 0) { + _gmac.update(Utils::ZERO256, 16 - len); + } + } - /** - * Feed ciphertext into the decryptor - * - * Unlike encryption, GMAC-SIV decryption requires only one pass. - * - * @param input Input ciphertext - * @param len Length of ciphertext - */ - ZT_INLINE void update(const void *const input, const unsigned int len) noexcept - { - _ctr.crypt(input, len); - _decryptedLen += len; - } + /** + * Feed ciphertext into the decryptor + * + * Unlike encryption, GMAC-SIV decryption requires only one pass. + * + * @param input Input ciphertext + * @param len Length of ciphertext + */ + ZT_INLINE void update(const void* const input, const unsigned int len) noexcept + { + _ctr.crypt(input, len); + _decryptedLen += len; + } - /** - * Flush decryption, compute MAC, and verify - * - * @return True if resulting plaintext (and AAD) pass message authentication check - */ - ZT_INLINE bool finish() noexcept - { - _ctr.finish(); + /** + * Flush decryption, compute MAC, and verify + * + * @return True if resulting plaintext (and AAD) pass message authentication check + */ + ZT_INLINE bool finish() noexcept + { + _ctr.finish(); - uint64_t gmacTag[2]; - _gmac.update(_output, _decryptedLen); - _gmac.finish(reinterpret_cast(gmacTag)); - return (gmacTag[0] ^ gmacTag[1]) == _ivMac[1]; - } + uint64_t gmacTag[2]; + _gmac.update(_output, _decryptedLen); + _gmac.finish(reinterpret_cast(gmacTag)); + return (gmacTag[0] ^ gmacTag[1]) == _ivMac[1]; + } - private: - uint64_t _ivMac[2]; - AES::CTR _ctr; - AES::GMAC _gmac; - void *_output; - unsigned int _decryptedLen; - }; + private: + uint64_t _ivMac[2]; + AES::CTR _ctr; + AES::GMAC _gmac; + void* _output; + unsigned int _decryptedLen; + }; -private: - static const uint32_t Te0[256]; - static const uint32_t Te4[256]; - static const uint32_t Td0[256]; - static const uint8_t Td4[256]; - static const uint32_t rcon[15]; + private: + static const uint32_t Te0[256]; + static const uint32_t Te4[256]; + static const uint32_t Td0[256]; + static const uint8_t Td4[256]; + static const uint32_t rcon[15]; - void p_initSW(const uint8_t *key) noexcept; - void p_encryptSW(const uint8_t *in, uint8_t *out) const noexcept; - void p_decryptSW(const uint8_t *in, uint8_t *out) const noexcept; + void p_initSW(const uint8_t* key) noexcept; + void p_encryptSW(const uint8_t* in, uint8_t* out) const noexcept; + void p_decryptSW(const uint8_t* in, uint8_t* out) const noexcept; - union - { + union { #ifdef ZT_AES_AESNI - struct - { - __m128i k[28]; - __m128i h[4]; // h, hh, hhh, hhhh - __m128i h2[4]; // _mm_xor_si128(_mm_shuffle_epi32(h, 78), h), etc. - } ni; + struct { + __m128i k[28]; + __m128i h[4]; // h, hh, hhh, hhhh + __m128i h2[4]; // _mm_xor_si128(_mm_shuffle_epi32(h, 78), h), etc. + } ni; #endif #ifdef ZT_AES_NEON - struct - { - uint64_t hsw[2]; // in case it has AES but not PMULL, not sure if that ever happens - uint8x16_t ek[15]; - uint8x16_t dk[15]; - uint8x16_t h; - } neon; + struct { + uint64_t hsw[2]; // in case it has AES but not PMULL, not sure if that ever happens + uint8x16_t ek[15]; + uint8x16_t dk[15]; + uint8x16_t h; + } neon; #endif - struct - { - uint64_t h[2]; - uint32_t ek[60]; - uint32_t dk[60]; - } sw; - } p_k; + struct { + uint64_t h[2]; + uint32_t ek[60]; + uint32_t dk[60]; + } sw; + } p_k; #ifdef ZT_AES_AESNI - void p_init_aesni(const uint8_t *key) noexcept; - void p_encrypt_aesni(const void *in, void *out) const noexcept; - void p_decrypt_aesni(const void *in, void *out) const noexcept; + void p_init_aesni(const uint8_t* key) noexcept; + void p_encrypt_aesni(const void* in, void* out) const noexcept; + void p_decrypt_aesni(const void* in, void* out) const noexcept; #endif #ifdef ZT_AES_NEON - void p_init_armneon_crypto(const uint8_t *key) noexcept; - void p_encrypt_armneon_crypto(const void *in, void *out) const noexcept; - void p_decrypt_armneon_crypto(const void *in, void *out) const noexcept; + void p_init_armneon_crypto(const uint8_t* key) noexcept; + void p_encrypt_armneon_crypto(const void* in, void* out) const noexcept; + void p_decrypt_armneon_crypto(const void* in, void* out) const noexcept; #endif }; -} // namespace ZeroTier +} // namespace ZeroTier #endif diff --git a/node/AES_aesni.cpp b/node/AES_aesni.cpp index c8de46df..2b4544d1 100644 --- a/node/AES_aesni.cpp +++ b/node/AES_aesni.cpp @@ -11,8 +11,8 @@ */ /****/ -#include "Constants.hpp" #include "AES.hpp" +#include "Constants.hpp" #ifdef ZT_AES_AESNI @@ -29,25 +29,26 @@ const __m128i s_sseSwapBytes = _mm_set_epi8(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 #ifdef __GNUC__ __attribute__((__target__("ssse3,sse4,sse4.1,sse4.2,pclmul"))) #endif -__m128i p_gmacPCLMUL128(const __m128i h, __m128i y) noexcept +__m128i +p_gmacPCLMUL128(const __m128i h, __m128i y) noexcept { - y = _mm_shuffle_epi8(y, s_sseSwapBytes); - __m128i t1 = _mm_clmulepi64_si128(h, y, 0x00); - __m128i t2 = _mm_clmulepi64_si128(h, y, 0x01); - __m128i t3 = _mm_clmulepi64_si128(h, y, 0x10); - __m128i t4 = _mm_clmulepi64_si128(h, y, 0x11); - t2 = _mm_xor_si128(t2, t3); - t3 = _mm_slli_si128(t2, 8); - t2 = _mm_srli_si128(t2, 8); - t1 = _mm_xor_si128(t1, t3); - t4 = _mm_xor_si128(t4, t2); - __m128i t5 = _mm_srli_epi32(t1, 31); - t1 = _mm_or_si128(_mm_slli_epi32(t1, 1), _mm_slli_si128(t5, 4)); - t4 = _mm_or_si128(_mm_or_si128(_mm_slli_epi32(t4, 1), _mm_slli_si128(_mm_srli_epi32(t4, 31), 4)), _mm_srli_si128(t5, 12)); - t5 = _mm_xor_si128(_mm_xor_si128(_mm_slli_epi32(t1, 31), _mm_slli_epi32(t1, 30)), _mm_slli_epi32(t1, 25)); - t1 = _mm_xor_si128(t1, _mm_slli_si128(t5, 12)); - t4 = _mm_xor_si128(_mm_xor_si128(_mm_xor_si128(_mm_xor_si128(_mm_xor_si128(t4, _mm_srli_si128(t5, 4)), t1), _mm_srli_epi32(t1, 2)), _mm_srli_epi32(t1, 7)), _mm_srli_epi32(t1, 1)); - return _mm_shuffle_epi8(t4, s_sseSwapBytes); + y = _mm_shuffle_epi8(y, s_sseSwapBytes); + __m128i t1 = _mm_clmulepi64_si128(h, y, 0x00); + __m128i t2 = _mm_clmulepi64_si128(h, y, 0x01); + __m128i t3 = _mm_clmulepi64_si128(h, y, 0x10); + __m128i t4 = _mm_clmulepi64_si128(h, y, 0x11); + t2 = _mm_xor_si128(t2, t3); + t3 = _mm_slli_si128(t2, 8); + t2 = _mm_srli_si128(t2, 8); + t1 = _mm_xor_si128(t1, t3); + t4 = _mm_xor_si128(t4, t2); + __m128i t5 = _mm_srli_epi32(t1, 31); + t1 = _mm_or_si128(_mm_slli_epi32(t1, 1), _mm_slli_si128(t5, 4)); + t4 = _mm_or_si128(_mm_or_si128(_mm_slli_epi32(t4, 1), _mm_slli_si128(_mm_srli_epi32(t4, 31), 4)), _mm_srli_si128(t5, 12)); + t5 = _mm_xor_si128(_mm_xor_si128(_mm_slli_epi32(t1, 31), _mm_slli_epi32(t1, 30)), _mm_slli_epi32(t1, 25)); + t1 = _mm_xor_si128(t1, _mm_slli_si128(t5, 12)); + t4 = _mm_xor_si128(_mm_xor_si128(_mm_xor_si128(_mm_xor_si128(_mm_xor_si128(t4, _mm_srli_si128(t5, 4)), t1), _mm_srli_epi32(t1, 2)), _mm_srli_epi32(t1, 7)), _mm_srli_epi32(t1, 1)); + return _mm_shuffle_epi8(t4, s_sseSwapBytes); } /* Disable VAES stuff on compilers too old to compile these intrinsics, @@ -55,7 +56,7 @@ __m128i p_gmacPCLMUL128(const __m128i h, __m128i y) noexcept * The performance gain can be significant but regular SSE is already so * fast it's highly unlikely to be a rate limiting factor except on massive * servers and network infrastructure stuff. */ -#if !defined(__WINDOWS__) && ((__GNUC__ >= 8) || (__clang_major__ >= 7)) +#if ! defined(__WINDOWS__) && ((__GNUC__ >= 8) || (__clang_major__ >= 7)) #define ZT_AES_VAES512 1 @@ -64,49 +65,45 @@ __attribute__((__target__("sse4,aes,avx,avx2,vaes,avx512f,avx512bw"))) #endif void p_aesCtrInnerVAES512(unsigned int &len, const uint64_t c0, uint64_t &c1, const uint8_t *&in, uint8_t *&out, const __m128i *const k) noexcept { - const __m512i kk0 = _mm512_broadcast_i32x4(k[0]); - const __m512i kk1 = _mm512_broadcast_i32x4(k[1]); - const __m512i kk2 = _mm512_broadcast_i32x4(k[2]); - const __m512i kk3 = _mm512_broadcast_i32x4(k[3]); - const __m512i kk4 = _mm512_broadcast_i32x4(k[4]); - const __m512i kk5 = _mm512_broadcast_i32x4(k[5]); - const __m512i kk6 = _mm512_broadcast_i32x4(k[6]); - const __m512i kk7 = _mm512_broadcast_i32x4(k[7]); - const __m512i kk8 = _mm512_broadcast_i32x4(k[8]); - const __m512i kk9 = _mm512_broadcast_i32x4(k[9]); - const __m512i kk10 = _mm512_broadcast_i32x4(k[10]); - const __m512i kk11 = _mm512_broadcast_i32x4(k[11]); - const __m512i kk12 = _mm512_broadcast_i32x4(k[12]); - const __m512i kk13 = _mm512_broadcast_i32x4(k[13]); - const __m512i kk14 = _mm512_broadcast_i32x4(k[14]); - do { - __m512i p0 = _mm512_loadu_si512(reinterpret_cast(in)); - __m512i d0 = _mm512_set_epi64( - (long long)Utils::hton(c1 + 3ULL), (long long)c0, - (long long)Utils::hton(c1 + 2ULL), (long long)c0, - (long long)Utils::hton(c1 + 1ULL), (long long)c0, - (long long)Utils::hton(c1), (long long)c0); - c1 += 4; - in += 64; - len -= 64; - d0 = _mm512_xor_si512(d0, kk0); - d0 = _mm512_aesenc_epi128(d0, kk1); - d0 = _mm512_aesenc_epi128(d0, kk2); - d0 = _mm512_aesenc_epi128(d0, kk3); - d0 = _mm512_aesenc_epi128(d0, kk4); - d0 = _mm512_aesenc_epi128(d0, kk5); - d0 = _mm512_aesenc_epi128(d0, kk6); - d0 = _mm512_aesenc_epi128(d0, kk7); - d0 = _mm512_aesenc_epi128(d0, kk8); - d0 = _mm512_aesenc_epi128(d0, kk9); - d0 = _mm512_aesenc_epi128(d0, kk10); - d0 = _mm512_aesenc_epi128(d0, kk11); - d0 = _mm512_aesenc_epi128(d0, kk12); - d0 = _mm512_aesenc_epi128(d0, kk13); - d0 = _mm512_aesenclast_epi128(d0, kk14); - _mm512_storeu_si512(reinterpret_cast<__m512i *>(out), _mm512_xor_si512(p0, d0)); - out += 64; - } while (likely(len >= 64)); + const __m512i kk0 = _mm512_broadcast_i32x4(k[0]); + const __m512i kk1 = _mm512_broadcast_i32x4(k[1]); + const __m512i kk2 = _mm512_broadcast_i32x4(k[2]); + const __m512i kk3 = _mm512_broadcast_i32x4(k[3]); + const __m512i kk4 = _mm512_broadcast_i32x4(k[4]); + const __m512i kk5 = _mm512_broadcast_i32x4(k[5]); + const __m512i kk6 = _mm512_broadcast_i32x4(k[6]); + const __m512i kk7 = _mm512_broadcast_i32x4(k[7]); + const __m512i kk8 = _mm512_broadcast_i32x4(k[8]); + const __m512i kk9 = _mm512_broadcast_i32x4(k[9]); + const __m512i kk10 = _mm512_broadcast_i32x4(k[10]); + const __m512i kk11 = _mm512_broadcast_i32x4(k[11]); + const __m512i kk12 = _mm512_broadcast_i32x4(k[12]); + const __m512i kk13 = _mm512_broadcast_i32x4(k[13]); + const __m512i kk14 = _mm512_broadcast_i32x4(k[14]); + do { + __m512i p0 = _mm512_loadu_si512(reinterpret_cast(in)); + __m512i d0 = _mm512_set_epi64((long long)Utils::hton(c1 + 3ULL), (long long)c0, (long long)Utils::hton(c1 + 2ULL), (long long)c0, (long long)Utils::hton(c1 + 1ULL), (long long)c0, (long long)Utils::hton(c1), (long long)c0); + c1 += 4; + in += 64; + len -= 64; + d0 = _mm512_xor_si512(d0, kk0); + d0 = _mm512_aesenc_epi128(d0, kk1); + d0 = _mm512_aesenc_epi128(d0, kk2); + d0 = _mm512_aesenc_epi128(d0, kk3); + d0 = _mm512_aesenc_epi128(d0, kk4); + d0 = _mm512_aesenc_epi128(d0, kk5); + d0 = _mm512_aesenc_epi128(d0, kk6); + d0 = _mm512_aesenc_epi128(d0, kk7); + d0 = _mm512_aesenc_epi128(d0, kk8); + d0 = _mm512_aesenc_epi128(d0, kk9); + d0 = _mm512_aesenc_epi128(d0, kk10); + d0 = _mm512_aesenc_epi128(d0, kk11); + d0 = _mm512_aesenc_epi128(d0, kk12); + d0 = _mm512_aesenc_epi128(d0, kk13); + d0 = _mm512_aesenclast_epi128(d0, kk14); + _mm512_storeu_si512(reinterpret_cast<__m512i*>(out), _mm512_xor_si512(p0, d0)); + out += 64; + } while (likely(len >= 64)); } #define ZT_AES_VAES256 1 @@ -116,176 +113,178 @@ __attribute__((__target__("sse4,aes,avx,avx2,vaes"))) #endif void p_aesCtrInnerVAES256(unsigned int &len, const uint64_t c0, uint64_t &c1, const uint8_t *&in, uint8_t *&out, const __m128i *const k) noexcept { - const __m256i kk0 = _mm256_broadcastsi128_si256(k[0]); - const __m256i kk1 = _mm256_broadcastsi128_si256(k[1]); - const __m256i kk2 = _mm256_broadcastsi128_si256(k[2]); - const __m256i kk3 = _mm256_broadcastsi128_si256(k[3]); - const __m256i kk4 = _mm256_broadcastsi128_si256(k[4]); - const __m256i kk5 = _mm256_broadcastsi128_si256(k[5]); - const __m256i kk6 = _mm256_broadcastsi128_si256(k[6]); - const __m256i kk7 = _mm256_broadcastsi128_si256(k[7]); - const __m256i kk8 = _mm256_broadcastsi128_si256(k[8]); - const __m256i kk9 = _mm256_broadcastsi128_si256(k[9]); - const __m256i kk10 = _mm256_broadcastsi128_si256(k[10]); - const __m256i kk11 = _mm256_broadcastsi128_si256(k[11]); - const __m256i kk12 = _mm256_broadcastsi128_si256(k[12]); - const __m256i kk13 = _mm256_broadcastsi128_si256(k[13]); - const __m256i kk14 = _mm256_broadcastsi128_si256(k[14]); - do { - __m256i p0 = _mm256_loadu_si256(reinterpret_cast(in)); - __m256i p1 = _mm256_loadu_si256(reinterpret_cast(in + 32)); - __m256i d0 = _mm256_set_epi64x( - (long long)Utils::hton(c1 + 1ULL), (long long)c0, - (long long)Utils::hton(c1), (long long)c0); - __m256i d1 = _mm256_set_epi64x( - (long long)Utils::hton(c1 + 3ULL), (long long)c0, - (long long)Utils::hton(c1 + 2ULL), (long long)c0); - c1 += 4; - in += 64; - len -= 64; - d0 = _mm256_xor_si256(d0, kk0); - d1 = _mm256_xor_si256(d1, kk0); - d0 = _mm256_aesenc_epi128(d0, kk1); - d1 = _mm256_aesenc_epi128(d1, kk1); - d0 = _mm256_aesenc_epi128(d0, kk2); - d1 = _mm256_aesenc_epi128(d1, kk2); - d0 = _mm256_aesenc_epi128(d0, kk3); - d1 = _mm256_aesenc_epi128(d1, kk3); - d0 = _mm256_aesenc_epi128(d0, kk4); - d1 = _mm256_aesenc_epi128(d1, kk4); - d0 = _mm256_aesenc_epi128(d0, kk5); - d1 = _mm256_aesenc_epi128(d1, kk5); - d0 = _mm256_aesenc_epi128(d0, kk6); - d1 = _mm256_aesenc_epi128(d1, kk6); - d0 = _mm256_aesenc_epi128(d0, kk7); - d1 = _mm256_aesenc_epi128(d1, kk7); - d0 = _mm256_aesenc_epi128(d0, kk8); - d1 = _mm256_aesenc_epi128(d1, kk8); - d0 = _mm256_aesenc_epi128(d0, kk9); - d1 = _mm256_aesenc_epi128(d1, kk9); - d0 = _mm256_aesenc_epi128(d0, kk10); - d1 = _mm256_aesenc_epi128(d1, kk10); - d0 = _mm256_aesenc_epi128(d0, kk11); - d1 = _mm256_aesenc_epi128(d1, kk11); - d0 = _mm256_aesenc_epi128(d0, kk12); - d1 = _mm256_aesenc_epi128(d1, kk12); - d0 = _mm256_aesenc_epi128(d0, kk13); - d1 = _mm256_aesenc_epi128(d1, kk13); - d0 = _mm256_aesenclast_epi128(d0, kk14); - d1 = _mm256_aesenclast_epi128(d1, kk14); - _mm256_storeu_si256(reinterpret_cast<__m256i *>(out), _mm256_xor_si256(d0, p0)); - _mm256_storeu_si256(reinterpret_cast<__m256i *>(out + 32), _mm256_xor_si256(d1, p1)); - out += 64; - } while (likely(len >= 64)); + const __m256i kk0 = _mm256_broadcastsi128_si256(k[0]); + const __m256i kk1 = _mm256_broadcastsi128_si256(k[1]); + const __m256i kk2 = _mm256_broadcastsi128_si256(k[2]); + const __m256i kk3 = _mm256_broadcastsi128_si256(k[3]); + const __m256i kk4 = _mm256_broadcastsi128_si256(k[4]); + const __m256i kk5 = _mm256_broadcastsi128_si256(k[5]); + const __m256i kk6 = _mm256_broadcastsi128_si256(k[6]); + const __m256i kk7 = _mm256_broadcastsi128_si256(k[7]); + const __m256i kk8 = _mm256_broadcastsi128_si256(k[8]); + const __m256i kk9 = _mm256_broadcastsi128_si256(k[9]); + const __m256i kk10 = _mm256_broadcastsi128_si256(k[10]); + const __m256i kk11 = _mm256_broadcastsi128_si256(k[11]); + const __m256i kk12 = _mm256_broadcastsi128_si256(k[12]); + const __m256i kk13 = _mm256_broadcastsi128_si256(k[13]); + const __m256i kk14 = _mm256_broadcastsi128_si256(k[14]); + do { + __m256i p0 = _mm256_loadu_si256(reinterpret_cast(in)); + __m256i p1 = _mm256_loadu_si256(reinterpret_cast(in + 32)); + __m256i d0 = _mm256_set_epi64x((long long)Utils::hton(c1 + 1ULL), (long long)c0, (long long)Utils::hton(c1), (long long)c0); + __m256i d1 = _mm256_set_epi64x((long long)Utils::hton(c1 + 3ULL), (long long)c0, (long long)Utils::hton(c1 + 2ULL), (long long)c0); + c1 += 4; + in += 64; + len -= 64; + d0 = _mm256_xor_si256(d0, kk0); + d1 = _mm256_xor_si256(d1, kk0); + d0 = _mm256_aesenc_epi128(d0, kk1); + d1 = _mm256_aesenc_epi128(d1, kk1); + d0 = _mm256_aesenc_epi128(d0, kk2); + d1 = _mm256_aesenc_epi128(d1, kk2); + d0 = _mm256_aesenc_epi128(d0, kk3); + d1 = _mm256_aesenc_epi128(d1, kk3); + d0 = _mm256_aesenc_epi128(d0, kk4); + d1 = _mm256_aesenc_epi128(d1, kk4); + d0 = _mm256_aesenc_epi128(d0, kk5); + d1 = _mm256_aesenc_epi128(d1, kk5); + d0 = _mm256_aesenc_epi128(d0, kk6); + d1 = _mm256_aesenc_epi128(d1, kk6); + d0 = _mm256_aesenc_epi128(d0, kk7); + d1 = _mm256_aesenc_epi128(d1, kk7); + d0 = _mm256_aesenc_epi128(d0, kk8); + d1 = _mm256_aesenc_epi128(d1, kk8); + d0 = _mm256_aesenc_epi128(d0, kk9); + d1 = _mm256_aesenc_epi128(d1, kk9); + d0 = _mm256_aesenc_epi128(d0, kk10); + d1 = _mm256_aesenc_epi128(d1, kk10); + d0 = _mm256_aesenc_epi128(d0, kk11); + d1 = _mm256_aesenc_epi128(d1, kk11); + d0 = _mm256_aesenc_epi128(d0, kk12); + d1 = _mm256_aesenc_epi128(d1, kk12); + d0 = _mm256_aesenc_epi128(d0, kk13); + d1 = _mm256_aesenc_epi128(d1, kk13); + d0 = _mm256_aesenclast_epi128(d0, kk14); + d1 = _mm256_aesenclast_epi128(d1, kk14); + _mm256_storeu_si256(reinterpret_cast<__m256i*>(out), _mm256_xor_si256(d0, p0)); + _mm256_storeu_si256(reinterpret_cast<__m256i*>(out + 32), _mm256_xor_si256(d1, p1)); + out += 64; + } while (likely(len >= 64)); } -#endif // does compiler support AVX2 and AVX512 AES intrinsics? +#endif // does compiler support AVX2 and AVX512 AES intrinsics? #ifdef __GNUC__ __attribute__((__target__("ssse3,sse4,sse4.1,sse4.2,aes,pclmul"))) #endif -__m128i p_init256_1_aesni(__m128i a, __m128i b) noexcept +__m128i +p_init256_1_aesni(__m128i a, __m128i b) noexcept { - __m128i x, y; - b = _mm_shuffle_epi32(b, 0xff); - y = _mm_slli_si128(a, 0x04); - x = _mm_xor_si128(a, y); - y = _mm_slli_si128(y, 0x04); - x = _mm_xor_si128(x, y); - y = _mm_slli_si128(y, 0x04); - x = _mm_xor_si128(x, y); - x = _mm_xor_si128(x, b); - return x; + __m128i x, y; + b = _mm_shuffle_epi32(b, 0xff); + y = _mm_slli_si128(a, 0x04); + x = _mm_xor_si128(a, y); + y = _mm_slli_si128(y, 0x04); + x = _mm_xor_si128(x, y); + y = _mm_slli_si128(y, 0x04); + x = _mm_xor_si128(x, y); + x = _mm_xor_si128(x, b); + return x; } #ifdef __GNUC__ __attribute__((__target__("ssse3,sse4,sse4.1,sse4.2,aes,pclmul"))) #endif -__m128i p_init256_2_aesni(__m128i a, __m128i b) noexcept +__m128i +p_init256_2_aesni(__m128i a, __m128i b) noexcept { - __m128i x, y, z; - y = _mm_aeskeygenassist_si128(a, 0x00); - z = _mm_shuffle_epi32(y, 0xaa); - y = _mm_slli_si128(b, 0x04); - x = _mm_xor_si128(b, y); - y = _mm_slli_si128(y, 0x04); - x = _mm_xor_si128(x, y); - y = _mm_slli_si128(y, 0x04); - x = _mm_xor_si128(x, y); - x = _mm_xor_si128(x, z); - return x; + __m128i x, y, z; + y = _mm_aeskeygenassist_si128(a, 0x00); + z = _mm_shuffle_epi32(y, 0xaa); + y = _mm_slli_si128(b, 0x04); + x = _mm_xor_si128(b, y); + y = _mm_slli_si128(y, 0x04); + x = _mm_xor_si128(x, y); + y = _mm_slli_si128(y, 0x04); + x = _mm_xor_si128(x, y); + x = _mm_xor_si128(x, z); + return x; } -} // anonymous namespace +} // anonymous namespace #ifdef __GNUC__ __attribute__((__target__("ssse3,sse4,sse4.1,sse4.2,pclmul"))) #endif void AES::GMAC::p_aesNIUpdate(const uint8_t *in, unsigned int len) noexcept { - __m128i y = _mm_loadu_si128(reinterpret_cast(_y)); + __m128i y = _mm_loadu_si128(reinterpret_cast(_y)); - // Handle anything left over from a previous run that wasn't a multiple of 16 bytes. - if (_rp) { - for (;;) { - if (!len) { - return; - } - --len; - _r[_rp++] = *(in++); - if (_rp == 16) { - y = p_gmacPCLMUL128(_aes.p_k.ni.h[0], _mm_xor_si128(y, _mm_loadu_si128(reinterpret_cast<__m128i *>(_r)))); - break; - } - } - } + // Handle anything left over from a previous run that wasn't a multiple of 16 bytes. + if (_rp) { + for (;;) { + if (! len) { + return; + } + --len; + _r[_rp++] = *(in++); + if (_rp == 16) { + y = p_gmacPCLMUL128(_aes.p_k.ni.h[0], _mm_xor_si128(y, _mm_loadu_si128(reinterpret_cast<__m128i*>(_r)))); + break; + } + } + } - if (likely(len >= 64)) { - const __m128i sb = s_sseSwapBytes; - const __m128i h = _aes.p_k.ni.h[0]; - const __m128i hh = _aes.p_k.ni.h[1]; - const __m128i hhh = _aes.p_k.ni.h[2]; - const __m128i hhhh = _aes.p_k.ni.h[3]; - const __m128i h2 = _aes.p_k.ni.h2[0]; - const __m128i hh2 = _aes.p_k.ni.h2[1]; - const __m128i hhh2 = _aes.p_k.ni.h2[2]; - const __m128i hhhh2 = _aes.p_k.ni.h2[3]; - const uint8_t *const end64 = in + (len & ~((unsigned int)63)); - len &= 63U; - do { - __m128i d1 = _mm_shuffle_epi8(_mm_xor_si128(y, _mm_loadu_si128(reinterpret_cast(in))), sb); - __m128i d2 = _mm_shuffle_epi8(_mm_loadu_si128(reinterpret_cast(in + 16)), sb); - __m128i d3 = _mm_shuffle_epi8(_mm_loadu_si128(reinterpret_cast(in + 32)), sb); - __m128i d4 = _mm_shuffle_epi8(_mm_loadu_si128(reinterpret_cast(in + 48)), sb); - in += 64; - __m128i a = _mm_xor_si128(_mm_xor_si128(_mm_clmulepi64_si128(hhhh, d1, 0x00), _mm_clmulepi64_si128(hhh, d2, 0x00)), _mm_xor_si128(_mm_clmulepi64_si128(hh, d3, 0x00), _mm_clmulepi64_si128(h, d4, 0x00))); - __m128i b = _mm_xor_si128(_mm_xor_si128(_mm_clmulepi64_si128(hhhh, d1, 0x11), _mm_clmulepi64_si128(hhh, d2, 0x11)), _mm_xor_si128(_mm_clmulepi64_si128(hh, d3, 0x11), _mm_clmulepi64_si128(h, d4, 0x11))); - __m128i c = _mm_xor_si128(_mm_xor_si128(_mm_xor_si128(_mm_clmulepi64_si128(hhhh2, _mm_xor_si128(_mm_shuffle_epi32(d1, 78), d1), 0x00), _mm_clmulepi64_si128(hhh2, _mm_xor_si128(_mm_shuffle_epi32(d2, 78), d2), 0x00)), _mm_xor_si128(_mm_clmulepi64_si128(hh2, _mm_xor_si128(_mm_shuffle_epi32(d3, 78), d3), 0x00), _mm_clmulepi64_si128(h2, _mm_xor_si128(_mm_shuffle_epi32(d4, 78), d4), 0x00))), _mm_xor_si128(a, b)); - a = _mm_xor_si128(_mm_slli_si128(c, 8), a); - b = _mm_xor_si128(_mm_srli_si128(c, 8), b); - c = _mm_srli_epi32(a, 31); - a = _mm_or_si128(_mm_slli_epi32(a, 1), _mm_slli_si128(c, 4)); - b = _mm_or_si128(_mm_or_si128(_mm_slli_epi32(b, 1), _mm_slli_si128(_mm_srli_epi32(b, 31), 4)), _mm_srli_si128(c, 12)); - c = _mm_xor_si128(_mm_slli_epi32(a, 31), _mm_xor_si128(_mm_slli_epi32(a, 30), _mm_slli_epi32(a, 25))); - a = _mm_xor_si128(a, _mm_slli_si128(c, 12)); - b = _mm_xor_si128(b, _mm_xor_si128(a, _mm_xor_si128(_mm_xor_si128(_mm_srli_epi32(a, 1), _mm_srli_si128(c, 4)), _mm_xor_si128(_mm_srli_epi32(a, 2), _mm_srli_epi32(a, 7))))); - y = _mm_shuffle_epi8(b, sb); - } while (likely(in != end64)); - } + if (likely(len >= 64)) { + const __m128i sb = s_sseSwapBytes; + const __m128i h = _aes.p_k.ni.h[0]; + const __m128i hh = _aes.p_k.ni.h[1]; + const __m128i hhh = _aes.p_k.ni.h[2]; + const __m128i hhhh = _aes.p_k.ni.h[3]; + const __m128i h2 = _aes.p_k.ni.h2[0]; + const __m128i hh2 = _aes.p_k.ni.h2[1]; + const __m128i hhh2 = _aes.p_k.ni.h2[2]; + const __m128i hhhh2 = _aes.p_k.ni.h2[3]; + const uint8_t* const end64 = in + (len & ~((unsigned int)63)); + len &= 63U; + do { + __m128i d1 = _mm_shuffle_epi8(_mm_xor_si128(y, _mm_loadu_si128(reinterpret_cast(in))), sb); + __m128i d2 = _mm_shuffle_epi8(_mm_loadu_si128(reinterpret_cast(in + 16)), sb); + __m128i d3 = _mm_shuffle_epi8(_mm_loadu_si128(reinterpret_cast(in + 32)), sb); + __m128i d4 = _mm_shuffle_epi8(_mm_loadu_si128(reinterpret_cast(in + 48)), sb); + in += 64; + __m128i a = _mm_xor_si128(_mm_xor_si128(_mm_clmulepi64_si128(hhhh, d1, 0x00), _mm_clmulepi64_si128(hhh, d2, 0x00)), _mm_xor_si128(_mm_clmulepi64_si128(hh, d3, 0x00), _mm_clmulepi64_si128(h, d4, 0x00))); + __m128i b = _mm_xor_si128(_mm_xor_si128(_mm_clmulepi64_si128(hhhh, d1, 0x11), _mm_clmulepi64_si128(hhh, d2, 0x11)), _mm_xor_si128(_mm_clmulepi64_si128(hh, d3, 0x11), _mm_clmulepi64_si128(h, d4, 0x11))); + __m128i c = _mm_xor_si128( + _mm_xor_si128( + _mm_xor_si128(_mm_clmulepi64_si128(hhhh2, _mm_xor_si128(_mm_shuffle_epi32(d1, 78), d1), 0x00), _mm_clmulepi64_si128(hhh2, _mm_xor_si128(_mm_shuffle_epi32(d2, 78), d2), 0x00)), + _mm_xor_si128(_mm_clmulepi64_si128(hh2, _mm_xor_si128(_mm_shuffle_epi32(d3, 78), d3), 0x00), _mm_clmulepi64_si128(h2, _mm_xor_si128(_mm_shuffle_epi32(d4, 78), d4), 0x00))), + _mm_xor_si128(a, b)); + a = _mm_xor_si128(_mm_slli_si128(c, 8), a); + b = _mm_xor_si128(_mm_srli_si128(c, 8), b); + c = _mm_srli_epi32(a, 31); + a = _mm_or_si128(_mm_slli_epi32(a, 1), _mm_slli_si128(c, 4)); + b = _mm_or_si128(_mm_or_si128(_mm_slli_epi32(b, 1), _mm_slli_si128(_mm_srli_epi32(b, 31), 4)), _mm_srli_si128(c, 12)); + c = _mm_xor_si128(_mm_slli_epi32(a, 31), _mm_xor_si128(_mm_slli_epi32(a, 30), _mm_slli_epi32(a, 25))); + a = _mm_xor_si128(a, _mm_slli_si128(c, 12)); + b = _mm_xor_si128(b, _mm_xor_si128(a, _mm_xor_si128(_mm_xor_si128(_mm_srli_epi32(a, 1), _mm_srli_si128(c, 4)), _mm_xor_si128(_mm_srli_epi32(a, 2), _mm_srli_epi32(a, 7))))); + y = _mm_shuffle_epi8(b, sb); + } while (likely(in != end64)); + } - while (len >= 16) { - y = p_gmacPCLMUL128(_aes.p_k.ni.h[0], _mm_xor_si128(y, _mm_loadu_si128(reinterpret_cast(in)))); - in += 16; - len -= 16; - } + while (len >= 16) { + y = p_gmacPCLMUL128(_aes.p_k.ni.h[0], _mm_xor_si128(y, _mm_loadu_si128(reinterpret_cast(in)))); + in += 16; + len -= 16; + } - _mm_storeu_si128(reinterpret_cast<__m128i *>(_y), y); + _mm_storeu_si128(reinterpret_cast<__m128i*>(_y), y); - // Any overflow is cached for a later run or finish(). - for (unsigned int i = 0; i < len; ++i) { - _r[i] = in[i]; - } - _rp = len; // len is always less than 16 here + // Any overflow is cached for a later run or finish(). + for (unsigned int i = 0; i < len; ++i) { + _r[i] = in[i]; + } + _rp = len; // len is always less than 16 here } #ifdef __GNUC__ @@ -293,73 +292,73 @@ __attribute__((__target__("ssse3,sse4,sse4.1,sse4.2,pclmul,aes"))) #endif void AES::GMAC::p_aesNIFinish(uint8_t tag[16]) noexcept { - __m128i y = _mm_loadu_si128(reinterpret_cast(_y)); + __m128i y = _mm_loadu_si128(reinterpret_cast(_y)); - // Handle any remaining bytes, padding the last block with zeroes. - if (_rp) { - while (_rp < 16) { - _r[_rp++] = 0; - } - y = p_gmacPCLMUL128(_aes.p_k.ni.h[0], _mm_xor_si128(y, _mm_loadu_si128(reinterpret_cast<__m128i *>(_r)))); - } + // Handle any remaining bytes, padding the last block with zeroes. + if (_rp) { + while (_rp < 16) { + _r[_rp++] = 0; + } + y = p_gmacPCLMUL128(_aes.p_k.ni.h[0], _mm_xor_si128(y, _mm_loadu_si128(reinterpret_cast<__m128i*>(_r)))); + } - // Interleave encryption of IV with the final GHASH of y XOR (length * 8). - // Then XOR these together to get the final tag. - const __m128i *const k = _aes.p_k.ni.k; - const __m128i h = _aes.p_k.ni.h[0]; - y = _mm_xor_si128(y, _mm_set_epi64x(0LL, (long long)Utils::hton((uint64_t)_len << 3U))); - y = _mm_shuffle_epi8(y, s_sseSwapBytes); - __m128i encIV = _mm_xor_si128(_mm_loadu_si128(reinterpret_cast(_iv)), k[0]); - __m128i t1 = _mm_clmulepi64_si128(h, y, 0x00); - __m128i t2 = _mm_clmulepi64_si128(h, y, 0x01); - __m128i t3 = _mm_clmulepi64_si128(h, y, 0x10); - __m128i t4 = _mm_clmulepi64_si128(h, y, 0x11); - encIV = _mm_aesenc_si128(encIV, k[1]); - t2 = _mm_xor_si128(t2, t3); - t3 = _mm_slli_si128(t2, 8); - encIV = _mm_aesenc_si128(encIV, k[2]); - t2 = _mm_srli_si128(t2, 8); - t1 = _mm_xor_si128(t1, t3); - encIV = _mm_aesenc_si128(encIV, k[3]); - t4 = _mm_xor_si128(t4, t2); - __m128i t5 = _mm_srli_epi32(t1, 31); - t1 = _mm_slli_epi32(t1, 1); - __m128i t6 = _mm_srli_epi32(t4, 31); - encIV = _mm_aesenc_si128(encIV, k[4]); - t4 = _mm_slli_epi32(t4, 1); - t3 = _mm_srli_si128(t5, 12); - encIV = _mm_aesenc_si128(encIV, k[5]); - t6 = _mm_slli_si128(t6, 4); - t5 = _mm_slli_si128(t5, 4); - encIV = _mm_aesenc_si128(encIV, k[6]); - t1 = _mm_or_si128(t1, t5); - t4 = _mm_or_si128(t4, t6); - encIV = _mm_aesenc_si128(encIV, k[7]); - t4 = _mm_or_si128(t4, t3); - t5 = _mm_slli_epi32(t1, 31); - encIV = _mm_aesenc_si128(encIV, k[8]); - t6 = _mm_slli_epi32(t1, 30); - t3 = _mm_slli_epi32(t1, 25); - encIV = _mm_aesenc_si128(encIV, k[9]); - t5 = _mm_xor_si128(t5, t6); - t5 = _mm_xor_si128(t5, t3); - encIV = _mm_aesenc_si128(encIV, k[10]); - t6 = _mm_srli_si128(t5, 4); - t4 = _mm_xor_si128(t4, t6); - encIV = _mm_aesenc_si128(encIV, k[11]); - t5 = _mm_slli_si128(t5, 12); - t1 = _mm_xor_si128(t1, t5); - t4 = _mm_xor_si128(t4, t1); - t5 = _mm_srli_epi32(t1, 1); - encIV = _mm_aesenc_si128(encIV, k[12]); - t2 = _mm_srli_epi32(t1, 2); - t3 = _mm_srli_epi32(t1, 7); - encIV = _mm_aesenc_si128(encIV, k[13]); - t4 = _mm_xor_si128(t4, t2); - t4 = _mm_xor_si128(t4, t3); - encIV = _mm_aesenclast_si128(encIV, k[14]); - t4 = _mm_xor_si128(t4, t5); - _mm_storeu_si128(reinterpret_cast<__m128i *>(tag), _mm_xor_si128(_mm_shuffle_epi8(t4, s_sseSwapBytes), encIV)); + // Interleave encryption of IV with the final GHASH of y XOR (length * 8). + // Then XOR these together to get the final tag. + const __m128i* const k = _aes.p_k.ni.k; + const __m128i h = _aes.p_k.ni.h[0]; + y = _mm_xor_si128(y, _mm_set_epi64x(0LL, (long long)Utils::hton((uint64_t)_len << 3U))); + y = _mm_shuffle_epi8(y, s_sseSwapBytes); + __m128i encIV = _mm_xor_si128(_mm_loadu_si128(reinterpret_cast(_iv)), k[0]); + __m128i t1 = _mm_clmulepi64_si128(h, y, 0x00); + __m128i t2 = _mm_clmulepi64_si128(h, y, 0x01); + __m128i t3 = _mm_clmulepi64_si128(h, y, 0x10); + __m128i t4 = _mm_clmulepi64_si128(h, y, 0x11); + encIV = _mm_aesenc_si128(encIV, k[1]); + t2 = _mm_xor_si128(t2, t3); + t3 = _mm_slli_si128(t2, 8); + encIV = _mm_aesenc_si128(encIV, k[2]); + t2 = _mm_srli_si128(t2, 8); + t1 = _mm_xor_si128(t1, t3); + encIV = _mm_aesenc_si128(encIV, k[3]); + t4 = _mm_xor_si128(t4, t2); + __m128i t5 = _mm_srli_epi32(t1, 31); + t1 = _mm_slli_epi32(t1, 1); + __m128i t6 = _mm_srli_epi32(t4, 31); + encIV = _mm_aesenc_si128(encIV, k[4]); + t4 = _mm_slli_epi32(t4, 1); + t3 = _mm_srli_si128(t5, 12); + encIV = _mm_aesenc_si128(encIV, k[5]); + t6 = _mm_slli_si128(t6, 4); + t5 = _mm_slli_si128(t5, 4); + encIV = _mm_aesenc_si128(encIV, k[6]); + t1 = _mm_or_si128(t1, t5); + t4 = _mm_or_si128(t4, t6); + encIV = _mm_aesenc_si128(encIV, k[7]); + t4 = _mm_or_si128(t4, t3); + t5 = _mm_slli_epi32(t1, 31); + encIV = _mm_aesenc_si128(encIV, k[8]); + t6 = _mm_slli_epi32(t1, 30); + t3 = _mm_slli_epi32(t1, 25); + encIV = _mm_aesenc_si128(encIV, k[9]); + t5 = _mm_xor_si128(t5, t6); + t5 = _mm_xor_si128(t5, t3); + encIV = _mm_aesenc_si128(encIV, k[10]); + t6 = _mm_srli_si128(t5, 4); + t4 = _mm_xor_si128(t4, t6); + encIV = _mm_aesenc_si128(encIV, k[11]); + t5 = _mm_slli_si128(t5, 12); + t1 = _mm_xor_si128(t1, t5); + t4 = _mm_xor_si128(t4, t1); + t5 = _mm_srli_epi32(t1, 1); + encIV = _mm_aesenc_si128(encIV, k[12]); + t2 = _mm_srli_epi32(t1, 2); + t3 = _mm_srli_epi32(t1, 7); + encIV = _mm_aesenc_si128(encIV, k[13]); + t4 = _mm_xor_si128(t4, t2); + t4 = _mm_xor_si128(t4, t3); + encIV = _mm_aesenclast_si128(encIV, k[14]); + t4 = _mm_xor_si128(t4, t5); + _mm_storeu_si128(reinterpret_cast<__m128i*>(tag), _mm_xor_si128(_mm_shuffle_epi8(t4, s_sseSwapBytes), encIV)); } #ifdef __GNUC__ @@ -367,199 +366,198 @@ __attribute__((__target__("ssse3,sse4,sse4.1,sse4.2,aes"))) #endif void AES::CTR::p_aesNICrypt(const uint8_t *in, uint8_t *out, unsigned int len) noexcept { - const __m128i dd = _mm_set_epi64x(0, (long long)_ctr[0]); - uint64_t c1 = Utils::ntoh(_ctr[1]); + const __m128i dd = _mm_set_epi64x(0, (long long)_ctr[0]); + uint64_t c1 = Utils::ntoh(_ctr[1]); - const __m128i *const k = _aes.p_k.ni.k; - const __m128i k0 = k[0]; - const __m128i k1 = k[1]; - const __m128i k2 = k[2]; - const __m128i k3 = k[3]; - const __m128i k4 = k[4]; - const __m128i k5 = k[5]; - const __m128i k6 = k[6]; - const __m128i k7 = k[7]; - const __m128i k8 = k[8]; - const __m128i k9 = k[9]; - const __m128i k10 = k[10]; - const __m128i k11 = k[11]; - const __m128i k12 = k[12]; - const __m128i k13 = k[13]; - const __m128i k14 = k[14]; + const __m128i* const k = _aes.p_k.ni.k; + const __m128i k0 = k[0]; + const __m128i k1 = k[1]; + const __m128i k2 = k[2]; + const __m128i k3 = k[3]; + const __m128i k4 = k[4]; + const __m128i k5 = k[5]; + const __m128i k6 = k[6]; + const __m128i k7 = k[7]; + const __m128i k8 = k[8]; + const __m128i k9 = k[9]; + const __m128i k10 = k[10]; + const __m128i k11 = k[11]; + const __m128i k12 = k[12]; + const __m128i k13 = k[13]; + const __m128i k14 = k[14]; - // Complete any unfinished blocks from previous calls to crypt(). - unsigned int totalLen = _len; - if ((totalLen & 15U)) { - for (;;) { - if (unlikely(!len)) { - _ctr[1] = Utils::hton(c1); - _len = totalLen; - return; - } - --len; - out[totalLen++] = *(in++); - if (!(totalLen & 15U)) { - __m128i d0 = _mm_insert_epi64(dd, (long long)Utils::hton(c1++), 1); - d0 = _mm_xor_si128(d0, k0); - d0 = _mm_aesenc_si128(d0, k1); - d0 = _mm_aesenc_si128(d0, k2); - d0 = _mm_aesenc_si128(d0, k3); - d0 = _mm_aesenc_si128(d0, k4); - d0 = _mm_aesenc_si128(d0, k5); - d0 = _mm_aesenc_si128(d0, k6); - d0 = _mm_aesenc_si128(d0, k7); - d0 = _mm_aesenc_si128(d0, k8); - d0 = _mm_aesenc_si128(d0, k9); - d0 = _mm_aesenc_si128(d0, k10); - __m128i *const outblk = reinterpret_cast<__m128i *>(out + (totalLen - 16)); - d0 = _mm_aesenc_si128(d0, k11); - const __m128i p0 = _mm_loadu_si128(outblk); - d0 = _mm_aesenc_si128(d0, k12); - d0 = _mm_aesenc_si128(d0, k13); - d0 = _mm_aesenclast_si128(d0, k14); - _mm_storeu_si128(outblk, _mm_xor_si128(p0, d0)); - break; - } - } - } + // Complete any unfinished blocks from previous calls to crypt(). + unsigned int totalLen = _len; + if ((totalLen & 15U)) { + for (;;) { + if (unlikely(! len)) { + _ctr[1] = Utils::hton(c1); + _len = totalLen; + return; + } + --len; + out[totalLen++] = *(in++); + if (! (totalLen & 15U)) { + __m128i d0 = _mm_insert_epi64(dd, (long long)Utils::hton(c1++), 1); + d0 = _mm_xor_si128(d0, k0); + d0 = _mm_aesenc_si128(d0, k1); + d0 = _mm_aesenc_si128(d0, k2); + d0 = _mm_aesenc_si128(d0, k3); + d0 = _mm_aesenc_si128(d0, k4); + d0 = _mm_aesenc_si128(d0, k5); + d0 = _mm_aesenc_si128(d0, k6); + d0 = _mm_aesenc_si128(d0, k7); + d0 = _mm_aesenc_si128(d0, k8); + d0 = _mm_aesenc_si128(d0, k9); + d0 = _mm_aesenc_si128(d0, k10); + __m128i* const outblk = reinterpret_cast<__m128i*>(out + (totalLen - 16)); + d0 = _mm_aesenc_si128(d0, k11); + const __m128i p0 = _mm_loadu_si128(outblk); + d0 = _mm_aesenc_si128(d0, k12); + d0 = _mm_aesenc_si128(d0, k13); + d0 = _mm_aesenclast_si128(d0, k14); + _mm_storeu_si128(outblk, _mm_xor_si128(p0, d0)); + break; + } + } + } - out += totalLen; - _len = totalLen + len; - - if (likely(len >= 64)) { + out += totalLen; + _len = totalLen + len; + if (likely(len >= 64)) { #if defined(ZT_AES_VAES512) && defined(ZT_AES_VAES256) - if (Utils::CPUID.vaes && (len >= 256)) { - if (Utils::CPUID.avx512f) { - p_aesCtrInnerVAES512(len, _ctr[0], c1, in, out, k); - } else { - p_aesCtrInnerVAES256(len, _ctr[0], c1, in, out, k); - } - goto skip_conventional_aesni_64; - } + if (Utils::CPUID.vaes && (len >= 256)) { + if (Utils::CPUID.avx512f) { + p_aesCtrInnerVAES512(len, _ctr[0], c1, in, out, k); + } + else { + p_aesCtrInnerVAES256(len, _ctr[0], c1, in, out, k); + } + goto skip_conventional_aesni_64; + } #endif -#if !defined(ZT_AES_VAES512) && defined(ZT_AES_VAES256) - if (Utils::CPUID.vaes && (len >= 256)) { - p_aesCtrInnerVAES256(len, _ctr[0], c1, in, out, k); - goto skip_conventional_aesni_64; - } +#if ! defined(ZT_AES_VAES512) && defined(ZT_AES_VAES256) + if (Utils::CPUID.vaes && (len >= 256)) { + p_aesCtrInnerVAES256(len, _ctr[0], c1, in, out, k); + goto skip_conventional_aesni_64; + } #endif - const uint8_t *const eof64 = in + (len & ~((unsigned int)63)); - len &= 63; - __m128i d0, d1, d2, d3; - do { - const uint64_t c10 = Utils::hton(c1); - const uint64_t c11 = Utils::hton(c1 + 1ULL); - const uint64_t c12 = Utils::hton(c1 + 2ULL); - const uint64_t c13 = Utils::hton(c1 + 3ULL); - d0 = _mm_insert_epi64(dd, (long long)c10, 1); - d1 = _mm_insert_epi64(dd, (long long)c11, 1); - d2 = _mm_insert_epi64(dd, (long long)c12, 1); - d3 = _mm_insert_epi64(dd, (long long)c13, 1); - c1 += 4; - d0 = _mm_xor_si128(d0, k0); - d1 = _mm_xor_si128(d1, k0); - d2 = _mm_xor_si128(d2, k0); - d3 = _mm_xor_si128(d3, k0); - d0 = _mm_aesenc_si128(d0, k1); - d1 = _mm_aesenc_si128(d1, k1); - d2 = _mm_aesenc_si128(d2, k1); - d3 = _mm_aesenc_si128(d3, k1); - d0 = _mm_aesenc_si128(d0, k2); - d1 = _mm_aesenc_si128(d1, k2); - d2 = _mm_aesenc_si128(d2, k2); - d3 = _mm_aesenc_si128(d3, k2); - d0 = _mm_aesenc_si128(d0, k3); - d1 = _mm_aesenc_si128(d1, k3); - d2 = _mm_aesenc_si128(d2, k3); - d3 = _mm_aesenc_si128(d3, k3); - d0 = _mm_aesenc_si128(d0, k4); - d1 = _mm_aesenc_si128(d1, k4); - d2 = _mm_aesenc_si128(d2, k4); - d3 = _mm_aesenc_si128(d3, k4); - d0 = _mm_aesenc_si128(d0, k5); - d1 = _mm_aesenc_si128(d1, k5); - d2 = _mm_aesenc_si128(d2, k5); - d3 = _mm_aesenc_si128(d3, k5); - d0 = _mm_aesenc_si128(d0, k6); - d1 = _mm_aesenc_si128(d1, k6); - d2 = _mm_aesenc_si128(d2, k6); - d3 = _mm_aesenc_si128(d3, k6); - d0 = _mm_aesenc_si128(d0, k7); - d1 = _mm_aesenc_si128(d1, k7); - d2 = _mm_aesenc_si128(d2, k7); - d3 = _mm_aesenc_si128(d3, k7); - d0 = _mm_aesenc_si128(d0, k8); - d1 = _mm_aesenc_si128(d1, k8); - d2 = _mm_aesenc_si128(d2, k8); - d3 = _mm_aesenc_si128(d3, k8); - d0 = _mm_aesenc_si128(d0, k9); - d1 = _mm_aesenc_si128(d1, k9); - d2 = _mm_aesenc_si128(d2, k9); - d3 = _mm_aesenc_si128(d3, k9); - d0 = _mm_aesenc_si128(d0, k10); - d1 = _mm_aesenc_si128(d1, k10); - d2 = _mm_aesenc_si128(d2, k10); - d3 = _mm_aesenc_si128(d3, k10); - d0 = _mm_aesenc_si128(d0, k11); - d1 = _mm_aesenc_si128(d1, k11); - d2 = _mm_aesenc_si128(d2, k11); - d3 = _mm_aesenc_si128(d3, k11); - d0 = _mm_aesenc_si128(d0, k12); - d1 = _mm_aesenc_si128(d1, k12); - d2 = _mm_aesenc_si128(d2, k12); - d3 = _mm_aesenc_si128(d3, k12); - d0 = _mm_aesenc_si128(d0, k13); - d1 = _mm_aesenc_si128(d1, k13); - d2 = _mm_aesenc_si128(d2, k13); - d3 = _mm_aesenc_si128(d3, k13); - d0 = _mm_xor_si128(_mm_aesenclast_si128(d0, k14), _mm_loadu_si128(reinterpret_cast(in))); - d1 = _mm_xor_si128(_mm_aesenclast_si128(d1, k14), _mm_loadu_si128(reinterpret_cast(in + 16))); - d2 = _mm_xor_si128(_mm_aesenclast_si128(d2, k14), _mm_loadu_si128(reinterpret_cast(in + 32))); - d3 = _mm_xor_si128(_mm_aesenclast_si128(d3, k14), _mm_loadu_si128(reinterpret_cast(in + 48))); - in += 64; - _mm_storeu_si128(reinterpret_cast<__m128i *>(out), d0); - _mm_storeu_si128(reinterpret_cast<__m128i *>(out + 16), d1); - _mm_storeu_si128(reinterpret_cast<__m128i *>(out + 32), d2); - _mm_storeu_si128(reinterpret_cast<__m128i *>(out + 48), d3); - out += 64; - } while (likely(in != eof64)); + const uint8_t* const eof64 = in + (len & ~((unsigned int)63)); + len &= 63; + __m128i d0, d1, d2, d3; + do { + const uint64_t c10 = Utils::hton(c1); + const uint64_t c11 = Utils::hton(c1 + 1ULL); + const uint64_t c12 = Utils::hton(c1 + 2ULL); + const uint64_t c13 = Utils::hton(c1 + 3ULL); + d0 = _mm_insert_epi64(dd, (long long)c10, 1); + d1 = _mm_insert_epi64(dd, (long long)c11, 1); + d2 = _mm_insert_epi64(dd, (long long)c12, 1); + d3 = _mm_insert_epi64(dd, (long long)c13, 1); + c1 += 4; + d0 = _mm_xor_si128(d0, k0); + d1 = _mm_xor_si128(d1, k0); + d2 = _mm_xor_si128(d2, k0); + d3 = _mm_xor_si128(d3, k0); + d0 = _mm_aesenc_si128(d0, k1); + d1 = _mm_aesenc_si128(d1, k1); + d2 = _mm_aesenc_si128(d2, k1); + d3 = _mm_aesenc_si128(d3, k1); + d0 = _mm_aesenc_si128(d0, k2); + d1 = _mm_aesenc_si128(d1, k2); + d2 = _mm_aesenc_si128(d2, k2); + d3 = _mm_aesenc_si128(d3, k2); + d0 = _mm_aesenc_si128(d0, k3); + d1 = _mm_aesenc_si128(d1, k3); + d2 = _mm_aesenc_si128(d2, k3); + d3 = _mm_aesenc_si128(d3, k3); + d0 = _mm_aesenc_si128(d0, k4); + d1 = _mm_aesenc_si128(d1, k4); + d2 = _mm_aesenc_si128(d2, k4); + d3 = _mm_aesenc_si128(d3, k4); + d0 = _mm_aesenc_si128(d0, k5); + d1 = _mm_aesenc_si128(d1, k5); + d2 = _mm_aesenc_si128(d2, k5); + d3 = _mm_aesenc_si128(d3, k5); + d0 = _mm_aesenc_si128(d0, k6); + d1 = _mm_aesenc_si128(d1, k6); + d2 = _mm_aesenc_si128(d2, k6); + d3 = _mm_aesenc_si128(d3, k6); + d0 = _mm_aesenc_si128(d0, k7); + d1 = _mm_aesenc_si128(d1, k7); + d2 = _mm_aesenc_si128(d2, k7); + d3 = _mm_aesenc_si128(d3, k7); + d0 = _mm_aesenc_si128(d0, k8); + d1 = _mm_aesenc_si128(d1, k8); + d2 = _mm_aesenc_si128(d2, k8); + d3 = _mm_aesenc_si128(d3, k8); + d0 = _mm_aesenc_si128(d0, k9); + d1 = _mm_aesenc_si128(d1, k9); + d2 = _mm_aesenc_si128(d2, k9); + d3 = _mm_aesenc_si128(d3, k9); + d0 = _mm_aesenc_si128(d0, k10); + d1 = _mm_aesenc_si128(d1, k10); + d2 = _mm_aesenc_si128(d2, k10); + d3 = _mm_aesenc_si128(d3, k10); + d0 = _mm_aesenc_si128(d0, k11); + d1 = _mm_aesenc_si128(d1, k11); + d2 = _mm_aesenc_si128(d2, k11); + d3 = _mm_aesenc_si128(d3, k11); + d0 = _mm_aesenc_si128(d0, k12); + d1 = _mm_aesenc_si128(d1, k12); + d2 = _mm_aesenc_si128(d2, k12); + d3 = _mm_aesenc_si128(d3, k12); + d0 = _mm_aesenc_si128(d0, k13); + d1 = _mm_aesenc_si128(d1, k13); + d2 = _mm_aesenc_si128(d2, k13); + d3 = _mm_aesenc_si128(d3, k13); + d0 = _mm_xor_si128(_mm_aesenclast_si128(d0, k14), _mm_loadu_si128(reinterpret_cast(in))); + d1 = _mm_xor_si128(_mm_aesenclast_si128(d1, k14), _mm_loadu_si128(reinterpret_cast(in + 16))); + d2 = _mm_xor_si128(_mm_aesenclast_si128(d2, k14), _mm_loadu_si128(reinterpret_cast(in + 32))); + d3 = _mm_xor_si128(_mm_aesenclast_si128(d3, k14), _mm_loadu_si128(reinterpret_cast(in + 48))); + in += 64; + _mm_storeu_si128(reinterpret_cast<__m128i*>(out), d0); + _mm_storeu_si128(reinterpret_cast<__m128i*>(out + 16), d1); + _mm_storeu_si128(reinterpret_cast<__m128i*>(out + 32), d2); + _mm_storeu_si128(reinterpret_cast<__m128i*>(out + 48), d3); + out += 64; + } while (likely(in != eof64)); + } - } +skip_conventional_aesni_64: + while (len >= 16) { + __m128i d0 = _mm_insert_epi64(dd, (long long)Utils::hton(c1++), 1); + d0 = _mm_xor_si128(d0, k0); + d0 = _mm_aesenc_si128(d0, k1); + d0 = _mm_aesenc_si128(d0, k2); + d0 = _mm_aesenc_si128(d0, k3); + d0 = _mm_aesenc_si128(d0, k4); + d0 = _mm_aesenc_si128(d0, k5); + d0 = _mm_aesenc_si128(d0, k6); + d0 = _mm_aesenc_si128(d0, k7); + d0 = _mm_aesenc_si128(d0, k8); + d0 = _mm_aesenc_si128(d0, k9); + d0 = _mm_aesenc_si128(d0, k10); + d0 = _mm_aesenc_si128(d0, k11); + d0 = _mm_aesenc_si128(d0, k12); + d0 = _mm_aesenc_si128(d0, k13); + _mm_storeu_si128(reinterpret_cast<__m128i*>(out), _mm_xor_si128(_mm_aesenclast_si128(d0, k14), _mm_loadu_si128(reinterpret_cast(in)))); + in += 16; + len -= 16; + out += 16; + } - skip_conventional_aesni_64: - while (len >= 16) { - __m128i d0 = _mm_insert_epi64(dd, (long long)Utils::hton(c1++), 1); - d0 = _mm_xor_si128(d0, k0); - d0 = _mm_aesenc_si128(d0, k1); - d0 = _mm_aesenc_si128(d0, k2); - d0 = _mm_aesenc_si128(d0, k3); - d0 = _mm_aesenc_si128(d0, k4); - d0 = _mm_aesenc_si128(d0, k5); - d0 = _mm_aesenc_si128(d0, k6); - d0 = _mm_aesenc_si128(d0, k7); - d0 = _mm_aesenc_si128(d0, k8); - d0 = _mm_aesenc_si128(d0, k9); - d0 = _mm_aesenc_si128(d0, k10); - d0 = _mm_aesenc_si128(d0, k11); - d0 = _mm_aesenc_si128(d0, k12); - d0 = _mm_aesenc_si128(d0, k13); - _mm_storeu_si128(reinterpret_cast<__m128i *>(out), _mm_xor_si128(_mm_aesenclast_si128(d0, k14), _mm_loadu_si128(reinterpret_cast(in)))); - in += 16; - len -= 16; - out += 16; - } + // Any remaining input is placed in _out. This will be picked up and crypted + // on subsequent calls to crypt() or finish() as it'll mean _len will not be + // an even multiple of 16. + for (unsigned int i = 0; i < len; ++i) { + out[i] = in[i]; + } - // Any remaining input is placed in _out. This will be picked up and crypted - // on subsequent calls to crypt() or finish() as it'll mean _len will not be - // an even multiple of 16. - for (unsigned int i = 0; i < len; ++i) { - out[i] = in[i]; - } - - _ctr[1] = Utils::hton(c1); + _ctr[1] = Utils::hton(c1); } #ifdef __GNUC__ @@ -567,63 +565,63 @@ __attribute__((__target__("ssse3,sse4,sse4.1,sse4.2,aes,pclmul"))) #endif void AES::p_init_aesni(const uint8_t *key) noexcept { - __m128i t1, t2, k1, k2, k3, k4, k5, k6, k7, k8, k9, k10, k11, k12, k13; - p_k.ni.k[0] = t1 = _mm_loadu_si128((const __m128i *)key); - p_k.ni.k[1] = k1 = t2 = _mm_loadu_si128((const __m128i *)(key + 16)); - p_k.ni.k[2] = k2 = t1 = p_init256_1_aesni(t1, _mm_aeskeygenassist_si128(t2, 0x01)); - p_k.ni.k[3] = k3 = t2 = p_init256_2_aesni(t1, t2); - p_k.ni.k[4] = k4 = t1 = p_init256_1_aesni(t1, _mm_aeskeygenassist_si128(t2, 0x02)); - p_k.ni.k[5] = k5 = t2 = p_init256_2_aesni(t1, t2); - p_k.ni.k[6] = k6 = t1 = p_init256_1_aesni(t1, _mm_aeskeygenassist_si128(t2, 0x04)); - p_k.ni.k[7] = k7 = t2 = p_init256_2_aesni(t1, t2); - p_k.ni.k[8] = k8 = t1 = p_init256_1_aesni(t1, _mm_aeskeygenassist_si128(t2, 0x08)); - p_k.ni.k[9] = k9 = t2 = p_init256_2_aesni(t1, t2); - p_k.ni.k[10] = k10 = t1 = p_init256_1_aesni(t1, _mm_aeskeygenassist_si128(t2, 0x10)); - p_k.ni.k[11] = k11 = t2 = p_init256_2_aesni(t1, t2); - p_k.ni.k[12] = k12 = t1 = p_init256_1_aesni(t1, _mm_aeskeygenassist_si128(t2, 0x20)); - p_k.ni.k[13] = k13 = t2 = p_init256_2_aesni(t1, t2); - p_k.ni.k[14] = p_init256_1_aesni(t1, _mm_aeskeygenassist_si128(t2, 0x40)); - p_k.ni.k[15] = _mm_aesimc_si128(k13); - p_k.ni.k[16] = _mm_aesimc_si128(k12); - p_k.ni.k[17] = _mm_aesimc_si128(k11); - p_k.ni.k[18] = _mm_aesimc_si128(k10); - p_k.ni.k[19] = _mm_aesimc_si128(k9); - p_k.ni.k[20] = _mm_aesimc_si128(k8); - p_k.ni.k[21] = _mm_aesimc_si128(k7); - p_k.ni.k[22] = _mm_aesimc_si128(k6); - p_k.ni.k[23] = _mm_aesimc_si128(k5); - p_k.ni.k[24] = _mm_aesimc_si128(k4); - p_k.ni.k[25] = _mm_aesimc_si128(k3); - p_k.ni.k[26] = _mm_aesimc_si128(k2); - p_k.ni.k[27] = _mm_aesimc_si128(k1); + __m128i t1, t2, k1, k2, k3, k4, k5, k6, k7, k8, k9, k10, k11, k12, k13; + p_k.ni.k[0] = t1 = _mm_loadu_si128((const __m128i*)key); + p_k.ni.k[1] = k1 = t2 = _mm_loadu_si128((const __m128i*)(key + 16)); + p_k.ni.k[2] = k2 = t1 = p_init256_1_aesni(t1, _mm_aeskeygenassist_si128(t2, 0x01)); + p_k.ni.k[3] = k3 = t2 = p_init256_2_aesni(t1, t2); + p_k.ni.k[4] = k4 = t1 = p_init256_1_aesni(t1, _mm_aeskeygenassist_si128(t2, 0x02)); + p_k.ni.k[5] = k5 = t2 = p_init256_2_aesni(t1, t2); + p_k.ni.k[6] = k6 = t1 = p_init256_1_aesni(t1, _mm_aeskeygenassist_si128(t2, 0x04)); + p_k.ni.k[7] = k7 = t2 = p_init256_2_aesni(t1, t2); + p_k.ni.k[8] = k8 = t1 = p_init256_1_aesni(t1, _mm_aeskeygenassist_si128(t2, 0x08)); + p_k.ni.k[9] = k9 = t2 = p_init256_2_aesni(t1, t2); + p_k.ni.k[10] = k10 = t1 = p_init256_1_aesni(t1, _mm_aeskeygenassist_si128(t2, 0x10)); + p_k.ni.k[11] = k11 = t2 = p_init256_2_aesni(t1, t2); + p_k.ni.k[12] = k12 = t1 = p_init256_1_aesni(t1, _mm_aeskeygenassist_si128(t2, 0x20)); + p_k.ni.k[13] = k13 = t2 = p_init256_2_aesni(t1, t2); + p_k.ni.k[14] = p_init256_1_aesni(t1, _mm_aeskeygenassist_si128(t2, 0x40)); + p_k.ni.k[15] = _mm_aesimc_si128(k13); + p_k.ni.k[16] = _mm_aesimc_si128(k12); + p_k.ni.k[17] = _mm_aesimc_si128(k11); + p_k.ni.k[18] = _mm_aesimc_si128(k10); + p_k.ni.k[19] = _mm_aesimc_si128(k9); + p_k.ni.k[20] = _mm_aesimc_si128(k8); + p_k.ni.k[21] = _mm_aesimc_si128(k7); + p_k.ni.k[22] = _mm_aesimc_si128(k6); + p_k.ni.k[23] = _mm_aesimc_si128(k5); + p_k.ni.k[24] = _mm_aesimc_si128(k4); + p_k.ni.k[25] = _mm_aesimc_si128(k3); + p_k.ni.k[26] = _mm_aesimc_si128(k2); + p_k.ni.k[27] = _mm_aesimc_si128(k1); - __m128i h = p_k.ni.k[0]; // _mm_xor_si128(_mm_setzero_si128(),_k.ni.k[0]); - h = _mm_aesenc_si128(h, k1); - h = _mm_aesenc_si128(h, k2); - h = _mm_aesenc_si128(h, k3); - h = _mm_aesenc_si128(h, k4); - h = _mm_aesenc_si128(h, k5); - h = _mm_aesenc_si128(h, k6); - h = _mm_aesenc_si128(h, k7); - h = _mm_aesenc_si128(h, k8); - h = _mm_aesenc_si128(h, k9); - h = _mm_aesenc_si128(h, k10); - h = _mm_aesenc_si128(h, k11); - h = _mm_aesenc_si128(h, k12); - h = _mm_aesenc_si128(h, k13); - h = _mm_aesenclast_si128(h, p_k.ni.k[14]); - __m128i hswap = _mm_shuffle_epi8(h, s_sseSwapBytes); - __m128i hh = p_gmacPCLMUL128(hswap, h); - __m128i hhh = p_gmacPCLMUL128(hswap, hh); - __m128i hhhh = p_gmacPCLMUL128(hswap, hhh); - p_k.ni.h[0] = hswap; - p_k.ni.h[1] = hh = _mm_shuffle_epi8(hh, s_sseSwapBytes); - p_k.ni.h[2] = hhh = _mm_shuffle_epi8(hhh, s_sseSwapBytes); - p_k.ni.h[3] = hhhh = _mm_shuffle_epi8(hhhh, s_sseSwapBytes); - p_k.ni.h2[0] = _mm_xor_si128(_mm_shuffle_epi32(hswap, 78), hswap); - p_k.ni.h2[1] = _mm_xor_si128(_mm_shuffle_epi32(hh, 78), hh); - p_k.ni.h2[2] = _mm_xor_si128(_mm_shuffle_epi32(hhh, 78), hhh); - p_k.ni.h2[3] = _mm_xor_si128(_mm_shuffle_epi32(hhhh, 78), hhhh); + __m128i h = p_k.ni.k[0]; // _mm_xor_si128(_mm_setzero_si128(),_k.ni.k[0]); + h = _mm_aesenc_si128(h, k1); + h = _mm_aesenc_si128(h, k2); + h = _mm_aesenc_si128(h, k3); + h = _mm_aesenc_si128(h, k4); + h = _mm_aesenc_si128(h, k5); + h = _mm_aesenc_si128(h, k6); + h = _mm_aesenc_si128(h, k7); + h = _mm_aesenc_si128(h, k8); + h = _mm_aesenc_si128(h, k9); + h = _mm_aesenc_si128(h, k10); + h = _mm_aesenc_si128(h, k11); + h = _mm_aesenc_si128(h, k12); + h = _mm_aesenc_si128(h, k13); + h = _mm_aesenclast_si128(h, p_k.ni.k[14]); + __m128i hswap = _mm_shuffle_epi8(h, s_sseSwapBytes); + __m128i hh = p_gmacPCLMUL128(hswap, h); + __m128i hhh = p_gmacPCLMUL128(hswap, hh); + __m128i hhhh = p_gmacPCLMUL128(hswap, hhh); + p_k.ni.h[0] = hswap; + p_k.ni.h[1] = hh = _mm_shuffle_epi8(hh, s_sseSwapBytes); + p_k.ni.h[2] = hhh = _mm_shuffle_epi8(hhh, s_sseSwapBytes); + p_k.ni.h[3] = hhhh = _mm_shuffle_epi8(hhhh, s_sseSwapBytes); + p_k.ni.h2[0] = _mm_xor_si128(_mm_shuffle_epi32(hswap, 78), hswap); + p_k.ni.h2[1] = _mm_xor_si128(_mm_shuffle_epi32(hh, 78), hh); + p_k.ni.h2[2] = _mm_xor_si128(_mm_shuffle_epi32(hhh, 78), hhh); + p_k.ni.h2[3] = _mm_xor_si128(_mm_shuffle_epi32(hhhh, 78), hhhh); } #ifdef __GNUC__ @@ -631,22 +629,22 @@ __attribute__((__target__("ssse3,sse4,sse4.1,sse4.2,aes,pclmul"))) #endif void AES::p_encrypt_aesni(const void *const in, void *const out) const noexcept { - __m128i tmp = _mm_loadu_si128((const __m128i *)in); - tmp = _mm_xor_si128(tmp, p_k.ni.k[0]); - tmp = _mm_aesenc_si128(tmp, p_k.ni.k[1]); - tmp = _mm_aesenc_si128(tmp, p_k.ni.k[2]); - tmp = _mm_aesenc_si128(tmp, p_k.ni.k[3]); - tmp = _mm_aesenc_si128(tmp, p_k.ni.k[4]); - tmp = _mm_aesenc_si128(tmp, p_k.ni.k[5]); - tmp = _mm_aesenc_si128(tmp, p_k.ni.k[6]); - tmp = _mm_aesenc_si128(tmp, p_k.ni.k[7]); - tmp = _mm_aesenc_si128(tmp, p_k.ni.k[8]); - tmp = _mm_aesenc_si128(tmp, p_k.ni.k[9]); - tmp = _mm_aesenc_si128(tmp, p_k.ni.k[10]); - tmp = _mm_aesenc_si128(tmp, p_k.ni.k[11]); - tmp = _mm_aesenc_si128(tmp, p_k.ni.k[12]); - tmp = _mm_aesenc_si128(tmp, p_k.ni.k[13]); - _mm_storeu_si128((__m128i *)out, _mm_aesenclast_si128(tmp, p_k.ni.k[14])); + __m128i tmp = _mm_loadu_si128((const __m128i*)in); + tmp = _mm_xor_si128(tmp, p_k.ni.k[0]); + tmp = _mm_aesenc_si128(tmp, p_k.ni.k[1]); + tmp = _mm_aesenc_si128(tmp, p_k.ni.k[2]); + tmp = _mm_aesenc_si128(tmp, p_k.ni.k[3]); + tmp = _mm_aesenc_si128(tmp, p_k.ni.k[4]); + tmp = _mm_aesenc_si128(tmp, p_k.ni.k[5]); + tmp = _mm_aesenc_si128(tmp, p_k.ni.k[6]); + tmp = _mm_aesenc_si128(tmp, p_k.ni.k[7]); + tmp = _mm_aesenc_si128(tmp, p_k.ni.k[8]); + tmp = _mm_aesenc_si128(tmp, p_k.ni.k[9]); + tmp = _mm_aesenc_si128(tmp, p_k.ni.k[10]); + tmp = _mm_aesenc_si128(tmp, p_k.ni.k[11]); + tmp = _mm_aesenc_si128(tmp, p_k.ni.k[12]); + tmp = _mm_aesenc_si128(tmp, p_k.ni.k[13]); + _mm_storeu_si128((__m128i*)out, _mm_aesenclast_si128(tmp, p_k.ni.k[14])); } #ifdef __GNUC__ @@ -654,24 +652,24 @@ __attribute__((__target__("ssse3,sse4,sse4.1,sse4.2,aes,pclmul"))) #endif void AES::p_decrypt_aesni(const void *in, void *out) const noexcept { - __m128i tmp = _mm_loadu_si128((const __m128i *)in); - tmp = _mm_xor_si128(tmp, p_k.ni.k[14]); - tmp = _mm_aesdec_si128(tmp, p_k.ni.k[15]); - tmp = _mm_aesdec_si128(tmp, p_k.ni.k[16]); - tmp = _mm_aesdec_si128(tmp, p_k.ni.k[17]); - tmp = _mm_aesdec_si128(tmp, p_k.ni.k[18]); - tmp = _mm_aesdec_si128(tmp, p_k.ni.k[19]); - tmp = _mm_aesdec_si128(tmp, p_k.ni.k[20]); - tmp = _mm_aesdec_si128(tmp, p_k.ni.k[21]); - tmp = _mm_aesdec_si128(tmp, p_k.ni.k[22]); - tmp = _mm_aesdec_si128(tmp, p_k.ni.k[23]); - tmp = _mm_aesdec_si128(tmp, p_k.ni.k[24]); - tmp = _mm_aesdec_si128(tmp, p_k.ni.k[25]); - tmp = _mm_aesdec_si128(tmp, p_k.ni.k[26]); - tmp = _mm_aesdec_si128(tmp, p_k.ni.k[27]); - _mm_storeu_si128((__m128i *)out, _mm_aesdeclast_si128(tmp, p_k.ni.k[0])); + __m128i tmp = _mm_loadu_si128((const __m128i*)in); + tmp = _mm_xor_si128(tmp, p_k.ni.k[14]); + tmp = _mm_aesdec_si128(tmp, p_k.ni.k[15]); + tmp = _mm_aesdec_si128(tmp, p_k.ni.k[16]); + tmp = _mm_aesdec_si128(tmp, p_k.ni.k[17]); + tmp = _mm_aesdec_si128(tmp, p_k.ni.k[18]); + tmp = _mm_aesdec_si128(tmp, p_k.ni.k[19]); + tmp = _mm_aesdec_si128(tmp, p_k.ni.k[20]); + tmp = _mm_aesdec_si128(tmp, p_k.ni.k[21]); + tmp = _mm_aesdec_si128(tmp, p_k.ni.k[22]); + tmp = _mm_aesdec_si128(tmp, p_k.ni.k[23]); + tmp = _mm_aesdec_si128(tmp, p_k.ni.k[24]); + tmp = _mm_aesdec_si128(tmp, p_k.ni.k[25]); + tmp = _mm_aesdec_si128(tmp, p_k.ni.k[26]); + tmp = _mm_aesdec_si128(tmp, p_k.ni.k[27]); + _mm_storeu_si128((__m128i*)out, _mm_aesdeclast_si128(tmp, p_k.ni.k[0])); } -} // namespace ZeroTier +} // namespace ZeroTier -#endif // ZT_AES_AESNI +#endif // ZT_AES_AESNI diff --git a/node/AES_armcrypto.cpp b/node/AES_armcrypto.cpp index 2319ae85..3cb12dc2 100644 --- a/node/AES_armcrypto.cpp +++ b/node/AES_armcrypto.cpp @@ -11,8 +11,8 @@ */ /****/ -#include "Constants.hpp" #include "AES.hpp" +#include "Constants.hpp" #ifdef ZT_AES_NEON @@ -22,373 +22,379 @@ namespace { ZT_INLINE uint8x16_t s_clmul_armneon_crypto(uint8x16_t h, uint8x16_t y, const uint8_t b[16]) noexcept { - uint8x16_t r0, r1, t0, t1; - r0 = vld1q_u8(b); - const uint8x16_t z = veorq_u8(h, h); - y = veorq_u8(r0, y); - y = vrbitq_u8(y); - const uint8x16_t p = vreinterpretq_u8_u64(vdupq_n_u64(0x0000000000000087)); - t0 = vextq_u8(y, y, 8); - __asm__ __volatile__("pmull %0.1q, %1.1d, %2.1d \n\t" : "=w" (r0) : "w" (h), "w" (y)); - __asm__ __volatile__("pmull2 %0.1q, %1.2d, %2.2d \n\t" :"=w" (r1) : "w" (h), "w" (y)); - __asm__ __volatile__("pmull %0.1q, %1.1d, %2.1d \n\t" : "=w" (t1) : "w" (h), "w" (t0)); - __asm__ __volatile__("pmull2 %0.1q, %1.2d, %2.2d \n\t" :"=w" (t0) : "w" (h), "w" (t0)); - t0 = veorq_u8(t0, t1); - t1 = vextq_u8(z, t0, 8); - r0 = veorq_u8(r0, t1); - t1 = vextq_u8(t0, z, 8); - r1 = veorq_u8(r1, t1); - __asm__ __volatile__("pmull2 %0.1q, %1.2d, %2.2d \n\t" :"=w" (t0) : "w" (r1), "w" (p)); - t1 = vextq_u8(t0, z, 8); - r1 = veorq_u8(r1, t1); - t1 = vextq_u8(z, t0, 8); - r0 = veorq_u8(r0, t1); - __asm__ __volatile__("pmull %0.1q, %1.1d, %2.1d \n\t" : "=w" (t0) : "w" (r1), "w" (p)); - return vrbitq_u8(veorq_u8(r0, t0)); + uint8x16_t r0, r1, t0, t1; + r0 = vld1q_u8(b); + const uint8x16_t z = veorq_u8(h, h); + y = veorq_u8(r0, y); + y = vrbitq_u8(y); + const uint8x16_t p = vreinterpretq_u8_u64(vdupq_n_u64(0x0000000000000087)); + t0 = vextq_u8(y, y, 8); + __asm__ __volatile__("pmull %0.1q, %1.1d, %2.1d \n\t" : "=w"(r0) : "w"(h), "w"(y)); + __asm__ __volatile__("pmull2 %0.1q, %1.2d, %2.2d \n\t" : "=w"(r1) : "w"(h), "w"(y)); + __asm__ __volatile__("pmull %0.1q, %1.1d, %2.1d \n\t" : "=w"(t1) : "w"(h), "w"(t0)); + __asm__ __volatile__("pmull2 %0.1q, %1.2d, %2.2d \n\t" : "=w"(t0) : "w"(h), "w"(t0)); + t0 = veorq_u8(t0, t1); + t1 = vextq_u8(z, t0, 8); + r0 = veorq_u8(r0, t1); + t1 = vextq_u8(t0, z, 8); + r1 = veorq_u8(r1, t1); + __asm__ __volatile__("pmull2 %0.1q, %1.2d, %2.2d \n\t" : "=w"(t0) : "w"(r1), "w"(p)); + t1 = vextq_u8(t0, z, 8); + r1 = veorq_u8(r1, t1); + t1 = vextq_u8(z, t0, 8); + r0 = veorq_u8(r0, t1); + __asm__ __volatile__("pmull %0.1q, %1.1d, %2.1d \n\t" : "=w"(t0) : "w"(r1), "w"(p)); + return vrbitq_u8(veorq_u8(r0, t0)); } -} // anonymous namespace +} // anonymous namespace -void AES::GMAC::p_armUpdate(const uint8_t *in, unsigned int len) noexcept +void AES::GMAC::p_armUpdate(const uint8_t* in, unsigned int len) noexcept { - uint8x16_t y = vld1q_u8(reinterpret_cast(_y)); - const uint8x16_t h = _aes.p_k.neon.h; + uint8x16_t y = vld1q_u8(reinterpret_cast(_y)); + const uint8x16_t h = _aes.p_k.neon.h; - if (_rp) { - for(;;) { - if (!len) { - return; - } - --len; - _r[_rp++] = *(in++); - if (_rp == 16) { - y = s_clmul_armneon_crypto(h, y, _r); - break; - } - } - } + if (_rp) { + for (;;) { + if (! len) { + return; + } + --len; + _r[_rp++] = *(in++); + if (_rp == 16) { + y = s_clmul_armneon_crypto(h, y, _r); + break; + } + } + } - while (len >= 16) { - y = s_clmul_armneon_crypto(h, y, in); - in += 16; - len -= 16; - } + while (len >= 16) { + y = s_clmul_armneon_crypto(h, y, in); + in += 16; + len -= 16; + } - vst1q_u8(reinterpret_cast(_y), y); + vst1q_u8(reinterpret_cast(_y), y); - for (unsigned int i = 0; i < len; ++i) { - _r[i] = in[i]; - } - _rp = len; // len is always less than 16 here + for (unsigned int i = 0; i < len; ++i) { + _r[i] = in[i]; + } + _rp = len; // len is always less than 16 here } void AES::GMAC::p_armFinish(uint8_t tag[16]) noexcept { - uint64_t tmp[2]; - uint8x16_t y = vld1q_u8(reinterpret_cast(_y)); - const uint8x16_t h = _aes.p_k.neon.h; + uint64_t tmp[2]; + uint8x16_t y = vld1q_u8(reinterpret_cast(_y)); + const uint8x16_t h = _aes.p_k.neon.h; - if (_rp) { - while (_rp < 16) { - _r[_rp++] = 0; - } - y = s_clmul_armneon_crypto(h, y, _r); - } + if (_rp) { + while (_rp < 16) { + _r[_rp++] = 0; + } + y = s_clmul_armneon_crypto(h, y, _r); + } - tmp[0] = Utils::hton((uint64_t)_len << 3U); - tmp[1] = 0; - y = s_clmul_armneon_crypto(h, y, reinterpret_cast(tmp)); + tmp[0] = Utils::hton((uint64_t)_len << 3U); + tmp[1] = 0; + y = s_clmul_armneon_crypto(h, y, reinterpret_cast(tmp)); - Utils::copy< 12 >(tmp, _iv); + Utils::copy<12>(tmp, _iv); #if __BYTE_ORDER == __BIG_ENDIAN - reinterpret_cast(tmp)[3] = 0x00000001; + reinterpret_cast(tmp)[3] = 0x00000001; #else - reinterpret_cast(tmp)[3] = 0x01000000; + reinterpret_cast(tmp)[3] = 0x01000000; #endif - _aes.encrypt(tmp, tmp); + _aes.encrypt(tmp, tmp); - uint8x16_t yy = y; - Utils::storeMachineEndian< uint64_t >(tag, tmp[0] ^ reinterpret_cast(&yy)[0]); - Utils::storeMachineEndian< uint64_t >(tag + 8, tmp[1] ^ reinterpret_cast(&yy)[1]); + uint8x16_t yy = y; + Utils::storeMachineEndian(tag, tmp[0] ^ reinterpret_cast(&yy)[0]); + Utils::storeMachineEndian(tag + 8, tmp[1] ^ reinterpret_cast(&yy)[1]); } -void AES::CTR::p_armCrypt(const uint8_t *in, uint8_t *out, unsigned int len) noexcept +void AES::CTR::p_armCrypt(const uint8_t* in, uint8_t* out, unsigned int len) noexcept { - uint8x16_t dd = vrev32q_u8(vld1q_u8(reinterpret_cast(_ctr))); - const uint32x4_t one = {0,0,0,1}; + uint8x16_t dd = vrev32q_u8(vld1q_u8(reinterpret_cast(_ctr))); + const uint32x4_t one = { 0, 0, 0, 1 }; - uint8x16_t k0 = _aes.p_k.neon.ek[0]; - uint8x16_t k1 = _aes.p_k.neon.ek[1]; - uint8x16_t k2 = _aes.p_k.neon.ek[2]; - uint8x16_t k3 = _aes.p_k.neon.ek[3]; - uint8x16_t k4 = _aes.p_k.neon.ek[4]; - uint8x16_t k5 = _aes.p_k.neon.ek[5]; - uint8x16_t k6 = _aes.p_k.neon.ek[6]; - uint8x16_t k7 = _aes.p_k.neon.ek[7]; - uint8x16_t k8 = _aes.p_k.neon.ek[8]; - uint8x16_t k9 = _aes.p_k.neon.ek[9]; - uint8x16_t k10 = _aes.p_k.neon.ek[10]; - uint8x16_t k11 = _aes.p_k.neon.ek[11]; - uint8x16_t k12 = _aes.p_k.neon.ek[12]; - uint8x16_t k13 = _aes.p_k.neon.ek[13]; - uint8x16_t k14 = _aes.p_k.neon.ek[14]; + uint8x16_t k0 = _aes.p_k.neon.ek[0]; + uint8x16_t k1 = _aes.p_k.neon.ek[1]; + uint8x16_t k2 = _aes.p_k.neon.ek[2]; + uint8x16_t k3 = _aes.p_k.neon.ek[3]; + uint8x16_t k4 = _aes.p_k.neon.ek[4]; + uint8x16_t k5 = _aes.p_k.neon.ek[5]; + uint8x16_t k6 = _aes.p_k.neon.ek[6]; + uint8x16_t k7 = _aes.p_k.neon.ek[7]; + uint8x16_t k8 = _aes.p_k.neon.ek[8]; + uint8x16_t k9 = _aes.p_k.neon.ek[9]; + uint8x16_t k10 = _aes.p_k.neon.ek[10]; + uint8x16_t k11 = _aes.p_k.neon.ek[11]; + uint8x16_t k12 = _aes.p_k.neon.ek[12]; + uint8x16_t k13 = _aes.p_k.neon.ek[13]; + uint8x16_t k14 = _aes.p_k.neon.ek[14]; - unsigned int totalLen = _len; - if ((totalLen & 15U) != 0) { - for (;;) { - if (unlikely(!len)) { - vst1q_u8(reinterpret_cast(_ctr), vrev32q_u8(dd)); - _len = totalLen; - return; - } - --len; - out[totalLen++] = *(in++); - if ((totalLen & 15U) == 0) { - uint8_t *const otmp = out + (totalLen - 16); - uint8x16_t d0 = vrev32q_u8(dd); - uint8x16_t pt = vld1q_u8(otmp); - d0 = vaesmcq_u8(vaeseq_u8(d0, k0)); - d0 = vaesmcq_u8(vaeseq_u8(d0, k1)); - d0 = vaesmcq_u8(vaeseq_u8(d0, k2)); - d0 = vaesmcq_u8(vaeseq_u8(d0, k3)); - d0 = vaesmcq_u8(vaeseq_u8(d0, k4)); - d0 = vaesmcq_u8(vaeseq_u8(d0, k5)); - d0 = vaesmcq_u8(vaeseq_u8(d0, k6)); - d0 = vaesmcq_u8(vaeseq_u8(d0, k7)); - d0 = vaesmcq_u8(vaeseq_u8(d0, k8)); - d0 = vaesmcq_u8(vaeseq_u8(d0, k9)); - d0 = vaesmcq_u8(vaeseq_u8(d0, k10)); - d0 = vaesmcq_u8(vaeseq_u8(d0, k11)); - d0 = vaesmcq_u8(vaeseq_u8(d0, k12)); - d0 = veorq_u8(vaeseq_u8(d0, k13), k14); - vst1q_u8(otmp, veorq_u8(pt, d0)); - dd = (uint8x16_t)vaddq_u32((uint32x4_t)dd, one); - break; - } - } - } + unsigned int totalLen = _len; + if ((totalLen & 15U) != 0) { + for (;;) { + if (unlikely(! len)) { + vst1q_u8(reinterpret_cast(_ctr), vrev32q_u8(dd)); + _len = totalLen; + return; + } + --len; + out[totalLen++] = *(in++); + if ((totalLen & 15U) == 0) { + uint8_t* const otmp = out + (totalLen - 16); + uint8x16_t d0 = vrev32q_u8(dd); + uint8x16_t pt = vld1q_u8(otmp); + d0 = vaesmcq_u8(vaeseq_u8(d0, k0)); + d0 = vaesmcq_u8(vaeseq_u8(d0, k1)); + d0 = vaesmcq_u8(vaeseq_u8(d0, k2)); + d0 = vaesmcq_u8(vaeseq_u8(d0, k3)); + d0 = vaesmcq_u8(vaeseq_u8(d0, k4)); + d0 = vaesmcq_u8(vaeseq_u8(d0, k5)); + d0 = vaesmcq_u8(vaeseq_u8(d0, k6)); + d0 = vaesmcq_u8(vaeseq_u8(d0, k7)); + d0 = vaesmcq_u8(vaeseq_u8(d0, k8)); + d0 = vaesmcq_u8(vaeseq_u8(d0, k9)); + d0 = vaesmcq_u8(vaeseq_u8(d0, k10)); + d0 = vaesmcq_u8(vaeseq_u8(d0, k11)); + d0 = vaesmcq_u8(vaeseq_u8(d0, k12)); + d0 = veorq_u8(vaeseq_u8(d0, k13), k14); + vst1q_u8(otmp, veorq_u8(pt, d0)); + dd = (uint8x16_t)vaddq_u32((uint32x4_t)dd, one); + break; + } + } + } - out += totalLen; - _len = totalLen + len; + out += totalLen; + _len = totalLen + len; - if (likely(len >= 64)) { - const uint32x4_t four = vshlq_n_u32(one, 2); - uint8x16_t dd1 = (uint8x16_t)vaddq_u32((uint32x4_t)dd, one); - uint8x16_t dd2 = (uint8x16_t)vaddq_u32((uint32x4_t)dd1, one); - uint8x16_t dd3 = (uint8x16_t)vaddq_u32((uint32x4_t)dd2, one); - for (;;) { - len -= 64; - uint8x16_t d0 = vrev32q_u8(dd); - uint8x16_t d1 = vrev32q_u8(dd1); - uint8x16_t d2 = vrev32q_u8(dd2); - uint8x16_t d3 = vrev32q_u8(dd3); - uint8x16_t pt0 = vld1q_u8(in); - uint8x16_t pt1 = vld1q_u8(in + 16); - uint8x16_t pt2 = vld1q_u8(in + 32); - uint8x16_t pt3 = vld1q_u8(in + 48); + if (likely(len >= 64)) { + const uint32x4_t four = vshlq_n_u32(one, 2); + uint8x16_t dd1 = (uint8x16_t)vaddq_u32((uint32x4_t)dd, one); + uint8x16_t dd2 = (uint8x16_t)vaddq_u32((uint32x4_t)dd1, one); + uint8x16_t dd3 = (uint8x16_t)vaddq_u32((uint32x4_t)dd2, one); + for (;;) { + len -= 64; + uint8x16_t d0 = vrev32q_u8(dd); + uint8x16_t d1 = vrev32q_u8(dd1); + uint8x16_t d2 = vrev32q_u8(dd2); + uint8x16_t d3 = vrev32q_u8(dd3); + uint8x16_t pt0 = vld1q_u8(in); + uint8x16_t pt1 = vld1q_u8(in + 16); + uint8x16_t pt2 = vld1q_u8(in + 32); + uint8x16_t pt3 = vld1q_u8(in + 48); - d0 = vaesmcq_u8(vaeseq_u8(d0, k0)); - d1 = vaesmcq_u8(vaeseq_u8(d1, k0)); - d2 = vaesmcq_u8(vaeseq_u8(d2, k0)); - d3 = vaesmcq_u8(vaeseq_u8(d3, k0)); - d0 = vaesmcq_u8(vaeseq_u8(d0, k1)); - d1 = vaesmcq_u8(vaeseq_u8(d1, k1)); - d2 = vaesmcq_u8(vaeseq_u8(d2, k1)); - d3 = vaesmcq_u8(vaeseq_u8(d3, k1)); - d0 = vaesmcq_u8(vaeseq_u8(d0, k2)); - d1 = vaesmcq_u8(vaeseq_u8(d1, k2)); - d2 = vaesmcq_u8(vaeseq_u8(d2, k2)); - d3 = vaesmcq_u8(vaeseq_u8(d3, k2)); - d0 = vaesmcq_u8(vaeseq_u8(d0, k3)); - d1 = vaesmcq_u8(vaeseq_u8(d1, k3)); - d2 = vaesmcq_u8(vaeseq_u8(d2, k3)); - d3 = vaesmcq_u8(vaeseq_u8(d3, k3)); - d0 = vaesmcq_u8(vaeseq_u8(d0, k4)); - d1 = vaesmcq_u8(vaeseq_u8(d1, k4)); - d2 = vaesmcq_u8(vaeseq_u8(d2, k4)); - d3 = vaesmcq_u8(vaeseq_u8(d3, k4)); - d0 = vaesmcq_u8(vaeseq_u8(d0, k5)); - d1 = vaesmcq_u8(vaeseq_u8(d1, k5)); - d2 = vaesmcq_u8(vaeseq_u8(d2, k5)); - d3 = vaesmcq_u8(vaeseq_u8(d3, k5)); - d0 = vaesmcq_u8(vaeseq_u8(d0, k6)); - d1 = vaesmcq_u8(vaeseq_u8(d1, k6)); - d2 = vaesmcq_u8(vaeseq_u8(d2, k6)); - d3 = vaesmcq_u8(vaeseq_u8(d3, k6)); - d0 = vaesmcq_u8(vaeseq_u8(d0, k7)); - d1 = vaesmcq_u8(vaeseq_u8(d1, k7)); - d2 = vaesmcq_u8(vaeseq_u8(d2, k7)); - d3 = vaesmcq_u8(vaeseq_u8(d3, k7)); - d0 = vaesmcq_u8(vaeseq_u8(d0, k8)); - d1 = vaesmcq_u8(vaeseq_u8(d1, k8)); - d2 = vaesmcq_u8(vaeseq_u8(d2, k8)); - d3 = vaesmcq_u8(vaeseq_u8(d3, k8)); - d0 = vaesmcq_u8(vaeseq_u8(d0, k9)); - d1 = vaesmcq_u8(vaeseq_u8(d1, k9)); - d2 = vaesmcq_u8(vaeseq_u8(d2, k9)); - d3 = vaesmcq_u8(vaeseq_u8(d3, k9)); - d0 = vaesmcq_u8(vaeseq_u8(d0, k10)); - d1 = vaesmcq_u8(vaeseq_u8(d1, k10)); - d2 = vaesmcq_u8(vaeseq_u8(d2, k10)); - d3 = vaesmcq_u8(vaeseq_u8(d3, k10)); - d0 = vaesmcq_u8(vaeseq_u8(d0, k11)); - d1 = vaesmcq_u8(vaeseq_u8(d1, k11)); - d2 = vaesmcq_u8(vaeseq_u8(d2, k11)); - d3 = vaesmcq_u8(vaeseq_u8(d3, k11)); - d0 = vaesmcq_u8(vaeseq_u8(d0, k12)); - d1 = vaesmcq_u8(vaeseq_u8(d1, k12)); - d2 = vaesmcq_u8(vaeseq_u8(d2, k12)); - d3 = vaesmcq_u8(vaeseq_u8(d3, k12)); - d0 = veorq_u8(vaeseq_u8(d0, k13), k14); - d1 = veorq_u8(vaeseq_u8(d1, k13), k14); - d2 = veorq_u8(vaeseq_u8(d2, k13), k14); - d3 = veorq_u8(vaeseq_u8(d3, k13), k14); + d0 = vaesmcq_u8(vaeseq_u8(d0, k0)); + d1 = vaesmcq_u8(vaeseq_u8(d1, k0)); + d2 = vaesmcq_u8(vaeseq_u8(d2, k0)); + d3 = vaesmcq_u8(vaeseq_u8(d3, k0)); + d0 = vaesmcq_u8(vaeseq_u8(d0, k1)); + d1 = vaesmcq_u8(vaeseq_u8(d1, k1)); + d2 = vaesmcq_u8(vaeseq_u8(d2, k1)); + d3 = vaesmcq_u8(vaeseq_u8(d3, k1)); + d0 = vaesmcq_u8(vaeseq_u8(d0, k2)); + d1 = vaesmcq_u8(vaeseq_u8(d1, k2)); + d2 = vaesmcq_u8(vaeseq_u8(d2, k2)); + d3 = vaesmcq_u8(vaeseq_u8(d3, k2)); + d0 = vaesmcq_u8(vaeseq_u8(d0, k3)); + d1 = vaesmcq_u8(vaeseq_u8(d1, k3)); + d2 = vaesmcq_u8(vaeseq_u8(d2, k3)); + d3 = vaesmcq_u8(vaeseq_u8(d3, k3)); + d0 = vaesmcq_u8(vaeseq_u8(d0, k4)); + d1 = vaesmcq_u8(vaeseq_u8(d1, k4)); + d2 = vaesmcq_u8(vaeseq_u8(d2, k4)); + d3 = vaesmcq_u8(vaeseq_u8(d3, k4)); + d0 = vaesmcq_u8(vaeseq_u8(d0, k5)); + d1 = vaesmcq_u8(vaeseq_u8(d1, k5)); + d2 = vaesmcq_u8(vaeseq_u8(d2, k5)); + d3 = vaesmcq_u8(vaeseq_u8(d3, k5)); + d0 = vaesmcq_u8(vaeseq_u8(d0, k6)); + d1 = vaesmcq_u8(vaeseq_u8(d1, k6)); + d2 = vaesmcq_u8(vaeseq_u8(d2, k6)); + d3 = vaesmcq_u8(vaeseq_u8(d3, k6)); + d0 = vaesmcq_u8(vaeseq_u8(d0, k7)); + d1 = vaesmcq_u8(vaeseq_u8(d1, k7)); + d2 = vaesmcq_u8(vaeseq_u8(d2, k7)); + d3 = vaesmcq_u8(vaeseq_u8(d3, k7)); + d0 = vaesmcq_u8(vaeseq_u8(d0, k8)); + d1 = vaesmcq_u8(vaeseq_u8(d1, k8)); + d2 = vaesmcq_u8(vaeseq_u8(d2, k8)); + d3 = vaesmcq_u8(vaeseq_u8(d3, k8)); + d0 = vaesmcq_u8(vaeseq_u8(d0, k9)); + d1 = vaesmcq_u8(vaeseq_u8(d1, k9)); + d2 = vaesmcq_u8(vaeseq_u8(d2, k9)); + d3 = vaesmcq_u8(vaeseq_u8(d3, k9)); + d0 = vaesmcq_u8(vaeseq_u8(d0, k10)); + d1 = vaesmcq_u8(vaeseq_u8(d1, k10)); + d2 = vaesmcq_u8(vaeseq_u8(d2, k10)); + d3 = vaesmcq_u8(vaeseq_u8(d3, k10)); + d0 = vaesmcq_u8(vaeseq_u8(d0, k11)); + d1 = vaesmcq_u8(vaeseq_u8(d1, k11)); + d2 = vaesmcq_u8(vaeseq_u8(d2, k11)); + d3 = vaesmcq_u8(vaeseq_u8(d3, k11)); + d0 = vaesmcq_u8(vaeseq_u8(d0, k12)); + d1 = vaesmcq_u8(vaeseq_u8(d1, k12)); + d2 = vaesmcq_u8(vaeseq_u8(d2, k12)); + d3 = vaesmcq_u8(vaeseq_u8(d3, k12)); + d0 = veorq_u8(vaeseq_u8(d0, k13), k14); + d1 = veorq_u8(vaeseq_u8(d1, k13), k14); + d2 = veorq_u8(vaeseq_u8(d2, k13), k14); + d3 = veorq_u8(vaeseq_u8(d3, k13), k14); - d0 = veorq_u8(pt0, d0); - d1 = veorq_u8(pt1, d1); - d2 = veorq_u8(pt2, d2); - d3 = veorq_u8(pt3, d3); + d0 = veorq_u8(pt0, d0); + d1 = veorq_u8(pt1, d1); + d2 = veorq_u8(pt2, d2); + d3 = veorq_u8(pt3, d3); - vst1q_u8(out, d0); - vst1q_u8(out + 16, d1); - vst1q_u8(out + 32, d2); - vst1q_u8(out + 48, d3); + vst1q_u8(out, d0); + vst1q_u8(out + 16, d1); + vst1q_u8(out + 32, d2); + vst1q_u8(out + 48, d3); - out += 64; - in += 64; + out += 64; + in += 64; - dd = (uint8x16_t)vaddq_u32((uint32x4_t)dd, four); - if (unlikely(len < 64)) { - break; - } - dd1 = (uint8x16_t)vaddq_u32((uint32x4_t)dd1, four); - dd2 = (uint8x16_t)vaddq_u32((uint32x4_t)dd2, four); - dd3 = (uint8x16_t)vaddq_u32((uint32x4_t)dd3, four); - } - } + dd = (uint8x16_t)vaddq_u32((uint32x4_t)dd, four); + if (unlikely(len < 64)) { + break; + } + dd1 = (uint8x16_t)vaddq_u32((uint32x4_t)dd1, four); + dd2 = (uint8x16_t)vaddq_u32((uint32x4_t)dd2, four); + dd3 = (uint8x16_t)vaddq_u32((uint32x4_t)dd3, four); + } + } - while (len >= 16) { - len -= 16; - uint8x16_t d0 = vrev32q_u8(dd); - uint8x16_t pt = vld1q_u8(in); - in += 16; - dd = (uint8x16_t)vaddq_u32((uint32x4_t)dd, one); - d0 = vaesmcq_u8(vaeseq_u8(d0, k0)); - d0 = vaesmcq_u8(vaeseq_u8(d0, k1)); - d0 = vaesmcq_u8(vaeseq_u8(d0, k2)); - d0 = vaesmcq_u8(vaeseq_u8(d0, k3)); - d0 = vaesmcq_u8(vaeseq_u8(d0, k4)); - d0 = vaesmcq_u8(vaeseq_u8(d0, k5)); - d0 = vaesmcq_u8(vaeseq_u8(d0, k6)); - d0 = vaesmcq_u8(vaeseq_u8(d0, k7)); - d0 = vaesmcq_u8(vaeseq_u8(d0, k8)); - d0 = vaesmcq_u8(vaeseq_u8(d0, k9)); - d0 = vaesmcq_u8(vaeseq_u8(d0, k10)); - d0 = vaesmcq_u8(vaeseq_u8(d0, k11)); - d0 = vaesmcq_u8(vaeseq_u8(d0, k12)); - d0 = veorq_u8(vaeseq_u8(d0, k13), k14); - vst1q_u8(out, veorq_u8(pt, d0)); - out += 16; - } + while (len >= 16) { + len -= 16; + uint8x16_t d0 = vrev32q_u8(dd); + uint8x16_t pt = vld1q_u8(in); + in += 16; + dd = (uint8x16_t)vaddq_u32((uint32x4_t)dd, one); + d0 = vaesmcq_u8(vaeseq_u8(d0, k0)); + d0 = vaesmcq_u8(vaeseq_u8(d0, k1)); + d0 = vaesmcq_u8(vaeseq_u8(d0, k2)); + d0 = vaesmcq_u8(vaeseq_u8(d0, k3)); + d0 = vaesmcq_u8(vaeseq_u8(d0, k4)); + d0 = vaesmcq_u8(vaeseq_u8(d0, k5)); + d0 = vaesmcq_u8(vaeseq_u8(d0, k6)); + d0 = vaesmcq_u8(vaeseq_u8(d0, k7)); + d0 = vaesmcq_u8(vaeseq_u8(d0, k8)); + d0 = vaesmcq_u8(vaeseq_u8(d0, k9)); + d0 = vaesmcq_u8(vaeseq_u8(d0, k10)); + d0 = vaesmcq_u8(vaeseq_u8(d0, k11)); + d0 = vaesmcq_u8(vaeseq_u8(d0, k12)); + d0 = veorq_u8(vaeseq_u8(d0, k13), k14); + vst1q_u8(out, veorq_u8(pt, d0)); + out += 16; + } - // Any remaining input is placed in _out. This will be picked up and crypted - // on subsequent calls to crypt() or finish() as it'll mean _len will not be - // an even multiple of 16. - for (unsigned int i = 0; i < len; ++i) { - out[i] = in[i]; - } + // Any remaining input is placed in _out. This will be picked up and crypted + // on subsequent calls to crypt() or finish() as it'll mean _len will not be + // an even multiple of 16. + for (unsigned int i = 0; i < len; ++i) { + out[i] = in[i]; + } - vst1q_u8(reinterpret_cast(_ctr), vrev32q_u8(dd)); + vst1q_u8(reinterpret_cast(_ctr), vrev32q_u8(dd)); } #define ZT_INIT_ARMNEON_CRYPTO_SUBWORD(w) ((uint32_t)s_sbox[w & 0xffU] + ((uint32_t)s_sbox[(w >> 8U) & 0xffU] << 8U) + ((uint32_t)s_sbox[(w >> 16U) & 0xffU] << 16U) + ((uint32_t)s_sbox[(w >> 24U) & 0xffU] << 24U)) #define ZT_INIT_ARMNEON_CRYPTO_ROTWORD(w) (((w) << 8U) | ((w) >> 24U)) -#define ZT_INIT_ARMNEON_CRYPTO_NK 8 -#define ZT_INIT_ARMNEON_CRYPTO_NB 4 -#define ZT_INIT_ARMNEON_CRYPTO_NR 14 +#define ZT_INIT_ARMNEON_CRYPTO_NK 8 +#define ZT_INIT_ARMNEON_CRYPTO_NB 4 +#define ZT_INIT_ARMNEON_CRYPTO_NR 14 -void AES::p_init_armneon_crypto(const uint8_t *key) noexcept +void AES::p_init_armneon_crypto(const uint8_t* key) noexcept { - static const uint8_t s_sbox[256] = {0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, - 0x58, 0xcf, 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, - 0x65, 0x7a, 0xae, 0x08, 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16}; + static const uint8_t s_sbox[256] = { 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, + 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, + 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, + 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, + 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, + 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, + 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, + 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 }; - uint64_t h[2]; - uint32_t *const w = reinterpret_cast(p_k.neon.ek); + uint64_t h[2]; + uint32_t* const w = reinterpret_cast(p_k.neon.ek); - for (unsigned int i=0;i(&(p_k.neon.h), h); - p_k.neon.h = vrbitq_u8(p_k.neon.h); - p_k.sw.h[0] = Utils::ntoh(h[0]); - p_k.sw.h[1] = Utils::ntoh(h[1]); + p_encrypt_armneon_crypto(Utils::ZERO256, h); + Utils::copy<16>(&(p_k.neon.h), h); + p_k.neon.h = vrbitq_u8(p_k.neon.h); + p_k.sw.h[0] = Utils::ntoh(h[0]); + p_k.sw.h[1] = Utils::ntoh(h[1]); } -void AES::p_encrypt_armneon_crypto(const void *const in, void *const out) const noexcept +void AES::p_encrypt_armneon_crypto(const void* const in, void* const out) const noexcept { - uint8x16_t tmp = vld1q_u8(reinterpret_cast(in)); - tmp = vaesmcq_u8(vaeseq_u8(tmp, p_k.neon.ek[0])); - tmp = vaesmcq_u8(vaeseq_u8(tmp, p_k.neon.ek[1])); - tmp = vaesmcq_u8(vaeseq_u8(tmp, p_k.neon.ek[2])); - tmp = vaesmcq_u8(vaeseq_u8(tmp, p_k.neon.ek[3])); - tmp = vaesmcq_u8(vaeseq_u8(tmp, p_k.neon.ek[4])); - tmp = vaesmcq_u8(vaeseq_u8(tmp, p_k.neon.ek[5])); - tmp = vaesmcq_u8(vaeseq_u8(tmp, p_k.neon.ek[6])); - tmp = vaesmcq_u8(vaeseq_u8(tmp, p_k.neon.ek[7])); - tmp = vaesmcq_u8(vaeseq_u8(tmp, p_k.neon.ek[8])); - tmp = vaesmcq_u8(vaeseq_u8(tmp, p_k.neon.ek[9])); - tmp = vaesmcq_u8(vaeseq_u8(tmp, p_k.neon.ek[10])); - tmp = vaesmcq_u8(vaeseq_u8(tmp, p_k.neon.ek[11])); - tmp = vaesmcq_u8(vaeseq_u8(tmp, p_k.neon.ek[12])); - tmp = veorq_u8(vaeseq_u8(tmp, p_k.neon.ek[13]), p_k.neon.ek[14]); - vst1q_u8(reinterpret_cast(out), tmp); + uint8x16_t tmp = vld1q_u8(reinterpret_cast(in)); + tmp = vaesmcq_u8(vaeseq_u8(tmp, p_k.neon.ek[0])); + tmp = vaesmcq_u8(vaeseq_u8(tmp, p_k.neon.ek[1])); + tmp = vaesmcq_u8(vaeseq_u8(tmp, p_k.neon.ek[2])); + tmp = vaesmcq_u8(vaeseq_u8(tmp, p_k.neon.ek[3])); + tmp = vaesmcq_u8(vaeseq_u8(tmp, p_k.neon.ek[4])); + tmp = vaesmcq_u8(vaeseq_u8(tmp, p_k.neon.ek[5])); + tmp = vaesmcq_u8(vaeseq_u8(tmp, p_k.neon.ek[6])); + tmp = vaesmcq_u8(vaeseq_u8(tmp, p_k.neon.ek[7])); + tmp = vaesmcq_u8(vaeseq_u8(tmp, p_k.neon.ek[8])); + tmp = vaesmcq_u8(vaeseq_u8(tmp, p_k.neon.ek[9])); + tmp = vaesmcq_u8(vaeseq_u8(tmp, p_k.neon.ek[10])); + tmp = vaesmcq_u8(vaeseq_u8(tmp, p_k.neon.ek[11])); + tmp = vaesmcq_u8(vaeseq_u8(tmp, p_k.neon.ek[12])); + tmp = veorq_u8(vaeseq_u8(tmp, p_k.neon.ek[13]), p_k.neon.ek[14]); + vst1q_u8(reinterpret_cast(out), tmp); } -void AES::p_decrypt_armneon_crypto(const void *const in, void *const out) const noexcept +void AES::p_decrypt_armneon_crypto(const void* const in, void* const out) const noexcept { - uint8x16_t tmp = vld1q_u8(reinterpret_cast(in)); - tmp = vaesimcq_u8(vaesdq_u8(tmp, p_k.neon.dk[0])); - tmp = vaesimcq_u8(vaesdq_u8(tmp, p_k.neon.dk[1])); - tmp = vaesimcq_u8(vaesdq_u8(tmp, p_k.neon.dk[2])); - tmp = vaesimcq_u8(vaesdq_u8(tmp, p_k.neon.dk[3])); - tmp = vaesimcq_u8(vaesdq_u8(tmp, p_k.neon.dk[4])); - tmp = vaesimcq_u8(vaesdq_u8(tmp, p_k.neon.dk[5])); - tmp = vaesimcq_u8(vaesdq_u8(tmp, p_k.neon.dk[6])); - tmp = vaesimcq_u8(vaesdq_u8(tmp, p_k.neon.dk[7])); - tmp = vaesimcq_u8(vaesdq_u8(tmp, p_k.neon.dk[8])); - tmp = vaesimcq_u8(vaesdq_u8(tmp, p_k.neon.dk[9])); - tmp = vaesimcq_u8(vaesdq_u8(tmp, p_k.neon.dk[10])); - tmp = vaesimcq_u8(vaesdq_u8(tmp, p_k.neon.dk[11])); - tmp = vaesimcq_u8(vaesdq_u8(tmp, p_k.neon.dk[12])); - tmp = veorq_u8(vaesdq_u8(tmp, p_k.neon.dk[13]), p_k.neon.dk[14]); - vst1q_u8(reinterpret_cast(out), tmp); + uint8x16_t tmp = vld1q_u8(reinterpret_cast(in)); + tmp = vaesimcq_u8(vaesdq_u8(tmp, p_k.neon.dk[0])); + tmp = vaesimcq_u8(vaesdq_u8(tmp, p_k.neon.dk[1])); + tmp = vaesimcq_u8(vaesdq_u8(tmp, p_k.neon.dk[2])); + tmp = vaesimcq_u8(vaesdq_u8(tmp, p_k.neon.dk[3])); + tmp = vaesimcq_u8(vaesdq_u8(tmp, p_k.neon.dk[4])); + tmp = vaesimcq_u8(vaesdq_u8(tmp, p_k.neon.dk[5])); + tmp = vaesimcq_u8(vaesdq_u8(tmp, p_k.neon.dk[6])); + tmp = vaesimcq_u8(vaesdq_u8(tmp, p_k.neon.dk[7])); + tmp = vaesimcq_u8(vaesdq_u8(tmp, p_k.neon.dk[8])); + tmp = vaesimcq_u8(vaesdq_u8(tmp, p_k.neon.dk[9])); + tmp = vaesimcq_u8(vaesdq_u8(tmp, p_k.neon.dk[10])); + tmp = vaesimcq_u8(vaesdq_u8(tmp, p_k.neon.dk[11])); + tmp = vaesimcq_u8(vaesdq_u8(tmp, p_k.neon.dk[12])); + tmp = veorq_u8(vaesdq_u8(tmp, p_k.neon.dk[13]), p_k.neon.dk[14]); + vst1q_u8(reinterpret_cast(out), tmp); } -} // namespace ZeroTier +} // namespace ZeroTier -#endif // ZT_AES_NEON +#endif // ZT_AES_NEON diff --git a/node/Address.hpp b/node/Address.hpp index 69847b91..412921b0 100644 --- a/node/Address.hpp +++ b/node/Address.hpp @@ -14,147 +14,218 @@ #ifndef ZT_ADDRESS_HPP #define ZT_ADDRESS_HPP -#include -#include -#include -#include - -#include - +#include "Buffer.hpp" #include "Constants.hpp" #include "Utils.hpp" -#include "Buffer.hpp" + +#include +#include +#include +#include +#include namespace ZeroTier { /** * A ZeroTier address */ -class Address -{ -public: - Address() : _a(0) {} - Address(const Address &a) : _a(a._a) {} - Address(uint64_t a) : _a(a & 0xffffffffffULL) {} +class Address { + public: + Address() : _a(0) + { + } + Address(const Address& a) : _a(a._a) + { + } + Address(uint64_t a) : _a(a & 0xffffffffffULL) + { + } - /** - * @param bits Raw address -- 5 bytes, big-endian byte order - * @param len Length of array - */ - Address(const void *bits,unsigned int len) { setTo(bits,len); } + /** + * @param bits Raw address -- 5 bytes, big-endian byte order + * @param len Length of array + */ + Address(const void* bits, unsigned int len) + { + setTo(bits, len); + } - inline Address &operator=(const Address &a) { _a = a._a; return *this; } - inline Address &operator=(const uint64_t a) { _a = (a & 0xffffffffffULL); return *this; } + inline Address& operator=(const Address& a) + { + _a = a._a; + return *this; + } + inline Address& operator=(const uint64_t a) + { + _a = (a & 0xffffffffffULL); + return *this; + } - /** - * @param bits Raw address -- 5 bytes, big-endian byte order - * @param len Length of array - */ - inline void setTo(const void *bits,const unsigned int len) - { - if (len < ZT_ADDRESS_LENGTH) { - _a = 0; - return; - } - const unsigned char *b = (const unsigned char *)bits; - uint64_t a = ((uint64_t)*b++) << 32; - a |= ((uint64_t)*b++) << 24; - a |= ((uint64_t)*b++) << 16; - a |= ((uint64_t)*b++) << 8; - a |= ((uint64_t)*b); - _a = a; - } + /** + * @param bits Raw address -- 5 bytes, big-endian byte order + * @param len Length of array + */ + inline void setTo(const void* bits, const unsigned int len) + { + if (len < ZT_ADDRESS_LENGTH) { + _a = 0; + return; + } + const unsigned char* b = (const unsigned char*)bits; + uint64_t a = ((uint64_t)*b++) << 32; + a |= ((uint64_t)*b++) << 24; + a |= ((uint64_t)*b++) << 16; + a |= ((uint64_t)*b++) << 8; + a |= ((uint64_t)*b); + _a = a; + } - /** - * @param bits Buffer to hold 5-byte address in big-endian byte order - * @param len Length of array - */ - inline void copyTo(void *const bits,const unsigned int len) const - { - if (len < ZT_ADDRESS_LENGTH) { - return; - } - unsigned char *b = (unsigned char *)bits; - *(b++) = (unsigned char)((_a >> 32) & 0xff); - *(b++) = (unsigned char)((_a >> 24) & 0xff); - *(b++) = (unsigned char)((_a >> 16) & 0xff); - *(b++) = (unsigned char)((_a >> 8) & 0xff); - *b = (unsigned char)(_a & 0xff); - } + /** + * @param bits Buffer to hold 5-byte address in big-endian byte order + * @param len Length of array + */ + inline void copyTo(void* const bits, const unsigned int len) const + { + if (len < ZT_ADDRESS_LENGTH) { + return; + } + unsigned char* b = (unsigned char*)bits; + *(b++) = (unsigned char)((_a >> 32) & 0xff); + *(b++) = (unsigned char)((_a >> 24) & 0xff); + *(b++) = (unsigned char)((_a >> 16) & 0xff); + *(b++) = (unsigned char)((_a >> 8) & 0xff); + *b = (unsigned char)(_a & 0xff); + } - /** - * Append to a buffer in big-endian byte order - * - * @param b Buffer to append to - */ - template - inline void appendTo(Buffer &b) const - { - unsigned char *p = (unsigned char *)b.appendField(ZT_ADDRESS_LENGTH); - *(p++) = (unsigned char)((_a >> 32) & 0xff); - *(p++) = (unsigned char)((_a >> 24) & 0xff); - *(p++) = (unsigned char)((_a >> 16) & 0xff); - *(p++) = (unsigned char)((_a >> 8) & 0xff); - *p = (unsigned char)(_a & 0xff); - } + /** + * Append to a buffer in big-endian byte order + * + * @param b Buffer to append to + */ + template inline void appendTo(Buffer& b) const + { + unsigned char* p = (unsigned char*)b.appendField(ZT_ADDRESS_LENGTH); + *(p++) = (unsigned char)((_a >> 32) & 0xff); + *(p++) = (unsigned char)((_a >> 24) & 0xff); + *(p++) = (unsigned char)((_a >> 16) & 0xff); + *(p++) = (unsigned char)((_a >> 8) & 0xff); + *p = (unsigned char)(_a & 0xff); + } - /** - * @return Integer containing address (0 to 2^40) - */ - inline uint64_t toInt() const { return _a; } + /** + * @return Integer containing address (0 to 2^40) + */ + inline uint64_t toInt() const + { + return _a; + } - /** - * @return Hash code for use with Hashtable - */ - inline unsigned long hashCode() const { return (unsigned long)_a; } + /** + * @return Hash code for use with Hashtable + */ + inline unsigned long hashCode() const + { + return (unsigned long)_a; + } - /** - * @return Hexadecimal string - */ - inline char *toString(char buf[11]) const { return Utils::hex10(_a,buf); } + /** + * @return Hexadecimal string + */ + inline char* toString(char buf[11]) const + { + return Utils::hex10(_a, buf); + } - /** - * @return True if this address is not zero - */ - inline operator bool() const { return (_a != 0); } + /** + * @return True if this address is not zero + */ + inline operator bool() const + { + return (_a != 0); + } - /** - * Check if this address is reserved - * - * The all-zero null address and any address beginning with 0xff are - * reserved. (0xff is reserved for future use to designate possibly - * longer addresses, addresses based on IPv6 innards, etc.) - * - * @return True if address is reserved and may not be used - */ - inline bool isReserved() const { return ((!_a)||((_a >> 32) == ZT_ADDRESS_RESERVED_PREFIX)); } + /** + * Check if this address is reserved + * + * The all-zero null address and any address beginning with 0xff are + * reserved. (0xff is reserved for future use to designate possibly + * longer addresses, addresses based on IPv6 innards, etc.) + * + * @return True if address is reserved and may not be used + */ + inline bool isReserved() const + { + return ((! _a) || ((_a >> 32) == ZT_ADDRESS_RESERVED_PREFIX)); + } - /** - * @param i Value from 0 to 4 (inclusive) - * @return Byte at said position (address interpreted in big-endian order) - */ - inline uint8_t operator[](unsigned int i) const { return (uint8_t)(_a >> (32 - (i * 8))); } + /** + * @param i Value from 0 to 4 (inclusive) + * @return Byte at said position (address interpreted in big-endian order) + */ + inline uint8_t operator[](unsigned int i) const + { + return (uint8_t)(_a >> (32 - (i * 8))); + } - inline void zero() { _a = 0; } + inline void zero() + { + _a = 0; + } - inline bool operator==(const uint64_t &a) const { return (_a == (a & 0xffffffffffULL)); } - inline bool operator!=(const uint64_t &a) const { return (_a != (a & 0xffffffffffULL)); } - inline bool operator>(const uint64_t &a) const { return (_a > (a & 0xffffffffffULL)); } - inline bool operator<(const uint64_t &a) const { return (_a < (a & 0xffffffffffULL)); } - inline bool operator>=(const uint64_t &a) const { return (_a >= (a & 0xffffffffffULL)); } - inline bool operator<=(const uint64_t &a) const { return (_a <= (a & 0xffffffffffULL)); } + inline bool operator==(const uint64_t& a) const + { + return (_a == (a & 0xffffffffffULL)); + } + inline bool operator!=(const uint64_t& a) const + { + return (_a != (a & 0xffffffffffULL)); + } + inline bool operator>(const uint64_t& a) const + { + return (_a > (a & 0xffffffffffULL)); + } + inline bool operator<(const uint64_t& a) const + { + return (_a < (a & 0xffffffffffULL)); + } + inline bool operator>=(const uint64_t& a) const + { + return (_a >= (a & 0xffffffffffULL)); + } + inline bool operator<=(const uint64_t& a) const + { + return (_a <= (a & 0xffffffffffULL)); + } - inline bool operator==(const Address &a) const { return (_a == a._a); } - inline bool operator!=(const Address &a) const { return (_a != a._a); } - inline bool operator>(const Address &a) const { return (_a > a._a); } - inline bool operator<(const Address &a) const { return (_a < a._a); } - inline bool operator>=(const Address &a) const { return (_a >= a._a); } - inline bool operator<=(const Address &a) const { return (_a <= a._a); } + inline bool operator==(const Address& a) const + { + return (_a == a._a); + } + inline bool operator!=(const Address& a) const + { + return (_a != a._a); + } + inline bool operator>(const Address& a) const + { + return (_a > a._a); + } + inline bool operator<(const Address& a) const + { + return (_a < a._a); + } + inline bool operator>=(const Address& a) const + { + return (_a >= a._a); + } + inline bool operator<=(const Address& a) const + { + return (_a <= a._a); + } -private: - uint64_t _a; + private: + uint64_t _a; }; -} // namespace ZeroTier +} // namespace ZeroTier #endif diff --git a/node/AtomicCounter.hpp b/node/AtomicCounter.hpp index 5d0b21f3..2e935200 100644 --- a/node/AtomicCounter.hpp +++ b/node/AtomicCounter.hpp @@ -25,49 +25,56 @@ namespace ZeroTier { /** * Simple atomic counter supporting increment and decrement */ -class AtomicCounter -{ -public: - AtomicCounter() { _v = 0; } +class AtomicCounter { + public: + AtomicCounter() + { + _v = 0; + } - inline int load() const - { + inline int load() const + { #ifdef __GNUC__ - return __sync_or_and_fetch(const_cast(&_v),0); + return __sync_or_and_fetch(const_cast(&_v), 0); #else - return _v.load(); + return _v.load(); #endif - } + } - inline int operator++() - { + inline int operator++() + { #ifdef __GNUC__ - return __sync_add_and_fetch(&_v,1); + return __sync_add_and_fetch(&_v, 1); #else - return ++_v; + return ++_v; #endif - } + } - inline int operator--() - { + inline int operator--() + { #ifdef __GNUC__ - return __sync_sub_and_fetch(&_v,1); + return __sync_sub_and_fetch(&_v, 1); #else - return --_v; + return --_v; #endif - } + } -private: - AtomicCounter(const AtomicCounter &) {} - const AtomicCounter &operator=(const AtomicCounter &) { return *this; } + private: + AtomicCounter(const AtomicCounter&) + { + } + const AtomicCounter& operator=(const AtomicCounter&) + { + return *this; + } #ifdef __GNUC__ - int _v; + int _v; #else - std::atomic_int _v; + std::atomic_int _v; #endif }; -} // namespace ZeroTier +} // namespace ZeroTier #endif diff --git a/node/Bond.cpp b/node/Bond.cpp index 2a061796..488fa87b 100644 --- a/node/Bond.cpp +++ b/node/Bond.cpp @@ -48,2008 +48,2008 @@ std::map > > Bond::_interface bool Bond::linkAllowed(std::string& policyAlias, SharedPtr link) { - if (! link) { - return false; - } - bool foundInDefinitions = false; - if (_linkDefinitions.count(policyAlias)) { - auto it = _linkDefinitions[policyAlias].begin(); - while (it != _linkDefinitions[policyAlias].end()) { - if (link->ifname() == (*it)->ifname()) { - foundInDefinitions = true; - break; - } - ++it; - } - } - return _linkDefinitions[policyAlias].empty() || foundInDefinitions; + if (! link) { + return false; + } + bool foundInDefinitions = false; + if (_linkDefinitions.count(policyAlias)) { + auto it = _linkDefinitions[policyAlias].begin(); + while (it != _linkDefinitions[policyAlias].end()) { + if (link->ifname() == (*it)->ifname()) { + foundInDefinitions = true; + break; + } + ++it; + } + } + return _linkDefinitions[policyAlias].empty() || foundInDefinitions; } void Bond::addCustomLink(std::string& policyAlias, SharedPtr link) { - Mutex::Lock _l(_links_m); - _linkDefinitions[policyAlias].push_back(link); - auto search = _interfaceToLinkMap[policyAlias].find(link->ifname()); - if (search == _interfaceToLinkMap[policyAlias].end()) { - link->setAsUserSpecified(true); - _interfaceToLinkMap[policyAlias].insert(std::pair >(link->ifname(), link)); - } + Mutex::Lock _l(_links_m); + _linkDefinitions[policyAlias].push_back(link); + auto search = _interfaceToLinkMap[policyAlias].find(link->ifname()); + if (search == _interfaceToLinkMap[policyAlias].end()) { + link->setAsUserSpecified(true); + _interfaceToLinkMap[policyAlias].insert(std::pair >(link->ifname(), link)); + } } bool Bond::addCustomPolicy(const SharedPtr& newBond) { - Mutex::Lock _l(_bonds_m); - if (! _bondPolicyTemplates.count(newBond->policyAlias())) { - _bondPolicyTemplates[newBond->policyAlias()] = newBond; - return true; - } - return false; + Mutex::Lock _l(_bonds_m); + if (! _bondPolicyTemplates.count(newBond->policyAlias())) { + _bondPolicyTemplates[newBond->policyAlias()] = newBond; + return true; + } + return false; } bool Bond::assignBondingPolicyToPeer(int64_t identity, const std::string& policyAlias) { - Mutex::Lock _l(_bonds_m); - if (! _policyTemplateAssignments.count(identity)) { - _policyTemplateAssignments[identity] = policyAlias; - return true; - } - return false; + Mutex::Lock _l(_bonds_m); + if (! _policyTemplateAssignments.count(identity)) { + _policyTemplateAssignments[identity] = policyAlias; + return true; + } + return false; } SharedPtr Bond::getBondByPeerId(int64_t identity) { - Mutex::Lock _l(_bonds_m); - return _bonds.count(identity) ? _bonds[identity] : SharedPtr(); + Mutex::Lock _l(_bonds_m); + return _bonds.count(identity) ? _bonds[identity] : SharedPtr(); } bool Bond::setAllMtuByTuple(uint16_t mtu, const std::string& ifStr, const std::string& ipStr) { - Mutex::Lock _l(_bonds_m); - std::map >::iterator bondItr = _bonds.begin(); - bool found = false; - while (bondItr != _bonds.end()) { - if (bondItr->second->setMtuByTuple(mtu, ifStr, ipStr)) { - found = true; - } - ++bondItr; - } - return found; + Mutex::Lock _l(_bonds_m); + std::map >::iterator bondItr = _bonds.begin(); + bool found = false; + while (bondItr != _bonds.end()) { + if (bondItr->second->setMtuByTuple(mtu, ifStr, ipStr)) { + found = true; + } + ++bondItr; + } + return found; } bool Bond::setMtuByTuple(uint16_t mtu, const std::string& ifStr, const std::string& ipStr) { - Mutex::Lock _lp(_paths_m); - bool found = false; - for (int i = 0; i < ZT_MAX_PEER_NETWORK_PATHS; ++i) { - if (_paths[i].p) { - SharedPtr sl = getLink(_paths[i].p); - if (sl) { - if (sl->ifname() == ifStr) { - char ipBuf[64] = { 0 }; - _paths[i].p->address().toIpString(ipBuf); - std::string newString = std::string(ipBuf); - if (newString == ipStr) { - _paths[i].p->_mtu = mtu; - found = true; - } - } - } - } - } - return found; + Mutex::Lock _lp(_paths_m); + bool found = false; + for (int i = 0; i < ZT_MAX_PEER_NETWORK_PATHS; ++i) { + if (_paths[i].p) { + SharedPtr sl = getLink(_paths[i].p); + if (sl) { + if (sl->ifname() == ifStr) { + char ipBuf[64] = { 0 }; + _paths[i].p->address().toIpString(ipBuf); + std::string newString = std::string(ipBuf); + if (newString == ipStr) { + _paths[i].p->_mtu = mtu; + found = true; + } + } + } + } + } + return found; } SharedPtr Bond::createBond(const RuntimeEnvironment* renv, const SharedPtr& peer) { - Mutex::Lock _l(_bonds_m); - int64_t identity = peer->identity().address().toInt(); - Bond* bond = nullptr; - if (! _bonds.count(identity)) { - if (! _policyTemplateAssignments.count(identity)) { - if (_defaultPolicy) { - bond = new Bond(renv, _defaultPolicy, peer); - bond->debug("new default bond"); - } - if (! _defaultPolicy && _defaultPolicyStr.length()) { - bond = new Bond(renv, _bondPolicyTemplates[_defaultPolicyStr].ptr(), peer); - bond->debug("new default custom bond (based on %s)", bond->getPolicyStrByCode(bond->policy()).c_str()); - } - } - else { - if (! _bondPolicyTemplates[_policyTemplateAssignments[identity]]) { - bond = new Bond(renv, _defaultPolicy, peer); - bond->debug("peer-specific bond, was specified as %s but the bond definition was not found, using default %s", _policyTemplateAssignments[identity].c_str(), getPolicyStrByCode(_defaultPolicy).c_str()); - } - else { - bond = new Bond(renv, _bondPolicyTemplates[_policyTemplateAssignments[identity]].ptr(), peer); - bond->debug("new default bond"); - } - } - } - if (bond) { - _bonds[identity] = bond; - /** - * Determine if user has specified anything that could affect the bonding policy's decisions - */ - if (_interfaceToLinkMap.count(bond->policyAlias())) { - std::map >::iterator it = _interfaceToLinkMap[bond->policyAlias()].begin(); - while (it != _interfaceToLinkMap[bond->policyAlias()].end()) { - if (it->second->isUserSpecified()) { - bond->_userHasSpecifiedLinks = true; - } - if (it->second->isUserSpecified() && it->second->primary()) { - bond->_userHasSpecifiedPrimaryLink = true; - } - if (it->second->isUserSpecified() && it->second->userHasSpecifiedFailoverInstructions()) { - bond->_userHasSpecifiedFailoverInstructions = true; - } - if (it->second->isUserSpecified() && (it->second->capacity() > 0)) { - bond->_userHasSpecifiedLinkCapacities = true; - } - ++it; - } - } - bond->startBond(); - return bond; - } - return SharedPtr(); + Mutex::Lock _l(_bonds_m); + int64_t identity = peer->identity().address().toInt(); + Bond* bond = nullptr; + if (! _bonds.count(identity)) { + if (! _policyTemplateAssignments.count(identity)) { + if (_defaultPolicy) { + bond = new Bond(renv, _defaultPolicy, peer); + bond->debug("new default bond"); + } + if (! _defaultPolicy && _defaultPolicyStr.length()) { + bond = new Bond(renv, _bondPolicyTemplates[_defaultPolicyStr].ptr(), peer); + bond->debug("new default custom bond (based on %s)", bond->getPolicyStrByCode(bond->policy()).c_str()); + } + } + else { + if (! _bondPolicyTemplates[_policyTemplateAssignments[identity]]) { + bond = new Bond(renv, _defaultPolicy, peer); + bond->debug("peer-specific bond, was specified as %s but the bond definition was not found, using default %s", _policyTemplateAssignments[identity].c_str(), getPolicyStrByCode(_defaultPolicy).c_str()); + } + else { + bond = new Bond(renv, _bondPolicyTemplates[_policyTemplateAssignments[identity]].ptr(), peer); + bond->debug("new default bond"); + } + } + } + if (bond) { + _bonds[identity] = bond; + /** + * Determine if user has specified anything that could affect the bonding policy's decisions + */ + if (_interfaceToLinkMap.count(bond->policyAlias())) { + std::map >::iterator it = _interfaceToLinkMap[bond->policyAlias()].begin(); + while (it != _interfaceToLinkMap[bond->policyAlias()].end()) { + if (it->second->isUserSpecified()) { + bond->_userHasSpecifiedLinks = true; + } + if (it->second->isUserSpecified() && it->second->primary()) { + bond->_userHasSpecifiedPrimaryLink = true; + } + if (it->second->isUserSpecified() && it->second->userHasSpecifiedFailoverInstructions()) { + bond->_userHasSpecifiedFailoverInstructions = true; + } + if (it->second->isUserSpecified() && (it->second->capacity() > 0)) { + bond->_userHasSpecifiedLinkCapacities = true; + } + ++it; + } + } + bond->startBond(); + return bond; + } + return SharedPtr(); } void Bond::destroyBond(uint64_t peerId) { - Mutex::Lock _l(_bonds_m); - auto iter = _bonds.find(peerId); - if (iter != _bonds.end()) { - iter->second->stopBond(); - _bonds.erase(iter); - } + Mutex::Lock _l(_bonds_m); + auto iter = _bonds.find(peerId); + if (iter != _bonds.end()) { + iter->second->stopBond(); + _bonds.erase(iter); + } } void Bond::stopBond() { - debug("stopping bond"); - _run = false; + debug("stopping bond"); + _run = false; } void Bond::startBond() { - debug("starting bond"); - _run = true; + debug("starting bond"); + _run = true; } SharedPtr Bond::getLinkBySocket(const std::string& policyAlias, uint64_t localSocket, bool createIfNeeded = false) { - Mutex::Lock _l(_links_m); - char ifname[ZT_MAX_PHYSIFNAME] = {}; - _binder->getIfName((PhySocket*)((uintptr_t)localSocket), ifname, sizeof(ifname) - 1); - std::string ifnameStr(ifname); - auto search = _interfaceToLinkMap[policyAlias].find(ifnameStr); - if (search == _interfaceToLinkMap[policyAlias].end()) { - if (createIfNeeded) { - SharedPtr s = new Link(ifnameStr, 0, 0, 0, true, ZT_BOND_SLAVE_MODE_PRIMARY, ""); - _interfaceToLinkMap[policyAlias].insert(std::pair >(ifnameStr, s)); - return s; - } - else { - return SharedPtr(); - } - } - else { - return search->second; - } + Mutex::Lock _l(_links_m); + char ifname[ZT_MAX_PHYSIFNAME] = {}; + _binder->getIfName((PhySocket*)((uintptr_t)localSocket), ifname, sizeof(ifname) - 1); + std::string ifnameStr(ifname); + auto search = _interfaceToLinkMap[policyAlias].find(ifnameStr); + if (search == _interfaceToLinkMap[policyAlias].end()) { + if (createIfNeeded) { + SharedPtr s = new Link(ifnameStr, 0, 0, 0, true, ZT_BOND_SLAVE_MODE_PRIMARY, ""); + _interfaceToLinkMap[policyAlias].insert(std::pair >(ifnameStr, s)); + return s; + } + else { + return SharedPtr(); + } + } + else { + return search->second; + } } SharedPtr Bond::getLinkByName(const std::string& policyAlias, const std::string& ifname) { - Mutex::Lock _l(_links_m); - auto search = _interfaceToLinkMap[policyAlias].find(ifname); - if (search != _interfaceToLinkMap[policyAlias].end()) { - return search->second; - } - return SharedPtr(); + Mutex::Lock _l(_links_m); + auto search = _interfaceToLinkMap[policyAlias].find(ifname); + if (search != _interfaceToLinkMap[policyAlias].end()) { + return search->second; + } + return SharedPtr(); } void Bond::processBackgroundTasks(void* tPtr, const int64_t now) { - unsigned long _currMinReqMonitorInterval = ZT_BOND_FAILOVER_DEFAULT_INTERVAL; - Mutex::Lock _l(_bonds_m); - std::map >::iterator bondItr = _bonds.begin(); - while (bondItr != _bonds.end()) { - // Update Bond Controller's background processing timer - _currMinReqMonitorInterval = std::min(_currMinReqMonitorInterval, (unsigned long)(bondItr->second->monitorInterval())); - bondItr->second->processBackgroundBondTasks(tPtr, now); - ++bondItr; - } - _minReqMonitorInterval = std::min(_currMinReqMonitorInterval, (unsigned long)ZT_BOND_FAILOVER_DEFAULT_INTERVAL); + unsigned long _currMinReqMonitorInterval = ZT_BOND_FAILOVER_DEFAULT_INTERVAL; + Mutex::Lock _l(_bonds_m); + std::map >::iterator bondItr = _bonds.begin(); + while (bondItr != _bonds.end()) { + // Update Bond Controller's background processing timer + _currMinReqMonitorInterval = std::min(_currMinReqMonitorInterval, (unsigned long)(bondItr->second->monitorInterval())); + bondItr->second->processBackgroundBondTasks(tPtr, now); + ++bondItr; + } + _minReqMonitorInterval = std::min(_currMinReqMonitorInterval, (unsigned long)ZT_BOND_FAILOVER_DEFAULT_INTERVAL); } Bond::Bond(const RuntimeEnvironment* renv) : RR(renv) { - initTimers(); + initTimers(); } Bond::Bond(const RuntimeEnvironment* renv, int policy, const SharedPtr& peer) : RR(renv), _freeRandomByte((unsigned char)((uintptr_t)this >> 4) ^ ++s_freeRandomByteCounter), _peer(peer), _peerId(_peer->_id.address().toInt()) { - initTimers(); - setBondParameters(policy, SharedPtr(), false); - _policyAlias = getPolicyStrByCode(policy); + initTimers(); + setBondParameters(policy, SharedPtr(), false); + _policyAlias = getPolicyStrByCode(policy); } Bond::Bond(const RuntimeEnvironment* renv, std::string& basePolicy, std::string& policyAlias, const SharedPtr& peer) : RR(renv), _policyAlias(policyAlias), _peer(peer) { - initTimers(); - setBondParameters(getPolicyCodeByStr(basePolicy), SharedPtr(), false); + initTimers(); + setBondParameters(getPolicyCodeByStr(basePolicy), SharedPtr(), false); } Bond::Bond(const RuntimeEnvironment* renv, SharedPtr originalBond, const SharedPtr& peer) - : RR(renv) - , _freeRandomByte((unsigned char)((uintptr_t)this >> 4) ^ ++s_freeRandomByteCounter) - , _peer(peer) - , _peerId(_peer->_id.address().toInt()) + : RR(renv) + , _freeRandomByte((unsigned char)((uintptr_t)this >> 4) ^ ++s_freeRandomByteCounter) + , _peer(peer) + , _peerId(_peer->_id.address().toInt()) { - initTimers(); - setBondParameters(originalBond->_policy, originalBond, true); + initTimers(); + setBondParameters(originalBond->_policy, originalBond, true); } void Bond::nominatePathToBond(const SharedPtr& path, int64_t now) { - Mutex::Lock _l(_paths_m); - debug("attempting to nominate link %s", pathToStr(path).c_str()); - /** - * Ensure the link is allowed and the path is not already present - */ - if (! RR->bc->linkAllowed(_policyAlias, getLinkBySocket(_policyAlias, path->localSocket(), true))) { - debug("link %s is not allowed according to user-specified rules", pathToStr(path).c_str()); - return; - } - bool alreadyPresent = false; - for (int i = 0; i < ZT_MAX_PEER_NETWORK_PATHS; ++i) { - // Sanity check - if (path.ptr() == _paths[i].p.ptr()) { - alreadyPresent = true; - debug("link %s already exists", pathToStr(path).c_str()); - break; - } - } - if (! alreadyPresent) { - SharedPtr link = getLink(path); - if (link) { - std::string ifnameStr = std::string(link->ifname()); - memset(path->_ifname, 0x0, ZT_MAX_PHYSIFNAME); - memcpy(path->_ifname, ifnameStr.c_str(), std::min((int)ifnameStr.length(), ZT_MAX_PHYSIFNAME)); - } - /** - * Find somewhere to stick it - */ - for (int i = 0; i < ZT_MAX_PEER_NETWORK_PATHS; ++i) { - if (! _paths[i].p) { - _paths[i].set(now, path); - /** - * Set user preferences and update state variables of other paths on the same link - */ - SharedPtr sl = getLink(_paths[i].p); - if (sl) { - // Determine if there are any other paths on this link - bool bFoundCommonLink = false; - SharedPtr commonLink = RR->bc->getLinkBySocket(_policyAlias, _paths[i].p->localSocket()); - if (commonLink) { - for (unsigned int j = 0; j < ZT_MAX_PEER_NETWORK_PATHS; ++j) { - if (_paths[j].p && _paths[j].p.ptr() != _paths[i].p.ptr()) { - if (RR->bc->getLinkBySocket(_policyAlias, _paths[j].p->localSocket(), true) == commonLink) { - bFoundCommonLink = true; - _paths[j].onlyPathOnLink = false; - } - } - } - _paths[i].ipvPref = sl->ipvPref(); - _paths[i].mode = sl->mode(); - _paths[i].enabled = sl->enabled(); - _paths[i].localPort = _phy->getLocalPort((PhySocket*)((uintptr_t)path->localSocket())); - _paths[i].onlyPathOnLink = ! bFoundCommonLink; - } - } - log("nominated link %s", pathToStr(path).c_str()); - break; - } - } - } - curateBond(now, true); - estimatePathQuality(now); + Mutex::Lock _l(_paths_m); + debug("attempting to nominate link %s", pathToStr(path).c_str()); + /** + * Ensure the link is allowed and the path is not already present + */ + if (! RR->bc->linkAllowed(_policyAlias, getLinkBySocket(_policyAlias, path->localSocket(), true))) { + debug("link %s is not allowed according to user-specified rules", pathToStr(path).c_str()); + return; + } + bool alreadyPresent = false; + for (int i = 0; i < ZT_MAX_PEER_NETWORK_PATHS; ++i) { + // Sanity check + if (path.ptr() == _paths[i].p.ptr()) { + alreadyPresent = true; + debug("link %s already exists", pathToStr(path).c_str()); + break; + } + } + if (! alreadyPresent) { + SharedPtr link = getLink(path); + if (link) { + std::string ifnameStr = std::string(link->ifname()); + memset(path->_ifname, 0x0, ZT_MAX_PHYSIFNAME); + memcpy(path->_ifname, ifnameStr.c_str(), std::min((int)ifnameStr.length(), ZT_MAX_PHYSIFNAME)); + } + /** + * Find somewhere to stick it + */ + for (int i = 0; i < ZT_MAX_PEER_NETWORK_PATHS; ++i) { + if (! _paths[i].p) { + _paths[i].set(now, path); + /** + * Set user preferences and update state variables of other paths on the same link + */ + SharedPtr sl = getLink(_paths[i].p); + if (sl) { + // Determine if there are any other paths on this link + bool bFoundCommonLink = false; + SharedPtr commonLink = RR->bc->getLinkBySocket(_policyAlias, _paths[i].p->localSocket()); + if (commonLink) { + for (unsigned int j = 0; j < ZT_MAX_PEER_NETWORK_PATHS; ++j) { + if (_paths[j].p && _paths[j].p.ptr() != _paths[i].p.ptr()) { + if (RR->bc->getLinkBySocket(_policyAlias, _paths[j].p->localSocket(), true) == commonLink) { + bFoundCommonLink = true; + _paths[j].onlyPathOnLink = false; + } + } + } + _paths[i].ipvPref = sl->ipvPref(); + _paths[i].mode = sl->mode(); + _paths[i].enabled = sl->enabled(); + _paths[i].localPort = _phy->getLocalPort((PhySocket*)((uintptr_t)path->localSocket())); + _paths[i].onlyPathOnLink = ! bFoundCommonLink; + } + } + log("nominated link %s", pathToStr(path).c_str()); + break; + } + } + } + curateBond(now, true); + estimatePathQuality(now); } void Bond::addPathToBond(int nominatedIdx, int bondedIdx) { - // Map bonded set to nominated set - _realIdxMap[bondedIdx] = nominatedIdx; - // Tell the bonding layer that we can now use this path for traffic - _paths[nominatedIdx].bonded = true; + // Map bonded set to nominated set + _realIdxMap[bondedIdx] = nominatedIdx; + // Tell the bonding layer that we can now use this path for traffic + _paths[nominatedIdx].bonded = true; } SharedPtr Bond::getAppropriatePath(int64_t now, int32_t flowId) { - Mutex::Lock _l(_paths_m); - /** - * active-backup - */ - if (_policy == ZT_BOND_POLICY_ACTIVE_BACKUP) { - if (_abPathIdx != ZT_MAX_PEER_NETWORK_PATHS && _paths[_abPathIdx].p) { - //fprintf(stderr, "trying to send via (_abPathIdx=%d) %s\n", _abPathIdx, pathToStr(_paths[_abPathIdx].p).c_str()); - return _paths[_abPathIdx].p; - } - } - /** - * broadcast - */ - if (_policy == ZT_BOND_POLICY_BROADCAST) { - return SharedPtr(); // Handled in Switch::_trySend() - } - if (! _numBondedPaths) { - return SharedPtr(); // No paths assigned to bond yet, cannot balance traffic - } - /** - * balance-rr - */ - if (_policy == ZT_BOND_POLICY_BALANCE_RR) { - if (_packetsPerLink == 0) { - // Randomly select a path - return _paths[_realIdxMap[_freeRandomByte % _numBondedPaths]].p; - } - if (_rrPacketsSentOnCurrLink < _packetsPerLink) { - // Continue to use this link - ++_rrPacketsSentOnCurrLink; - return _paths[_realIdxMap[_rrIdx]].p; - } - // Reset striping counter - _rrPacketsSentOnCurrLink = 0; - if (_numBondedPaths == 1 || _rrIdx >= (ZT_MAX_PEER_NETWORK_PATHS - 1)) { - _rrIdx = 0; - } - else { - int _tempIdx = _rrIdx; - for (int searchCount = 0; searchCount < (_numBondedPaths - 1); searchCount++) { - _tempIdx = (_tempIdx == (_numBondedPaths - 1)) ? 0 : _tempIdx + 1; - if (_realIdxMap[_tempIdx] != ZT_MAX_PEER_NETWORK_PATHS) { - if (_paths[_realIdxMap[_tempIdx]].p && _paths[_realIdxMap[_tempIdx]].eligible) { - _rrIdx = _tempIdx; - break; - } - } - } - } - if (_paths[_realIdxMap[_rrIdx]].p) { - return _paths[_realIdxMap[_rrIdx]].p; - } - } - /** - * balance-xor/aware - */ - if (_policy == ZT_BOND_POLICY_BALANCE_XOR || _policy == ZT_BOND_POLICY_BALANCE_AWARE) { - if (flowId == -1) { - // No specific path required for unclassified traffic, send on anything - int m_idx = _realIdxMap[_freeRandomByte % _numBondedPaths]; - return _paths[m_idx].p; - } - Mutex::Lock _l(_flows_m); - std::map >::iterator it = _flows.find(flowId); - if (likely(it != _flows.end())) { - it->second->lastActivity = now; - return _paths[it->second->assignedPath].p; - } - else { - unsigned char entropy; - Utils::getSecureRandom(&entropy, 1); - SharedPtr flow = createFlow(ZT_MAX_PEER_NETWORK_PATHS, flowId, entropy, now); - _flows[flowId] = flow; - return _paths[flow->assignedPath].p; - } - } - return SharedPtr(); + Mutex::Lock _l(_paths_m); + /** + * active-backup + */ + if (_policy == ZT_BOND_POLICY_ACTIVE_BACKUP) { + if (_abPathIdx != ZT_MAX_PEER_NETWORK_PATHS && _paths[_abPathIdx].p) { + // fprintf(stderr, "trying to send via (_abPathIdx=%d) %s\n", _abPathIdx, pathToStr(_paths[_abPathIdx].p).c_str()); + return _paths[_abPathIdx].p; + } + } + /** + * broadcast + */ + if (_policy == ZT_BOND_POLICY_BROADCAST) { + return SharedPtr(); // Handled in Switch::_trySend() + } + if (! _numBondedPaths) { + return SharedPtr(); // No paths assigned to bond yet, cannot balance traffic + } + /** + * balance-rr + */ + if (_policy == ZT_BOND_POLICY_BALANCE_RR) { + if (_packetsPerLink == 0) { + // Randomly select a path + return _paths[_realIdxMap[_freeRandomByte % _numBondedPaths]].p; + } + if (_rrPacketsSentOnCurrLink < _packetsPerLink) { + // Continue to use this link + ++_rrPacketsSentOnCurrLink; + return _paths[_realIdxMap[_rrIdx]].p; + } + // Reset striping counter + _rrPacketsSentOnCurrLink = 0; + if (_numBondedPaths == 1 || _rrIdx >= (ZT_MAX_PEER_NETWORK_PATHS - 1)) { + _rrIdx = 0; + } + else { + int _tempIdx = _rrIdx; + for (int searchCount = 0; searchCount < (_numBondedPaths - 1); searchCount++) { + _tempIdx = (_tempIdx == (_numBondedPaths - 1)) ? 0 : _tempIdx + 1; + if (_realIdxMap[_tempIdx] != ZT_MAX_PEER_NETWORK_PATHS) { + if (_paths[_realIdxMap[_tempIdx]].p && _paths[_realIdxMap[_tempIdx]].eligible) { + _rrIdx = _tempIdx; + break; + } + } + } + } + if (_paths[_realIdxMap[_rrIdx]].p) { + return _paths[_realIdxMap[_rrIdx]].p; + } + } + /** + * balance-xor/aware + */ + if (_policy == ZT_BOND_POLICY_BALANCE_XOR || _policy == ZT_BOND_POLICY_BALANCE_AWARE) { + if (flowId == -1) { + // No specific path required for unclassified traffic, send on anything + int m_idx = _realIdxMap[_freeRandomByte % _numBondedPaths]; + return _paths[m_idx].p; + } + Mutex::Lock _l(_flows_m); + std::map >::iterator it = _flows.find(flowId); + if (likely(it != _flows.end())) { + it->second->lastActivity = now; + return _paths[it->second->assignedPath].p; + } + else { + unsigned char entropy; + Utils::getSecureRandom(&entropy, 1); + SharedPtr flow = createFlow(ZT_MAX_PEER_NETWORK_PATHS, flowId, entropy, now); + _flows[flowId] = flow; + return _paths[flow->assignedPath].p; + } + } + return SharedPtr(); } void Bond::recordIncomingInvalidPacket(const SharedPtr& path) { - Mutex::Lock _l(_paths_m); - for (int i = 0; i < ZT_MAX_PEER_NETWORK_PATHS; ++i) { - if (_paths[i].p == path) { - //_paths[i].packetValiditySamples.push(false); - } - } + Mutex::Lock _l(_paths_m); + for (int i = 0; i < ZT_MAX_PEER_NETWORK_PATHS; ++i) { + if (_paths[i].p == path) { + //_paths[i].packetValiditySamples.push(false); + } + } } void Bond::recordOutgoingPacket(const SharedPtr& path, uint64_t packetId, uint16_t payloadLength, const Packet::Verb verb, const int32_t flowId, int64_t now) { - _freeRandomByte += (unsigned char)(packetId >> 8); // Grab entropy to use in path selection logic - bool isFrame = (verb == Packet::Packet::VERB_ECHO || verb == Packet::VERB_FRAME || verb == Packet::VERB_EXT_FRAME); - bool shouldRecord = (packetId & (ZT_QOS_ACK_DIVISOR - 1) && (verb != Packet::VERB_ACK) && (verb != Packet::VERB_QOS_MEASUREMENT)); - if (isFrame || shouldRecord) { - Mutex::Lock _l(_paths_m); - int pathIdx = getNominatedPathIdx(path); - if (pathIdx == ZT_MAX_PEER_NETWORK_PATHS) { - return; - } - if (isFrame) { - ++(_paths[pathIdx].packetsOut); - _lastFrame = now; - } - if (shouldRecord) { - //_paths[pathIdx].expectingAckAsOf = now; - //_paths[pathIdx].totalBytesSentSinceLastAckReceived += payloadLength; - //_paths[pathIdx].unackedBytes += payloadLength; - if (_paths[pathIdx].qosStatsOut.size() < ZT_QOS_MAX_PENDING_RECORDS) { - _paths[pathIdx].qosStatsOut[packetId] = now; - } - } - } - if (flowId != ZT_QOS_NO_FLOW) { - Mutex::Lock _l(_flows_m); - if (_flows.count(flowId)) { - _flows[flowId]->bytesOut += payloadLength; - } - } + _freeRandomByte += (unsigned char)(packetId >> 8); // Grab entropy to use in path selection logic + bool isFrame = (verb == Packet::Packet::VERB_ECHO || verb == Packet::VERB_FRAME || verb == Packet::VERB_EXT_FRAME); + bool shouldRecord = (packetId & (ZT_QOS_ACK_DIVISOR - 1) && (verb != Packet::VERB_ACK) && (verb != Packet::VERB_QOS_MEASUREMENT)); + if (isFrame || shouldRecord) { + Mutex::Lock _l(_paths_m); + int pathIdx = getNominatedPathIdx(path); + if (pathIdx == ZT_MAX_PEER_NETWORK_PATHS) { + return; + } + if (isFrame) { + ++(_paths[pathIdx].packetsOut); + _lastFrame = now; + } + if (shouldRecord) { + //_paths[pathIdx].expectingAckAsOf = now; + //_paths[pathIdx].totalBytesSentSinceLastAckReceived += payloadLength; + //_paths[pathIdx].unackedBytes += payloadLength; + if (_paths[pathIdx].qosStatsOut.size() < ZT_QOS_MAX_PENDING_RECORDS) { + _paths[pathIdx].qosStatsOut[packetId] = now; + } + } + } + if (flowId != ZT_QOS_NO_FLOW) { + Mutex::Lock _l(_flows_m); + if (_flows.count(flowId)) { + _flows[flowId]->bytesOut += payloadLength; + } + } } void Bond::recordIncomingPacket(const SharedPtr& path, uint64_t packetId, uint16_t payloadLength, Packet::Verb verb, int32_t flowId, int64_t now) { - bool isFrame = (verb == Packet::Packet::VERB_ECHO || verb == Packet::VERB_FRAME || verb == Packet::VERB_EXT_FRAME); - bool shouldRecord = (packetId & (ZT_QOS_ACK_DIVISOR - 1) && (verb != Packet::VERB_ACK) && (verb != Packet::VERB_QOS_MEASUREMENT)); - Mutex::Lock _l(_paths_m); - int pathIdx = getNominatedPathIdx(path); - if (pathIdx == ZT_MAX_PEER_NETWORK_PATHS) { - return; - } - // Take note of the time that this previously-dead path received a packet - if (! _paths[pathIdx].alive) { - _paths[pathIdx].lastAliveToggle = now; - } - if (isFrame || shouldRecord) { - if (_paths[pathIdx].allowed()) { - if (isFrame) { - ++(_paths[pathIdx].packetsIn); - _lastFrame = now; - } - if (shouldRecord) { - if (_paths[pathIdx].qosStatsIn.size() < ZT_QOS_MAX_PENDING_RECORDS) { - // debug("Recording QoS information (table size = %d)", _paths[pathIdx].qosStatsIn.size()); - _paths[pathIdx].qosStatsIn[packetId] = now; - ++(_paths[pathIdx].packetsReceivedSinceLastQoS); - //_paths[pathIdx].packetValiditySamples.push(true); - } - else { - // debug("QoS buffer full, will not record information"); - } - /* - if (_paths[pathIdx].ackStatsIn.size() < ZT_ACK_MAX_PENDING_RECORDS) { - //debug("Recording ACK information (table size = %d)", _paths[pathIdx].ackStatsIn.size()); - _paths[pathIdx].ackStatsIn[packetId] = payloadLength; - ++(_paths[pathIdx].packetsReceivedSinceLastAck); - } - else { - debug("ACK buffer full, will not record information"); - } - */ - } - } - } + bool isFrame = (verb == Packet::Packet::VERB_ECHO || verb == Packet::VERB_FRAME || verb == Packet::VERB_EXT_FRAME); + bool shouldRecord = (packetId & (ZT_QOS_ACK_DIVISOR - 1) && (verb != Packet::VERB_ACK) && (verb != Packet::VERB_QOS_MEASUREMENT)); + Mutex::Lock _l(_paths_m); + int pathIdx = getNominatedPathIdx(path); + if (pathIdx == ZT_MAX_PEER_NETWORK_PATHS) { + return; + } + // Take note of the time that this previously-dead path received a packet + if (! _paths[pathIdx].alive) { + _paths[pathIdx].lastAliveToggle = now; + } + if (isFrame || shouldRecord) { + if (_paths[pathIdx].allowed()) { + if (isFrame) { + ++(_paths[pathIdx].packetsIn); + _lastFrame = now; + } + if (shouldRecord) { + if (_paths[pathIdx].qosStatsIn.size() < ZT_QOS_MAX_PENDING_RECORDS) { + // debug("Recording QoS information (table size = %d)", _paths[pathIdx].qosStatsIn.size()); + _paths[pathIdx].qosStatsIn[packetId] = now; + ++(_paths[pathIdx].packetsReceivedSinceLastQoS); + //_paths[pathIdx].packetValiditySamples.push(true); + } + else { + // debug("QoS buffer full, will not record information"); + } + /* + if (_paths[pathIdx].ackStatsIn.size() < ZT_ACK_MAX_PENDING_RECORDS) { + //debug("Recording ACK information (table size = %d)", _paths[pathIdx].ackStatsIn.size()); + _paths[pathIdx].ackStatsIn[packetId] = payloadLength; + ++(_paths[pathIdx].packetsReceivedSinceLastAck); + } + else { + debug("ACK buffer full, will not record information"); + } + */ + } + } + } - /** - * Learn new flows and pro-actively create entries for them in the bond so - * that the next time we send a packet out that is part of a flow we know - * which path to use. - */ - if ((flowId != ZT_QOS_NO_FLOW) && (_policy == ZT_BOND_POLICY_BALANCE_RR || _policy == ZT_BOND_POLICY_BALANCE_XOR || _policy == ZT_BOND_POLICY_BALANCE_AWARE)) { - Mutex::Lock _l(_flows_m); - SharedPtr flow; - if (! _flows.count(flowId)) { - flow = createFlow(pathIdx, flowId, 0, now); - } - else { - flow = _flows[flowId]; - } - if (flow) { - flow->bytesIn += payloadLength; - } - } + /** + * Learn new flows and pro-actively create entries for them in the bond so + * that the next time we send a packet out that is part of a flow we know + * which path to use. + */ + if ((flowId != ZT_QOS_NO_FLOW) && (_policy == ZT_BOND_POLICY_BALANCE_RR || _policy == ZT_BOND_POLICY_BALANCE_XOR || _policy == ZT_BOND_POLICY_BALANCE_AWARE)) { + Mutex::Lock _l(_flows_m); + SharedPtr flow; + if (! _flows.count(flowId)) { + flow = createFlow(pathIdx, flowId, 0, now); + } + else { + flow = _flows[flowId]; + } + if (flow) { + flow->bytesIn += payloadLength; + } + } } void Bond::receivedQoS(const SharedPtr& path, int64_t now, int count, uint64_t* rx_id, uint16_t* rx_ts) { - Mutex::Lock _l(_paths_m); - int pathIdx = getNominatedPathIdx(path); - if (pathIdx == ZT_MAX_PEER_NETWORK_PATHS) { - return; - } - _paths[pathIdx].lastQoSReceived = now; - // debug("received QoS packet (sampling %d frames) via %s", count, pathToStr(path).c_str()); - // Look up egress times and compute latency values for each record - std::map::iterator it; - for (int j = 0; j < count; j++) { - it = _paths[pathIdx].qosStatsOut.find(rx_id[j]); - if (it != _paths[pathIdx].qosStatsOut.end()) { - _paths[pathIdx].latencySamples.push(((uint16_t)(now - it->second) - rx_ts[j]) / 2); - // if (_paths[pathIdx].shouldAvoid) { - // debug("RX sample on avoided path %d", pathIdx); - // } - _paths[pathIdx].qosStatsOut.erase(it); - } - } - _paths[pathIdx].qosRecordSize.push(count); + Mutex::Lock _l(_paths_m); + int pathIdx = getNominatedPathIdx(path); + if (pathIdx == ZT_MAX_PEER_NETWORK_PATHS) { + return; + } + _paths[pathIdx].lastQoSReceived = now; + // debug("received QoS packet (sampling %d frames) via %s", count, pathToStr(path).c_str()); + // Look up egress times and compute latency values for each record + std::map::iterator it; + for (int j = 0; j < count; j++) { + it = _paths[pathIdx].qosStatsOut.find(rx_id[j]); + if (it != _paths[pathIdx].qosStatsOut.end()) { + _paths[pathIdx].latencySamples.push(((uint16_t)(now - it->second) - rx_ts[j]) / 2); + // if (_paths[pathIdx].shouldAvoid) { + // debug("RX sample on avoided path %d", pathIdx); + // } + _paths[pathIdx].qosStatsOut.erase(it); + } + } + _paths[pathIdx].qosRecordSize.push(count); } void Bond::receivedAck(int pathIdx, int64_t now, int32_t ackedBytes) { - /* - Mutex::Lock _l(_paths_m); - debug("received ACK of %d bytes on path %s, there are still %d un-acked bytes", ackedBytes, pathToStr(_paths[pathIdx].p).c_str(), _paths[pathIdx].unackedBytes); - _paths[pathIdx].lastAckReceived = now; - _paths[pathIdx].unackedBytes = (ackedBytes > _paths[pathIdx].unackedBytes) ? 0 : _paths[pathIdx].unackedBytes - ackedBytes; - */ + /* + Mutex::Lock _l(_paths_m); + debug("received ACK of %d bytes on path %s, there are still %d un-acked bytes", ackedBytes, pathToStr(_paths[pathIdx].p).c_str(), _paths[pathIdx].unackedBytes); + _paths[pathIdx].lastAckReceived = now; + _paths[pathIdx].unackedBytes = (ackedBytes > _paths[pathIdx].unackedBytes) ? 0 : _paths[pathIdx].unackedBytes - ackedBytes; + */ } int32_t Bond::generateQoSPacket(int pathIdx, int64_t now, char* qosBuffer) { - int32_t len = 0; - std::map::iterator it = _paths[pathIdx].qosStatsIn.begin(); - int i = 0; - int numRecords = std::min(_paths[pathIdx].packetsReceivedSinceLastQoS, ZT_QOS_TABLE_SIZE); - // debug("numRecords=%3d, packetsReceivedSinceLastQoS=%3d, _paths[pathIdx].qosStatsIn.size()=%3zu", numRecords, _paths[pathIdx].packetsReceivedSinceLastQoS, _paths[pathIdx].qosStatsIn.size()); - while (i < numRecords && it != _paths[pathIdx].qosStatsIn.end()) { - uint64_t id = it->first; - memcpy(qosBuffer, &id, sizeof(uint64_t)); - qosBuffer += sizeof(uint64_t); - uint16_t holdingTime = (uint16_t)(now - it->second); - memcpy(qosBuffer, &holdingTime, sizeof(uint16_t)); - qosBuffer += sizeof(uint16_t); - len += sizeof(uint64_t) + sizeof(uint16_t); - _paths[pathIdx].qosStatsIn.erase(it++); - ++i; - } - return len; + int32_t len = 0; + std::map::iterator it = _paths[pathIdx].qosStatsIn.begin(); + int i = 0; + int numRecords = std::min(_paths[pathIdx].packetsReceivedSinceLastQoS, ZT_QOS_TABLE_SIZE); + // debug("numRecords=%3d, packetsReceivedSinceLastQoS=%3d, _paths[pathIdx].qosStatsIn.size()=%3zu", numRecords, _paths[pathIdx].packetsReceivedSinceLastQoS, _paths[pathIdx].qosStatsIn.size()); + while (i < numRecords && it != _paths[pathIdx].qosStatsIn.end()) { + uint64_t id = it->first; + memcpy(qosBuffer, &id, sizeof(uint64_t)); + qosBuffer += sizeof(uint64_t); + uint16_t holdingTime = (uint16_t)(now - it->second); + memcpy(qosBuffer, &holdingTime, sizeof(uint16_t)); + qosBuffer += sizeof(uint16_t); + len += sizeof(uint64_t) + sizeof(uint16_t); + _paths[pathIdx].qosStatsIn.erase(it++); + ++i; + } + return len; } bool Bond::assignFlowToBondedPath(SharedPtr& flow, int64_t now, bool reassign = false) { - if (! _numBondedPaths) { - debug("unable to assign flow %x (bond has no links)", flow->id); - return false; - } - unsigned int bondedIdx = ZT_MAX_PEER_NETWORK_PATHS; - if (_policy == ZT_BOND_POLICY_BALANCE_XOR) { - bondedIdx = abs((int)(flow->id % _numBondedPaths)); - flow->assignPath(_realIdxMap[bondedIdx], now); - ++(_paths[_realIdxMap[bondedIdx]].assignedFlowCount); - } - if (_policy == ZT_BOND_POLICY_BALANCE_AWARE) { - /** balance-aware generally works like balance-xor except that it will try to - * take into account user preferences (or default sane limits) that will discourage - * allocating traffic to links with a lesser perceived "quality" */ - int offset = 0; - float bestQuality = 0.0; - int nextBestQualIdx = ZT_MAX_PEER_NETWORK_PATHS; + if (! _numBondedPaths) { + debug("unable to assign flow %x (bond has no links)", flow->id); + return false; + } + unsigned int bondedIdx = ZT_MAX_PEER_NETWORK_PATHS; + if (_policy == ZT_BOND_POLICY_BALANCE_XOR) { + bondedIdx = abs((int)(flow->id % _numBondedPaths)); + flow->assignPath(_realIdxMap[bondedIdx], now); + ++(_paths[_realIdxMap[bondedIdx]].assignedFlowCount); + } + if (_policy == ZT_BOND_POLICY_BALANCE_AWARE) { + /** balance-aware generally works like balance-xor except that it will try to + * take into account user preferences (or default sane limits) that will discourage + * allocating traffic to links with a lesser perceived "quality" */ + int offset = 0; + float bestQuality = 0.0; + int nextBestQualIdx = ZT_MAX_PEER_NETWORK_PATHS; - if (reassign) { - log("attempting to re-assign out-flow %04x previously on idx %d (%u / %zu flows)", flow->id, flow->assignedPath, _paths[_realIdxMap[flow->assignedPath]].assignedFlowCount, _flows.size()); - } - else { - debug("attempting to assign flow for the first time"); - } + if (reassign) { + log("attempting to re-assign out-flow %04x previously on idx %d (%u / %zu flows)", flow->id, flow->assignedPath, _paths[_realIdxMap[flow->assignedPath]].assignedFlowCount, _flows.size()); + } + else { + debug("attempting to assign flow for the first time"); + } - unsigned char entropy; - Utils::getSecureRandom(&entropy, 1); - float randomLinkCapacity = ((float)entropy / 255.0); // Used to random but proportional choices + unsigned char entropy; + Utils::getSecureRandom(&entropy, 1); + float randomLinkCapacity = ((float)entropy / 255.0); // Used to random but proportional choices - while (offset < _numBondedPaths) { - unsigned char entropy; - Utils::getSecureRandom(&entropy, 1); + while (offset < _numBondedPaths) { + unsigned char entropy; + Utils::getSecureRandom(&entropy, 1); - if (reassign) { - bondedIdx = (flow->assignedPath + offset) % (_numBondedPaths); - } - else { - bondedIdx = abs((int)((entropy + offset) % (_numBondedPaths))); - } - // debug("idx=%d, offset=%d, randomCap=%f, actualCap=%f", bondedIdx, offset, randomLinkCapacity, _paths[_realIdxMap[bondedIdx]].relativeLinkCapacity); - if (! _paths[_realIdxMap[bondedIdx]].p) { - continue; - } - if (! _paths[_realIdxMap[bondedIdx]].shouldAvoid && randomLinkCapacity <= _paths[_realIdxMap[bondedIdx]].relativeLinkCapacity) { - // debug(" assign out-flow %04x to link %s (%u / %zu flows)", flow->id, pathToStr(_paths[_realIdxMap[bondedIdx]].p).c_str(), _paths[_realIdxMap[bondedIdx]].assignedFlowCount, _flows.size()); - break; // Acceptable -- No violation of quality spec - } - if (_paths[_realIdxMap[bondedIdx]].relativeQuality > bestQuality) { - bestQuality = _paths[_realIdxMap[bondedIdx]].relativeQuality; - nextBestQualIdx = bondedIdx; - // debug(" recording next-best link %f idx %d", _paths[_realIdxMap[bondedIdx]].relativeQuality, bondedIdx); - } - ++offset; - } - if (offset < _numBondedPaths) { - // We were (able) to find a path that didn't violate any of the user's quality requirements - flow->assignPath(_realIdxMap[bondedIdx], now); - ++(_paths[_realIdxMap[bondedIdx]].assignedFlowCount); - // debug(" ABLE to find optimal link %f idx %d", _paths[_realIdxMap[bondedIdx]].relativeQuality, bondedIdx); - } - else { - // We were (unable) to find a path that didn't violate at least one quality requirement, will choose next best option - flow->assignPath(_realIdxMap[nextBestQualIdx], now); - ++(_paths[_realIdxMap[nextBestQualIdx]].assignedFlowCount); - // debug(" UNABLE to find, will use link %f idx %d", _paths[_realIdxMap[nextBestQualIdx]].relativeQuality, nextBestQualIdx); - } - } - if (_policy == ZT_BOND_POLICY_ACTIVE_BACKUP) { - if (_abPathIdx == ZT_MAX_PEER_NETWORK_PATHS) { - log("unable to assign out-flow %x (no active backup link)", flow->id); - } - flow->assignPath(_abPathIdx, now); - } - log("assign out-flow %04x to link %s (%u / %zu flows)", flow->id, pathToStr(_paths[flow->assignedPath].p).c_str(), _paths[flow->assignedPath].assignedFlowCount, _flows.size()); - return true; + if (reassign) { + bondedIdx = (flow->assignedPath + offset) % (_numBondedPaths); + } + else { + bondedIdx = abs((int)((entropy + offset) % (_numBondedPaths))); + } + // debug("idx=%d, offset=%d, randomCap=%f, actualCap=%f", bondedIdx, offset, randomLinkCapacity, _paths[_realIdxMap[bondedIdx]].relativeLinkCapacity); + if (! _paths[_realIdxMap[bondedIdx]].p) { + continue; + } + if (! _paths[_realIdxMap[bondedIdx]].shouldAvoid && randomLinkCapacity <= _paths[_realIdxMap[bondedIdx]].relativeLinkCapacity) { + // debug(" assign out-flow %04x to link %s (%u / %zu flows)", flow->id, pathToStr(_paths[_realIdxMap[bondedIdx]].p).c_str(), _paths[_realIdxMap[bondedIdx]].assignedFlowCount, _flows.size()); + break; // Acceptable -- No violation of quality spec + } + if (_paths[_realIdxMap[bondedIdx]].relativeQuality > bestQuality) { + bestQuality = _paths[_realIdxMap[bondedIdx]].relativeQuality; + nextBestQualIdx = bondedIdx; + // debug(" recording next-best link %f idx %d", _paths[_realIdxMap[bondedIdx]].relativeQuality, bondedIdx); + } + ++offset; + } + if (offset < _numBondedPaths) { + // We were (able) to find a path that didn't violate any of the user's quality requirements + flow->assignPath(_realIdxMap[bondedIdx], now); + ++(_paths[_realIdxMap[bondedIdx]].assignedFlowCount); + // debug(" ABLE to find optimal link %f idx %d", _paths[_realIdxMap[bondedIdx]].relativeQuality, bondedIdx); + } + else { + // We were (unable) to find a path that didn't violate at least one quality requirement, will choose next best option + flow->assignPath(_realIdxMap[nextBestQualIdx], now); + ++(_paths[_realIdxMap[nextBestQualIdx]].assignedFlowCount); + // debug(" UNABLE to find, will use link %f idx %d", _paths[_realIdxMap[nextBestQualIdx]].relativeQuality, nextBestQualIdx); + } + } + if (_policy == ZT_BOND_POLICY_ACTIVE_BACKUP) { + if (_abPathIdx == ZT_MAX_PEER_NETWORK_PATHS) { + log("unable to assign out-flow %x (no active backup link)", flow->id); + } + flow->assignPath(_abPathIdx, now); + } + log("assign out-flow %04x to link %s (%u / %zu flows)", flow->id, pathToStr(_paths[flow->assignedPath].p).c_str(), _paths[flow->assignedPath].assignedFlowCount, _flows.size()); + return true; } SharedPtr Bond::createFlow(int pathIdx, int32_t flowId, unsigned char entropy, int64_t now) { - if (! _numBondedPaths) { - debug("unable to assign flow %04x (bond has no links)", flowId); - return SharedPtr(); - } - if (_flows.size() >= ZT_FLOW_MAX_COUNT) { - debug("forget oldest flow (max flows reached: %d)", ZT_FLOW_MAX_COUNT); - forgetFlowsWhenNecessary(0, true, now); - } - SharedPtr flow = new Flow(flowId, now); - _flows[flowId] = flow; - /** - * Add a flow with a given Path already provided. This is the case when a packet - * is received on a path but no flow exists, in this case we simply assign the path - * that the remote peer chose for us. - */ - if (pathIdx != ZT_MAX_PEER_NETWORK_PATHS) { - flow->assignPath(pathIdx, now); - _paths[pathIdx].assignedFlowCount++; - debug("assign in-flow %04x to link %s (%u / %zu)", flow->id, pathToStr(_paths[pathIdx].p).c_str(), _paths[pathIdx].assignedFlowCount, _flows.size()); - } - /** - * Add a flow when no path was provided. This means that it is an outgoing packet - * and that it is up to the local peer to decide how to load-balance its transmission. - */ - else { - assignFlowToBondedPath(flow, now); - } - return flow; + if (! _numBondedPaths) { + debug("unable to assign flow %04x (bond has no links)", flowId); + return SharedPtr(); + } + if (_flows.size() >= ZT_FLOW_MAX_COUNT) { + debug("forget oldest flow (max flows reached: %d)", ZT_FLOW_MAX_COUNT); + forgetFlowsWhenNecessary(0, true, now); + } + SharedPtr flow = new Flow(flowId, now); + _flows[flowId] = flow; + /** + * Add a flow with a given Path already provided. This is the case when a packet + * is received on a path but no flow exists, in this case we simply assign the path + * that the remote peer chose for us. + */ + if (pathIdx != ZT_MAX_PEER_NETWORK_PATHS) { + flow->assignPath(pathIdx, now); + _paths[pathIdx].assignedFlowCount++; + debug("assign in-flow %04x to link %s (%u / %zu)", flow->id, pathToStr(_paths[pathIdx].p).c_str(), _paths[pathIdx].assignedFlowCount, _flows.size()); + } + /** + * Add a flow when no path was provided. This means that it is an outgoing packet + * and that it is up to the local peer to decide how to load-balance its transmission. + */ + else { + assignFlowToBondedPath(flow, now); + } + return flow; } void Bond::forgetFlowsWhenNecessary(uint64_t age, bool oldest, int64_t now) { - std::map >::iterator it = _flows.begin(); - std::map >::iterator oldestFlow = _flows.end(); - SharedPtr expiredFlow; - if (age) { // Remove by specific age - while (it != _flows.end()) { - if (it->second->age(now) > age) { - debug("forget flow %04x (age %" PRId64 ") (%u / %zu)", it->first, it->second->age(now), _paths[it->second->assignedPath].assignedFlowCount, (_flows.size() - 1)); - _paths[it->second->assignedPath].assignedFlowCount--; - it = _flows.erase(it); - } - else { - ++it; - } - } - } - else if (oldest) { // Remove single oldest by natural expiration - uint64_t maxAge = 0; - while (it != _flows.end()) { - if (it->second->age(now) > maxAge) { - maxAge = (now - it->second->age(now)); - oldestFlow = it; - } - ++it; - } - if (oldestFlow != _flows.end()) { - debug("forget oldest flow %04x (age %" PRId64 ") (total flows: %zu)", oldestFlow->first, oldestFlow->second->age(now), _flows.size() - 1); - _paths[oldestFlow->second->assignedPath].assignedFlowCount--; - _flows.erase(oldestFlow); - } - } + std::map >::iterator it = _flows.begin(); + std::map >::iterator oldestFlow = _flows.end(); + SharedPtr expiredFlow; + if (age) { // Remove by specific age + while (it != _flows.end()) { + if (it->second->age(now) > age) { + debug("forget flow %04x (age %" PRId64 ") (%u / %zu)", it->first, it->second->age(now), _paths[it->second->assignedPath].assignedFlowCount, (_flows.size() - 1)); + _paths[it->second->assignedPath].assignedFlowCount--; + it = _flows.erase(it); + } + else { + ++it; + } + } + } + else if (oldest) { // Remove single oldest by natural expiration + uint64_t maxAge = 0; + while (it != _flows.end()) { + if (it->second->age(now) > maxAge) { + maxAge = (now - it->second->age(now)); + oldestFlow = it; + } + ++it; + } + if (oldestFlow != _flows.end()) { + debug("forget oldest flow %04x (age %" PRId64 ") (total flows: %zu)", oldestFlow->first, oldestFlow->second->age(now), _flows.size() - 1); + _paths[oldestFlow->second->assignedPath].assignedFlowCount--; + _flows.erase(oldestFlow); + } + } } void Bond::processIncomingPathNegotiationRequest(uint64_t now, SharedPtr& path, int16_t remoteUtility) { - char pathStr[64] = { 0 }; - if (_abLinkSelectMethod != ZT_BOND_RESELECTION_POLICY_OPTIMIZE) { - return; - } - Mutex::Lock _l(_paths_m); - int pathIdx = getNominatedPathIdx(path); - if (pathIdx == ZT_MAX_PEER_NETWORK_PATHS) { - return; - } - _paths[pathIdx].p->address().toString(pathStr); - if (! _lastPathNegotiationCheck) { - return; - } - SharedPtr link = RR->bc->getLinkBySocket(_policyAlias, _paths[pathIdx].p->localSocket()); - if (link) { - if (remoteUtility > _localUtility) { - _paths[pathIdx].p->address().toString(pathStr); - debug("peer suggests alternate link %s/%s, remote utility (%d) greater than local utility (%d), switching to suggested link\n", link->ifname().c_str(), pathStr, remoteUtility, _localUtility); - _negotiatedPathIdx = pathIdx; - } - if (remoteUtility < _localUtility) { - debug("peer suggests alternate link %s/%s, remote utility (%d) less than local utility (%d), not switching\n", link->ifname().c_str(), pathStr, remoteUtility, _localUtility); - } - if (remoteUtility == _localUtility) { - debug("peer suggests alternate link %s/%s, remote utility (%d) equal to local utility (%d)\n", link->ifname().c_str(), pathStr, remoteUtility, _localUtility); - if (_peer->_id.address().toInt() > RR->node->identity().address().toInt()) { - debug("agree with peer to use alternate link %s/%s\n", link->ifname().c_str(), pathStr); - _negotiatedPathIdx = pathIdx; - } - else { - debug("ignore petition from peer to use alternate link %s/%s\n", link->ifname().c_str(), pathStr); - } - } - } + char pathStr[64] = { 0 }; + if (_abLinkSelectMethod != ZT_BOND_RESELECTION_POLICY_OPTIMIZE) { + return; + } + Mutex::Lock _l(_paths_m); + int pathIdx = getNominatedPathIdx(path); + if (pathIdx == ZT_MAX_PEER_NETWORK_PATHS) { + return; + } + _paths[pathIdx].p->address().toString(pathStr); + if (! _lastPathNegotiationCheck) { + return; + } + SharedPtr link = RR->bc->getLinkBySocket(_policyAlias, _paths[pathIdx].p->localSocket()); + if (link) { + if (remoteUtility > _localUtility) { + _paths[pathIdx].p->address().toString(pathStr); + debug("peer suggests alternate link %s/%s, remote utility (%d) greater than local utility (%d), switching to suggested link\n", link->ifname().c_str(), pathStr, remoteUtility, _localUtility); + _negotiatedPathIdx = pathIdx; + } + if (remoteUtility < _localUtility) { + debug("peer suggests alternate link %s/%s, remote utility (%d) less than local utility (%d), not switching\n", link->ifname().c_str(), pathStr, remoteUtility, _localUtility); + } + if (remoteUtility == _localUtility) { + debug("peer suggests alternate link %s/%s, remote utility (%d) equal to local utility (%d)\n", link->ifname().c_str(), pathStr, remoteUtility, _localUtility); + if (_peer->_id.address().toInt() > RR->node->identity().address().toInt()) { + debug("agree with peer to use alternate link %s/%s\n", link->ifname().c_str(), pathStr); + _negotiatedPathIdx = pathIdx; + } + else { + debug("ignore petition from peer to use alternate link %s/%s\n", link->ifname().c_str(), pathStr); + } + } + } } void Bond::pathNegotiationCheck(void* tPtr, int64_t now) { - int maxInPathIdx = ZT_MAX_PEER_NETWORK_PATHS; - int maxOutPathIdx = ZT_MAX_PEER_NETWORK_PATHS; - uint64_t maxInCount = 0; - uint64_t maxOutCount = 0; - for (unsigned int i = 0; i < ZT_MAX_PEER_NETWORK_PATHS; ++i) { - if (! _paths[i].p) { - continue; - } - if (_paths[i].packetsIn > maxInCount) { - maxInCount = _paths[i].packetsIn; - maxInPathIdx = i; - } - if (_paths[i].packetsOut > maxOutCount) { - maxOutCount = _paths[i].packetsOut; - maxOutPathIdx = i; - } - _paths[i].resetPacketCounts(); - } - bool _peerLinksSynchronized = ((maxInPathIdx != ZT_MAX_PEER_NETWORK_PATHS) && (maxOutPathIdx != ZT_MAX_PEER_NETWORK_PATHS) && (maxInPathIdx != maxOutPathIdx)) ? false : true; - /** - * Determine utility and attempt to petition remote peer to switch to our chosen path - */ - if (! _peerLinksSynchronized) { - _localUtility = _paths[maxOutPathIdx].failoverScore - _paths[maxInPathIdx].failoverScore; - if (_paths[maxOutPathIdx].negotiated) { - _localUtility -= ZT_BOND_FAILOVER_HANDICAP_NEGOTIATED; - } - if ((now - _lastSentPathNegotiationRequest) > ZT_PATH_NEGOTIATION_CUTOFF_TIME) { - // fprintf(stderr, "BT: (sync) it's been long enough, sending more requests.\n"); - _numSentPathNegotiationRequests = 0; - } - if (_numSentPathNegotiationRequests < ZT_PATH_NEGOTIATION_TRY_COUNT) { - if (_localUtility >= 0) { - // fprintf(stderr, "BT: (sync) paths appear to be out of sync (utility=%d)\n", _localUtility); - sendPATH_NEGOTIATION_REQUEST(tPtr, _paths[maxOutPathIdx].p); - ++_numSentPathNegotiationRequests; - _lastSentPathNegotiationRequest = now; - // fprintf(stderr, "sending request to use %s on %s, ls=%llx, utility=%d\n", pathStr, link->ifname().c_str(), _paths[maxOutPathIdx].p->localSocket(), _localUtility); - } - } - /** - * Give up negotiating and consider switching - */ - else if ((now - _lastSentPathNegotiationRequest) > (2 * ZT_BOND_OPTIMIZE_INTERVAL)) { - if (_localUtility == 0) { - // There's no loss to us, just switch without sending a another request - // fprintf(stderr, "BT: (sync) giving up, switching to remote peer's path.\n"); - _negotiatedPathIdx = maxInPathIdx; - } - } - } + int maxInPathIdx = ZT_MAX_PEER_NETWORK_PATHS; + int maxOutPathIdx = ZT_MAX_PEER_NETWORK_PATHS; + uint64_t maxInCount = 0; + uint64_t maxOutCount = 0; + for (unsigned int i = 0; i < ZT_MAX_PEER_NETWORK_PATHS; ++i) { + if (! _paths[i].p) { + continue; + } + if (_paths[i].packetsIn > maxInCount) { + maxInCount = _paths[i].packetsIn; + maxInPathIdx = i; + } + if (_paths[i].packetsOut > maxOutCount) { + maxOutCount = _paths[i].packetsOut; + maxOutPathIdx = i; + } + _paths[i].resetPacketCounts(); + } + bool _peerLinksSynchronized = ((maxInPathIdx != ZT_MAX_PEER_NETWORK_PATHS) && (maxOutPathIdx != ZT_MAX_PEER_NETWORK_PATHS) && (maxInPathIdx != maxOutPathIdx)) ? false : true; + /** + * Determine utility and attempt to petition remote peer to switch to our chosen path + */ + if (! _peerLinksSynchronized) { + _localUtility = _paths[maxOutPathIdx].failoverScore - _paths[maxInPathIdx].failoverScore; + if (_paths[maxOutPathIdx].negotiated) { + _localUtility -= ZT_BOND_FAILOVER_HANDICAP_NEGOTIATED; + } + if ((now - _lastSentPathNegotiationRequest) > ZT_PATH_NEGOTIATION_CUTOFF_TIME) { + // fprintf(stderr, "BT: (sync) it's been long enough, sending more requests.\n"); + _numSentPathNegotiationRequests = 0; + } + if (_numSentPathNegotiationRequests < ZT_PATH_NEGOTIATION_TRY_COUNT) { + if (_localUtility >= 0) { + // fprintf(stderr, "BT: (sync) paths appear to be out of sync (utility=%d)\n", _localUtility); + sendPATH_NEGOTIATION_REQUEST(tPtr, _paths[maxOutPathIdx].p); + ++_numSentPathNegotiationRequests; + _lastSentPathNegotiationRequest = now; + // fprintf(stderr, "sending request to use %s on %s, ls=%llx, utility=%d\n", pathStr, link->ifname().c_str(), _paths[maxOutPathIdx].p->localSocket(), _localUtility); + } + } + /** + * Give up negotiating and consider switching + */ + else if ((now - _lastSentPathNegotiationRequest) > (2 * ZT_BOND_OPTIMIZE_INTERVAL)) { + if (_localUtility == 0) { + // There's no loss to us, just switch without sending a another request + // fprintf(stderr, "BT: (sync) giving up, switching to remote peer's path.\n"); + _negotiatedPathIdx = maxInPathIdx; + } + } + } } void Bond::sendPATH_NEGOTIATION_REQUEST(void* tPtr, int pathIdx) { - debug("send link negotiation request to peer via link %s, local utility is %d", pathToStr(_paths[pathIdx].p).c_str(), _localUtility); - if (_abLinkSelectMethod != ZT_BOND_RESELECTION_POLICY_OPTIMIZE) { - return; - } - Packet outp(_peer->_id.address(), RR->identity.address(), Packet::VERB_PATH_NEGOTIATION_REQUEST); - outp.append(_localUtility); - if (_paths[pathIdx].p->address()) { - Metrics::pkt_path_negotiation_request_out++; - outp.armor(_peer->key(), false, _peer->aesKeysIfSupported()); - RR->node->putPacket(tPtr, _paths[pathIdx].p->localSocket(), _paths[pathIdx].p->address(), outp.data(), outp.size()); - _overheadBytes += outp.size(); - } + debug("send link negotiation request to peer via link %s, local utility is %d", pathToStr(_paths[pathIdx].p).c_str(), _localUtility); + if (_abLinkSelectMethod != ZT_BOND_RESELECTION_POLICY_OPTIMIZE) { + return; + } + Packet outp(_peer->_id.address(), RR->identity.address(), Packet::VERB_PATH_NEGOTIATION_REQUEST); + outp.append(_localUtility); + if (_paths[pathIdx].p->address()) { + Metrics::pkt_path_negotiation_request_out++; + outp.armor(_peer->key(), true, false, _peer->aesKeysIfSupported(), _peer->identity()); + RR->node->putPacket(tPtr, _paths[pathIdx].p->localSocket(), _paths[pathIdx].p->address(), outp.data(), outp.size()); + _overheadBytes += outp.size(); + } } void Bond::sendACK(void* tPtr, int pathIdx, int64_t localSocket, const InetAddress& atAddress, int64_t now) { - /* - Packet outp(_peer->_id.address(), RR->identity.address(), Packet::VERB_ACK); - int32_t bytesToAck = 0; - std::map::iterator it = _paths[pathIdx].ackStatsIn.begin(); - while (it != _paths[pathIdx].ackStatsIn.end()) { - bytesToAck += it->second; - ++it; - } - debug("sending ACK of %d bytes on path %s (table size = %zu)", bytesToAck, pathToStr(_paths[pathIdx].p).c_str(), _paths[pathIdx].ackStatsIn.size()); - outp.append(bytesToAck); - if (atAddress) { - outp.armor(_peer->key(), false, _peer->aesKeysIfSupported()); - RR->node->putPacket(tPtr, localSocket, atAddress, outp.data(), outp.size()); - } - else { - RR->sw->send(tPtr, outp, false); - } - _paths[pathIdx].ackStatsIn.clear(); - _paths[pathIdx].packetsReceivedSinceLastAck = 0; - _paths[pathIdx].lastAckSent = now; - */ + /* + Packet outp(_peer->_id.address(), RR->identity.address(), Packet::VERB_ACK); + int32_t bytesToAck = 0; + std::map::iterator it = _paths[pathIdx].ackStatsIn.begin(); + while (it != _paths[pathIdx].ackStatsIn.end()) { + bytesToAck += it->second; + ++it; + } + debug("sending ACK of %d bytes on path %s (table size = %zu)", bytesToAck, pathToStr(_paths[pathIdx].p).c_str(), _paths[pathIdx].ackStatsIn.size()); + outp.append(bytesToAck); + if (atAddress) { + outp.armor(_peer->key(), false, _peer->aesKeysIfSupported()); + RR->node->putPacket(tPtr, localSocket, atAddress, outp.data(), outp.size()); + } + else { + RR->sw->send(tPtr, outp, false); + } + _paths[pathIdx].ackStatsIn.clear(); + _paths[pathIdx].packetsReceivedSinceLastAck = 0; + _paths[pathIdx].lastAckSent = now; + */ } void Bond::sendQOS_MEASUREMENT(void* tPtr, int pathIdx, int64_t localSocket, const InetAddress& atAddress, int64_t now) { - int64_t _now = RR->node->now(); - Packet outp(_peer->_id.address(), RR->identity.address(), Packet::VERB_QOS_MEASUREMENT); - char qosData[ZT_QOS_MAX_PACKET_SIZE]; - int16_t len = generateQoSPacket(pathIdx, _now, qosData); - if (len) { - // debug("sending QOS via link %s (len=%d)", pathToStr(_paths[pathIdx].p).c_str(), len); - outp.append(qosData, len); - if (atAddress) { - outp.armor(_peer->key(), false, _peer->aesKeysIfSupported()); - RR->node->putPacket(tPtr, localSocket, atAddress, outp.data(), outp.size()); - } - else { - RR->sw->send(tPtr, outp, false); - } - Metrics::pkt_qos_out++; - _paths[pathIdx].packetsReceivedSinceLastQoS = 0; - _paths[pathIdx].lastQoSMeasurement = now; - _overheadBytes += outp.size(); - } + int64_t _now = RR->node->now(); + Packet outp(_peer->_id.address(), RR->identity.address(), Packet::VERB_QOS_MEASUREMENT); + char qosData[ZT_QOS_MAX_PACKET_SIZE]; + int16_t len = generateQoSPacket(pathIdx, _now, qosData); + if (len) { + // debug("sending QOS via link %s (len=%d)", pathToStr(_paths[pathIdx].p).c_str(), len); + outp.append(qosData, len); + if (atAddress) { + outp.armor(_peer->key(), true, false, _peer->aesKeysIfSupported(), _peer->identity()); + RR->node->putPacket(tPtr, localSocket, atAddress, outp.data(), outp.size()); + } + else { + RR->sw->send(tPtr, outp, false); + } + Metrics::pkt_qos_out++; + _paths[pathIdx].packetsReceivedSinceLastQoS = 0; + _paths[pathIdx].lastQoSMeasurement = now; + _overheadBytes += outp.size(); + } } void Bond::processBackgroundBondTasks(void* tPtr, int64_t now) { - if (! _run) { - return; - } - if (! _peer->_localMultipathSupported || (now - _lastBackgroundTaskCheck) < ZT_BOND_BACKGROUND_TASK_MIN_INTERVAL) { - return; - } - _lastBackgroundTaskCheck = now; - Mutex::Lock _l(_paths_m); + if (! _run) { + return; + } + if (! _peer->_localMultipathSupported || (now - _lastBackgroundTaskCheck) < ZT_BOND_BACKGROUND_TASK_MIN_INTERVAL) { + return; + } + _lastBackgroundTaskCheck = now; + Mutex::Lock _l(_paths_m); - curateBond(now, false); - if ((now - _lastQualityEstimation) > _qualityEstimationInterval) { - _lastQualityEstimation = now; - estimatePathQuality(now); - } - dumpInfo(now, false); + curateBond(now, false); + if ((now - _lastQualityEstimation) > _qualityEstimationInterval) { + _lastQualityEstimation = now; + estimatePathQuality(now); + } + dumpInfo(now, false); - // Send ambient monitoring traffic - for (unsigned int i = 0; i < ZT_MAX_PEER_NETWORK_PATHS; ++i) { - if (_paths[i].p && _paths[i].allowed()) { - if (_isLeaf) { - if ((_monitorInterval > 0) && (((now - _paths[i].p->_lastIn) >= (_paths[i].alive ? _monitorInterval : _failoverInterval)))) { - if ((_peer->remoteVersionProtocol() >= 5) && (! ((_peer->remoteVersionMajor() == 1) && (_peer->remoteVersionMinor() == 1) && (_peer->remoteVersionRevision() == 0)))) { - Packet outp(_peer->address(), RR->identity.address(), Packet::VERB_ECHO); // ECHO (this is our bond's heartbeat) - outp.armor(_peer->key(), true, _peer->aesKeysIfSupported()); - RR->node->expectReplyTo(outp.packetId()); - RR->node->putPacket(tPtr, _paths[i].p->localSocket(), _paths[i].p->address(), outp.data(), outp.size()); - _paths[i].p->_lastOut = now; - _overheadBytes += outp.size(); - Metrics::pkt_echo_out++; - // debug("tx: verb 0x%-2x of len %4d via %s (ECHO)", Packet::VERB_ECHO, outp.size(), pathToStr(_paths[i].p).c_str()); - } - } - // QOS - if (_paths[i].needsToSendQoS(now, _qosSendInterval)) { - sendQOS_MEASUREMENT(tPtr, i, _paths[i].p->localSocket(), _paths[i].p->address(), now); - } - // ACK - /* - if (_paths[i].needsToSendAck(now, _ackSendInterval)) { - sendACK(tPtr, i, _paths[i].p->localSocket(), _paths[i].p->address(), now); - } - */ - } - } - } - // Perform periodic background tasks unique to each bonding policy - switch (_policy) { - case ZT_BOND_POLICY_ACTIVE_BACKUP: - processActiveBackupTasks(tPtr, now); - break; - case ZT_BOND_POLICY_BROADCAST: - break; - case ZT_BOND_POLICY_BALANCE_RR: - case ZT_BOND_POLICY_BALANCE_XOR: - case ZT_BOND_POLICY_BALANCE_AWARE: - processBalanceTasks(now); - break; - default: - break; - } - // Check whether or not a path negotiation needs to be performed - if (((now - _lastPathNegotiationCheck) > ZT_BOND_OPTIMIZE_INTERVAL) && _allowPathNegotiation) { - _lastPathNegotiationCheck = now; - pathNegotiationCheck(tPtr, now); - } + // Send ambient monitoring traffic + for (unsigned int i = 0; i < ZT_MAX_PEER_NETWORK_PATHS; ++i) { + if (_paths[i].p && _paths[i].allowed()) { + if (_isLeaf) { + if ((_monitorInterval > 0) && (((now - _paths[i].p->_lastIn) >= (_paths[i].alive ? _monitorInterval : _failoverInterval)))) { + if ((_peer->remoteVersionProtocol() >= 5) && (! ((_peer->remoteVersionMajor() == 1) && (_peer->remoteVersionMinor() == 1) && (_peer->remoteVersionRevision() == 0)))) { + Packet outp(_peer->address(), RR->identity.address(), Packet::VERB_ECHO); // ECHO (this is our bond's heartbeat) + outp.armor(_peer->key(), true, false, _peer->aesKeysIfSupported(), _peer->identity()); + RR->node->expectReplyTo(outp.packetId()); + RR->node->putPacket(tPtr, _paths[i].p->localSocket(), _paths[i].p->address(), outp.data(), outp.size()); + _paths[i].p->_lastOut = now; + _overheadBytes += outp.size(); + Metrics::pkt_echo_out++; + // debug("tx: verb 0x%-2x of len %4d via %s (ECHO)", Packet::VERB_ECHO, outp.size(), pathToStr(_paths[i].p).c_str()); + } + } + // QOS + if (_paths[i].needsToSendQoS(now, _qosSendInterval)) { + sendQOS_MEASUREMENT(tPtr, i, _paths[i].p->localSocket(), _paths[i].p->address(), now); + } + // ACK + /* + if (_paths[i].needsToSendAck(now, _ackSendInterval)) { + sendACK(tPtr, i, _paths[i].p->localSocket(), _paths[i].p->address(), now); + } + */ + } + } + } + // Perform periodic background tasks unique to each bonding policy + switch (_policy) { + case ZT_BOND_POLICY_ACTIVE_BACKUP: + processActiveBackupTasks(tPtr, now); + break; + case ZT_BOND_POLICY_BROADCAST: + break; + case ZT_BOND_POLICY_BALANCE_RR: + case ZT_BOND_POLICY_BALANCE_XOR: + case ZT_BOND_POLICY_BALANCE_AWARE: + processBalanceTasks(now); + break; + default: + break; + } + // Check whether or not a path negotiation needs to be performed + if (((now - _lastPathNegotiationCheck) > ZT_BOND_OPTIMIZE_INTERVAL) && _allowPathNegotiation) { + _lastPathNegotiationCheck = now; + pathNegotiationCheck(tPtr, now); + } } void Bond::curateBond(int64_t now, bool rebuildBond) { - uint8_t tmpNumAliveLinks = 0; - uint8_t tmpNumTotalLinks = 0; + uint8_t tmpNumAliveLinks = 0; + uint8_t tmpNumTotalLinks = 0; - /** - * Update path state variables. State variables are used so that critical - * blocks that perform fast packet processing won't need to make as many - * function calls or computations. - */ - for (unsigned int i = 0; i < ZT_MAX_PEER_NETWORK_PATHS; ++i) { - if (! _paths[i].p) { - continue; - } + /** + * Update path state variables. State variables are used so that critical + * blocks that perform fast packet processing won't need to make as many + * function calls or computations. + */ + for (unsigned int i = 0; i < ZT_MAX_PEER_NETWORK_PATHS; ++i) { + if (! _paths[i].p) { + continue; + } - // Whether this path is still in its trial period - bool inTrial = (now - _paths[i].whenNominated) < ZT_BOND_OPTIMIZE_INTERVAL; + // Whether this path is still in its trial period + bool inTrial = (now - _paths[i].whenNominated) < ZT_BOND_OPTIMIZE_INTERVAL; - /** - * Remove expired or invalid links from bond - */ - SharedPtr link = getLink(_paths[i].p); - if (! link) { - log("link is no longer valid, removing from bond"); - _paths[i].p->_valid = false; - _paths[i] = NominatedPath(); - _paths[i].p = SharedPtr(); - continue; - } - if ((now - _paths[i].lastEligibility) > (ZT_PEER_EXPIRED_PATH_TRIAL_PERIOD) && ! inTrial) { - log("link (%s) has expired or is invalid, removing from bond", pathToStr(_paths[i].p).c_str()); - _paths[i] = NominatedPath(); - _paths[i].p = SharedPtr(); - continue; - } + /** + * Remove expired or invalid links from bond + */ + SharedPtr link = getLink(_paths[i].p); + if (! link) { + log("link is no longer valid, removing from bond"); + _paths[i].p->_valid = false; + _paths[i] = NominatedPath(); + _paths[i].p = SharedPtr(); + continue; + } + if ((now - _paths[i].lastEligibility) > (ZT_PEER_EXPIRED_PATH_TRIAL_PERIOD) && ! inTrial) { + log("link (%s) has expired or is invalid, removing from bond", pathToStr(_paths[i].p).c_str()); + _paths[i] = NominatedPath(); + _paths[i].p = SharedPtr(); + continue; + } - tmpNumTotalLinks++; - if (_paths[i].eligible) { - tmpNumAliveLinks++; - } + tmpNumTotalLinks++; + if (_paths[i].eligible) { + tmpNumAliveLinks++; + } - /** - * Determine aliveness - */ - _paths[i].alive = _isLeaf ? (now - _paths[i].p->_lastIn) < _failoverInterval : (now - _paths[i].p->_lastIn) < ZT_PEER_PATH_EXPIRATION; + /** + * Determine aliveness + */ + _paths[i].alive = _isLeaf ? (now - _paths[i].p->_lastIn) < _failoverInterval : (now - _paths[i].p->_lastIn) < ZT_PEER_PATH_EXPIRATION; - /** - * Determine current eligibility - */ - bool currEligibility = false; - // Simple RX age (driven by packets of any type and gratuitous VERB_HELLOs) - bool acceptableAge = _isLeaf ? (_paths[i].p->age(now) < (_failoverInterval + _downDelay)) : _paths[i].alive; - // Whether we've waited long enough since the link last came online - bool satisfiedUpDelay = (now - _paths[i].lastAliveToggle) >= _upDelay; - // How long since the last QoS was received (Must be less than ZT_PEER_PATH_EXPIRATION since the remote peer's _qosSendInterval isn't known) - bool acceptableQoSAge = (_paths[i].lastQoSReceived == 0 && inTrial) || ((now - _paths[i].lastQoSReceived) < ZT_PEER_EXPIRED_PATH_TRIAL_PERIOD); + /** + * Determine current eligibility + */ + bool currEligibility = false; + // Simple RX age (driven by packets of any type and gratuitous VERB_HELLOs) + bool acceptableAge = _isLeaf ? (_paths[i].p->age(now) < (_failoverInterval + _downDelay)) : _paths[i].alive; + // Whether we've waited long enough since the link last came online + bool satisfiedUpDelay = (now - _paths[i].lastAliveToggle) >= _upDelay; + // How long since the last QoS was received (Must be less than ZT_PEER_PATH_EXPIRATION since the remote peer's _qosSendInterval isn't known) + bool acceptableQoSAge = (_paths[i].lastQoSReceived == 0 && inTrial) || ((now - _paths[i].lastQoSReceived) < ZT_PEER_EXPIRED_PATH_TRIAL_PERIOD); - // Allow active-backup to operate without the receipt of QoS records - // This may be expanded to the other modes as an option - if (_policy == ZT_BOND_POLICY_ACTIVE_BACKUP) { - acceptableQoSAge = true; - } + // Allow active-backup to operate without the receipt of QoS records + // This may be expanded to the other modes as an option + if (_policy == ZT_BOND_POLICY_ACTIVE_BACKUP) { + acceptableQoSAge = true; + } - currEligibility = _paths[i].allowed() && ((acceptableAge && satisfiedUpDelay && acceptableQoSAge) || inTrial); + currEligibility = _paths[i].allowed() && ((acceptableAge && satisfiedUpDelay && acceptableQoSAge) || inTrial); - if (currEligibility) { - _paths[i].lastEligibility = now; - } + if (currEligibility) { + _paths[i].lastEligibility = now; + } - /** - * Note eligibility state change (if any) and take appropriate action - */ - if (currEligibility != _paths[i].eligible) { - if (currEligibility == 0) { - log("link %s is no longer eligible (reason: allowed=%d, age=%d, ud=%d, qos=%d, trial=%d)", pathToStr(_paths[i].p).c_str(), _paths[i].allowed(), acceptableAge, satisfiedUpDelay, acceptableQoSAge, inTrial); - } - if (currEligibility == 1) { - log("link %s is eligible", pathToStr(_paths[i].p).c_str()); - } - dumpPathStatus(now, i); - if (currEligibility) { - rebuildBond = true; - } - if (! currEligibility) { - _paths[i].adjustRefractoryPeriod(now, _defaultPathRefractoryPeriod, ! currEligibility); - if (_paths[i].bonded) { - debug("link %s was bonded, flow reallocation will occur soon", pathToStr(_paths[i].p).c_str()); - rebuildBond = true; - _paths[i].shouldAvoid = true; - _paths[i].bonded = false; - } - } - } - if (currEligibility) { - _paths[i].adjustRefractoryPeriod(now, _defaultPathRefractoryPeriod, false); - } - _paths[i].eligible = currEligibility; - } + /** + * Note eligibility state change (if any) and take appropriate action + */ + if (currEligibility != _paths[i].eligible) { + if (currEligibility == 0) { + log("link %s is no longer eligible (reason: allowed=%d, age=%d, ud=%d, qos=%d, trial=%d)", pathToStr(_paths[i].p).c_str(), _paths[i].allowed(), acceptableAge, satisfiedUpDelay, acceptableQoSAge, inTrial); + } + if (currEligibility == 1) { + log("link %s is eligible", pathToStr(_paths[i].p).c_str()); + } + dumpPathStatus(now, i); + if (currEligibility) { + rebuildBond = true; + } + if (! currEligibility) { + _paths[i].adjustRefractoryPeriod(now, _defaultPathRefractoryPeriod, ! currEligibility); + if (_paths[i].bonded) { + debug("link %s was bonded, flow reallocation will occur soon", pathToStr(_paths[i].p).c_str()); + rebuildBond = true; + _paths[i].shouldAvoid = true; + _paths[i].bonded = false; + } + } + } + if (currEligibility) { + _paths[i].adjustRefractoryPeriod(now, _defaultPathRefractoryPeriod, false); + } + _paths[i].eligible = currEligibility; + } - /** - * Trigger status report if number of links change - */ - _numAliveLinks = tmpNumAliveLinks; - _numTotalLinks = tmpNumTotalLinks; - if ((_numAliveLinks != tmpNumAliveLinks) || (_numTotalLinks != tmpNumTotalLinks)) { - dumpInfo(now, true); - } + /** + * Trigger status report if number of links change + */ + _numAliveLinks = tmpNumAliveLinks; + _numTotalLinks = tmpNumTotalLinks; + if ((_numAliveLinks != tmpNumAliveLinks) || (_numTotalLinks != tmpNumTotalLinks)) { + dumpInfo(now, true); + } - /** - * Check for failure of (all) primary links and inform bond to use spares if present - */ - bool foundUsablePrimaryPath = false; - for (int i = 0; i < ZT_MAX_PEER_NETWORK_PATHS; ++i) { - // debug("[%d], bonded=%d, alive=%d", i, _paths[i].bonded , _paths[i].alive); - if (_paths[i].p && _paths[i].bonded && _paths[i].alive) { - foundUsablePrimaryPath = true; - } - } - rebuildBond = rebuildBond ? true : ! foundUsablePrimaryPath; + /** + * Check for failure of (all) primary links and inform bond to use spares if present + */ + bool foundUsablePrimaryPath = false; + for (int i = 0; i < ZT_MAX_PEER_NETWORK_PATHS; ++i) { + // debug("[%d], bonded=%d, alive=%d", i, _paths[i].bonded , _paths[i].alive); + if (_paths[i].p && _paths[i].bonded && _paths[i].alive) { + foundUsablePrimaryPath = true; + } + } + rebuildBond = rebuildBond ? true : ! foundUsablePrimaryPath; - /** - * Curate the set of paths that are part of the bond proper. Select a set of paths - * per logical link according to eligibility and user-specified constraints. - */ - int updatedBondedPathCount = 0; - if ((_policy == ZT_BOND_POLICY_BALANCE_RR) || (_policy == ZT_BOND_POLICY_BALANCE_XOR) || (_policy == ZT_BOND_POLICY_BALANCE_AWARE)) { - if (! _numBondedPaths) { - rebuildBond = true; - } - if (rebuildBond) { - // Clear previous bonded index mapping - for (int i = 0; i < ZT_MAX_PEER_NETWORK_PATHS; ++i) { - _realIdxMap[i] = ZT_MAX_PEER_NETWORK_PATHS; - _paths[i].bonded = false; - } + /** + * Curate the set of paths that are part of the bond proper. Select a set of paths + * per logical link according to eligibility and user-specified constraints. + */ + int updatedBondedPathCount = 0; + if ((_policy == ZT_BOND_POLICY_BALANCE_RR) || (_policy == ZT_BOND_POLICY_BALANCE_XOR) || (_policy == ZT_BOND_POLICY_BALANCE_AWARE)) { + if (! _numBondedPaths) { + rebuildBond = true; + } + if (rebuildBond) { + // Clear previous bonded index mapping + for (int i = 0; i < ZT_MAX_PEER_NETWORK_PATHS; ++i) { + _realIdxMap[i] = ZT_MAX_PEER_NETWORK_PATHS; + _paths[i].bonded = false; + } - // Build map associating paths with local physical links. Will be selected from in next step - std::map, std::vector > linkMap; - for (int i = 0; i < ZT_MAX_PEER_NETWORK_PATHS; ++i) { - if (_paths[i].p) { - SharedPtr link = RR->bc->getLinkBySocket(_policyAlias, _paths[i].p->localSocket()); - if (link) { - linkMap[link].push_back(i); - } - } - } - // Re-form bond from link<->path map - std::map, std::vector >::iterator it = linkMap.begin(); - while (it != linkMap.end()) { - SharedPtr link = it->first; + // Build map associating paths with local physical links. Will be selected from in next step + std::map, std::vector > linkMap; + for (int i = 0; i < ZT_MAX_PEER_NETWORK_PATHS; ++i) { + if (_paths[i].p) { + SharedPtr link = RR->bc->getLinkBySocket(_policyAlias, _paths[i].p->localSocket()); + if (link) { + linkMap[link].push_back(i); + } + } + } + // Re-form bond from link<->path map + std::map, std::vector >::iterator it = linkMap.begin(); + while (it != linkMap.end()) { + SharedPtr link = it->first; - // Bond a spare link if required (no viable primary links left) - if (! foundUsablePrimaryPath) { - // debug("no usable primary links remain, will attempt to use spare if available"); - for (int j = 0; j < it->second.size(); j++) { - int idx = it->second.at(j); - if (! _paths[idx].p || ! _paths[idx].eligible || ! _paths[idx].allowed() || ! _paths[idx].isSpare()) { - continue; - } - addPathToBond(idx, updatedBondedPathCount); - ++updatedBondedPathCount; - debug("add %s (spare)", pathToStr(_paths[idx].p).c_str()); - } - } + // Bond a spare link if required (no viable primary links left) + if (! foundUsablePrimaryPath) { + // debug("no usable primary links remain, will attempt to use spare if available"); + for (int j = 0; j < it->second.size(); j++) { + int idx = it->second.at(j); + if (! _paths[idx].p || ! _paths[idx].eligible || ! _paths[idx].allowed() || ! _paths[idx].isSpare()) { + continue; + } + addPathToBond(idx, updatedBondedPathCount); + ++updatedBondedPathCount; + debug("add %s (spare)", pathToStr(_paths[idx].p).c_str()); + } + } - int ipvPref = link->ipvPref(); + int ipvPref = link->ipvPref(); - // If user has no address type preference, then use every path we find on a link - if (ipvPref == 0) { - for (int j = 0; j < it->second.size(); j++) { - int idx = it->second.at(j); - if (! _paths[idx].p || ! _paths[idx].eligible || ! _paths[idx].allowed() || _paths[idx].isSpare()) { - continue; - } - addPathToBond(idx, updatedBondedPathCount); - ++updatedBondedPathCount; - debug("add %s (no user addr preference)", pathToStr(_paths[idx].p).c_str()); - } - } - // If the user prefers to only use one address type (IPv4 or IPv6) - if (ipvPref == 4 || ipvPref == 6) { - for (int j = 0; j < it->second.size(); j++) { - int idx = it->second.at(j); - if (! _paths[idx].p || ! _paths[idx].eligible || _paths[idx].isSpare()) { - continue; - } - if (! _paths[idx].allowed()) { - debug("did not add %s (user addr preference %d)", pathToStr(_paths[idx].p).c_str(), ipvPref); - continue; - } - addPathToBond(idx, updatedBondedPathCount); - ++updatedBondedPathCount; - debug("add path %s (user addr preference %d)", pathToStr(_paths[idx].p).c_str(), ipvPref); - } - } - // If the users prefers one address type to another, try to find at least - // one path of that type before considering others. - if (ipvPref == 46 || ipvPref == 64) { - bool foundPreferredPath = false; - // Search for preferred paths - for (int j = 0; j < it->second.size(); j++) { - int idx = it->second.at(j); - if (! _paths[idx].p || ! _paths[idx].eligible || ! _paths[idx].allowed() || _paths[idx].isSpare()) { - continue; - } - if (_paths[idx].preferred()) { - addPathToBond(idx, updatedBondedPathCount); - ++updatedBondedPathCount; - debug("add %s (user addr preference %d)", pathToStr(_paths[idx].p).c_str(), ipvPref); - foundPreferredPath = true; - } - } - // Unable to find a path that matches user preference, settle for another address type - if (! foundPreferredPath) { - debug("did not find first-choice path type on link %s (user preference %d)", link->ifname().c_str(), ipvPref); - for (int j = 0; j < it->second.size(); j++) { - int idx = it->second.at(j); - if (! _paths[idx].p || ! _paths[idx].eligible || _paths[idx].isSpare()) { - continue; - } - addPathToBond(idx, updatedBondedPathCount); - ++updatedBondedPathCount; - debug("add %s (user addr preference %d)", pathToStr(_paths[idx].p).c_str(), ipvPref); - foundPreferredPath = true; - } - } - } - ++it; // Next link - } - _numBondedPaths = updatedBondedPathCount; - if (_policy == ZT_BOND_POLICY_BALANCE_RR) { - // Cause a RR reset since the current index might no longer be valid - _rrPacketsSentOnCurrLink = _packetsPerLink; - _rrIdx = 0; - } - } - } - if (_policy == ZT_BOND_POLICY_ACTIVE_BACKUP) { - for (int i = 0; i < ZT_MAX_PEER_NETWORK_PATHS; ++i) { - if (_paths[i].p && _paths[i].bonded) { - updatedBondedPathCount++; - } - } - _numBondedPaths = updatedBondedPathCount; - } + // If user has no address type preference, then use every path we find on a link + if (ipvPref == 0) { + for (int j = 0; j < it->second.size(); j++) { + int idx = it->second.at(j); + if (! _paths[idx].p || ! _paths[idx].eligible || ! _paths[idx].allowed() || _paths[idx].isSpare()) { + continue; + } + addPathToBond(idx, updatedBondedPathCount); + ++updatedBondedPathCount; + debug("add %s (no user addr preference)", pathToStr(_paths[idx].p).c_str()); + } + } + // If the user prefers to only use one address type (IPv4 or IPv6) + if (ipvPref == 4 || ipvPref == 6) { + for (int j = 0; j < it->second.size(); j++) { + int idx = it->second.at(j); + if (! _paths[idx].p || ! _paths[idx].eligible || _paths[idx].isSpare()) { + continue; + } + if (! _paths[idx].allowed()) { + debug("did not add %s (user addr preference %d)", pathToStr(_paths[idx].p).c_str(), ipvPref); + continue; + } + addPathToBond(idx, updatedBondedPathCount); + ++updatedBondedPathCount; + debug("add path %s (user addr preference %d)", pathToStr(_paths[idx].p).c_str(), ipvPref); + } + } + // If the users prefers one address type to another, try to find at least + // one path of that type before considering others. + if (ipvPref == 46 || ipvPref == 64) { + bool foundPreferredPath = false; + // Search for preferred paths + for (int j = 0; j < it->second.size(); j++) { + int idx = it->second.at(j); + if (! _paths[idx].p || ! _paths[idx].eligible || ! _paths[idx].allowed() || _paths[idx].isSpare()) { + continue; + } + if (_paths[idx].preferred()) { + addPathToBond(idx, updatedBondedPathCount); + ++updatedBondedPathCount; + debug("add %s (user addr preference %d)", pathToStr(_paths[idx].p).c_str(), ipvPref); + foundPreferredPath = true; + } + } + // Unable to find a path that matches user preference, settle for another address type + if (! foundPreferredPath) { + debug("did not find first-choice path type on link %s (user preference %d)", link->ifname().c_str(), ipvPref); + for (int j = 0; j < it->second.size(); j++) { + int idx = it->second.at(j); + if (! _paths[idx].p || ! _paths[idx].eligible || _paths[idx].isSpare()) { + continue; + } + addPathToBond(idx, updatedBondedPathCount); + ++updatedBondedPathCount; + debug("add %s (user addr preference %d)", pathToStr(_paths[idx].p).c_str(), ipvPref); + foundPreferredPath = true; + } + } + } + ++it; // Next link + } + _numBondedPaths = updatedBondedPathCount; + if (_policy == ZT_BOND_POLICY_BALANCE_RR) { + // Cause a RR reset since the current index might no longer be valid + _rrPacketsSentOnCurrLink = _packetsPerLink; + _rrIdx = 0; + } + } + } + if (_policy == ZT_BOND_POLICY_ACTIVE_BACKUP) { + for (int i = 0; i < ZT_MAX_PEER_NETWORK_PATHS; ++i) { + if (_paths[i].p && _paths[i].bonded) { + updatedBondedPathCount++; + } + } + _numBondedPaths = updatedBondedPathCount; + } } void Bond::estimatePathQuality(int64_t now) { - float lat[ZT_MAX_PEER_NETWORK_PATHS] = { 0 }; - float pdv[ZT_MAX_PEER_NETWORK_PATHS] = { 0 }; - float plr[ZT_MAX_PEER_NETWORK_PATHS] = { 0 }; - float per[ZT_MAX_PEER_NETWORK_PATHS] = { 0 }; + float lat[ZT_MAX_PEER_NETWORK_PATHS] = { 0 }; + float pdv[ZT_MAX_PEER_NETWORK_PATHS] = { 0 }; + float plr[ZT_MAX_PEER_NETWORK_PATHS] = { 0 }; + float per[ZT_MAX_PEER_NETWORK_PATHS] = { 0 }; - float maxLAT = 0; - float maxPDV = 0; - float maxPLR = 0; - float maxPER = 0; + float maxLAT = 0; + float maxPDV = 0; + float maxPLR = 0; + float maxPER = 0; - float absoluteQuality[ZT_MAX_PEER_NETWORK_PATHS] = { 0 }; + float absoluteQuality[ZT_MAX_PEER_NETWORK_PATHS] = { 0 }; - float totQuality = 0.0f; + float totQuality = 0.0f; - // Process observation samples, compute summary statistics, and compute relative link qualities - for (unsigned int i = 0; i < ZT_MAX_PEER_NETWORK_PATHS; ++i) { - if (! _paths[i].p || ! _paths[i].allowed()) { - continue; - } - // Drain unacknowledged QoS records - int qosRecordTimeout = (_qosSendInterval * 3); - std::map::iterator it = _paths[i].qosStatsOut.begin(); - int numDroppedQosOutRecords = 0; - while (it != _paths[i].qosStatsOut.end()) { - if ((now - it->second) >= qosRecordTimeout) { - it = _paths[i].qosStatsOut.erase(it); - ++numDroppedQosOutRecords; - } - else { - ++it; - } - } - if (numDroppedQosOutRecords) { - // debug("dropped %d QOS out-records", numDroppedQosOutRecords); - } + // Process observation samples, compute summary statistics, and compute relative link qualities + for (unsigned int i = 0; i < ZT_MAX_PEER_NETWORK_PATHS; ++i) { + if (! _paths[i].p || ! _paths[i].allowed()) { + continue; + } + // Drain unacknowledged QoS records + int qosRecordTimeout = (_qosSendInterval * 3); + std::map::iterator it = _paths[i].qosStatsOut.begin(); + int numDroppedQosOutRecords = 0; + while (it != _paths[i].qosStatsOut.end()) { + if ((now - it->second) >= qosRecordTimeout) { + it = _paths[i].qosStatsOut.erase(it); + ++numDroppedQosOutRecords; + } + else { + ++it; + } + } + if (numDroppedQosOutRecords) { + // debug("dropped %d QOS out-records", numDroppedQosOutRecords); + } - /* - for (unsigned int i = 0; i < ZT_MAX_PEER_NETWORK_PATHS; ++i) { - if (! _paths[i].p) { - continue; - } - // if ((now - _paths[i].lastAckReceived) > ackSendInterval) { - // debug("been a while since ACK"); - // if (_paths[i].unackedBytes > 0) { - // _paths[i].unackedBytes / _paths[i].bytesSen - // } - // } - } - */ + /* + for (unsigned int i = 0; i < ZT_MAX_PEER_NETWORK_PATHS; ++i) { + if (! _paths[i].p) { + continue; + } + // if ((now - _paths[i].lastAckReceived) > ackSendInterval) { + // debug("been a while since ACK"); + // if (_paths[i].unackedBytes > 0) { + // _paths[i].unackedBytes / _paths[i].bytesSen + // } + // } + } + */ - it = _paths[i].qosStatsIn.begin(); - int numDroppedQosInRecords = 0; - while (it != _paths[i].qosStatsIn.end()) { - if ((now - it->second) >= qosRecordTimeout) { - it = _paths[i].qosStatsIn.erase(it); - ++numDroppedQosInRecords; - } - else { - ++it; - } - } - if (numDroppedQosInRecords) { - // debug("dropped %d QOS in-records", numDroppedQosInRecords); - } + it = _paths[i].qosStatsIn.begin(); + int numDroppedQosInRecords = 0; + while (it != _paths[i].qosStatsIn.end()) { + if ((now - it->second) >= qosRecordTimeout) { + it = _paths[i].qosStatsIn.erase(it); + ++numDroppedQosInRecords; + } + else { + ++it; + } + } + if (numDroppedQosInRecords) { + // debug("dropped %d QOS in-records", numDroppedQosInRecords); + } - absoluteQuality[i] = 0; - totQuality = 0; - // Normalize raw observations according to sane limits and/or user specified values - lat[i] = 1.0 / expf(4 * Utils::normalize(_paths[i].latency, 0, _qw[ZT_QOS_LAT_MAX_IDX], 0, 1)); - pdv[i] = 1.0 / expf(4 * Utils::normalize(_paths[i].latencyVariance, 0, _qw[ZT_QOS_PDV_MAX_IDX], 0, 1)); - plr[i] = 1.0 / expf(4 * Utils::normalize(_paths[i].packetLossRatio, 0, _qw[ZT_QOS_PLR_MAX_IDX], 0, 1)); - per[i] = 1.0 / expf(4 * Utils::normalize(_paths[i].packetErrorRatio, 0, _qw[ZT_QOS_PER_MAX_IDX], 0, 1)); - // Record bond-wide maximums to determine relative values - maxLAT = lat[i] > maxLAT ? lat[i] : maxLAT; - maxPDV = pdv[i] > maxPDV ? pdv[i] : maxPDV; - maxPLR = plr[i] > maxPLR ? plr[i] : maxPLR; - maxPER = per[i] > maxPER ? per[i] : maxPER; - } + absoluteQuality[i] = 0; + totQuality = 0; + // Normalize raw observations according to sane limits and/or user specified values + lat[i] = 1.0 / expf(4 * Utils::normalize(_paths[i].latency, 0, _qw[ZT_QOS_LAT_MAX_IDX], 0, 1)); + pdv[i] = 1.0 / expf(4 * Utils::normalize(_paths[i].latencyVariance, 0, _qw[ZT_QOS_PDV_MAX_IDX], 0, 1)); + plr[i] = 1.0 / expf(4 * Utils::normalize(_paths[i].packetLossRatio, 0, _qw[ZT_QOS_PLR_MAX_IDX], 0, 1)); + per[i] = 1.0 / expf(4 * Utils::normalize(_paths[i].packetErrorRatio, 0, _qw[ZT_QOS_PER_MAX_IDX], 0, 1)); + // Record bond-wide maximums to determine relative values + maxLAT = lat[i] > maxLAT ? lat[i] : maxLAT; + maxPDV = pdv[i] > maxPDV ? pdv[i] : maxPDV; + maxPLR = plr[i] > maxPLR ? plr[i] : maxPLR; + maxPER = per[i] > maxPER ? per[i] : maxPER; + } - // Compute relative user-specified link capacities (may change during life of Bond) - int maxObservedLinkCap = 0; - // Find current maximum - for (unsigned int i = 0; i < ZT_MAX_PEER_NETWORK_PATHS; ++i) { - if (_paths[i].p && _paths[i].allowed()) { - SharedPtr link = RR->bc->getLinkBySocket(_policyAlias, _paths[i].p->localSocket()); - if (link) { - int linkSpeed = link->capacity(); - _paths[i].p->_givenLinkSpeed = linkSpeed; - _paths[i].p->_mtu = link->mtu() ? link->mtu() : _paths[i].p->_mtu; - _paths[i].p->_assignedFlowCount = _paths[i].assignedFlowCount; - maxObservedLinkCap = linkSpeed > maxObservedLinkCap ? linkSpeed : maxObservedLinkCap; - } - } - } - // Compute relative link capacity (Used for weighting traffic allocations) - for (unsigned int i = 0; i < ZT_MAX_PEER_NETWORK_PATHS; ++i) { - if (_paths[i].p && _paths[i].allowed()) { - SharedPtr link = RR->bc->getLinkBySocket(_policyAlias, _paths[i].p->localSocket()); - if (link) { - float relativeCapacity = (link->capacity() / (float)maxObservedLinkCap); - link->setRelativeCapacity(relativeCapacity); - _paths[i].relativeLinkCapacity = relativeCapacity; - } - } - } + // Compute relative user-specified link capacities (may change during life of Bond) + int maxObservedLinkCap = 0; + // Find current maximum + for (unsigned int i = 0; i < ZT_MAX_PEER_NETWORK_PATHS; ++i) { + if (_paths[i].p && _paths[i].allowed()) { + SharedPtr link = RR->bc->getLinkBySocket(_policyAlias, _paths[i].p->localSocket()); + if (link) { + int linkSpeed = link->capacity(); + _paths[i].p->_givenLinkSpeed = linkSpeed; + _paths[i].p->_mtu = link->mtu() ? link->mtu() : _paths[i].p->_mtu; + _paths[i].p->_assignedFlowCount = _paths[i].assignedFlowCount; + maxObservedLinkCap = linkSpeed > maxObservedLinkCap ? linkSpeed : maxObservedLinkCap; + } + } + } + // Compute relative link capacity (Used for weighting traffic allocations) + for (unsigned int i = 0; i < ZT_MAX_PEER_NETWORK_PATHS; ++i) { + if (_paths[i].p && _paths[i].allowed()) { + SharedPtr link = RR->bc->getLinkBySocket(_policyAlias, _paths[i].p->localSocket()); + if (link) { + float relativeCapacity = (link->capacity() / (float)maxObservedLinkCap); + link->setRelativeCapacity(relativeCapacity); + _paths[i].relativeLinkCapacity = relativeCapacity; + } + } + } - // Convert metrics to relative quantities and apply contribution weights - for (unsigned int i = 0; i < ZT_MAX_PEER_NETWORK_PATHS; ++i) { - if (_paths[i].p && _paths[i].bonded) { - absoluteQuality[i] += ((maxLAT > 0.0f ? lat[i] / maxLAT : 0.0f) * _qw[ZT_QOS_LAT_WEIGHT_IDX]); - absoluteQuality[i] += ((maxPDV > 0.0f ? pdv[i] / maxPDV : 0.0f) * _qw[ZT_QOS_PDV_WEIGHT_IDX]); - absoluteQuality[i] += ((maxPLR > 0.0f ? plr[i] / maxPLR : 0.0f) * _qw[ZT_QOS_PLR_WEIGHT_IDX]); - absoluteQuality[i] += ((maxPER > 0.0f ? per[i] / maxPER : 0.0f) * _qw[ZT_QOS_PER_WEIGHT_IDX]); - absoluteQuality[i] *= _paths[i].relativeLinkCapacity; - totQuality += absoluteQuality[i]; - } - } + // Convert metrics to relative quantities and apply contribution weights + for (unsigned int i = 0; i < ZT_MAX_PEER_NETWORK_PATHS; ++i) { + if (_paths[i].p && _paths[i].bonded) { + absoluteQuality[i] += ((maxLAT > 0.0f ? lat[i] / maxLAT : 0.0f) * _qw[ZT_QOS_LAT_WEIGHT_IDX]); + absoluteQuality[i] += ((maxPDV > 0.0f ? pdv[i] / maxPDV : 0.0f) * _qw[ZT_QOS_PDV_WEIGHT_IDX]); + absoluteQuality[i] += ((maxPLR > 0.0f ? plr[i] / maxPLR : 0.0f) * _qw[ZT_QOS_PLR_WEIGHT_IDX]); + absoluteQuality[i] += ((maxPER > 0.0f ? per[i] / maxPER : 0.0f) * _qw[ZT_QOS_PER_WEIGHT_IDX]); + absoluteQuality[i] *= _paths[i].relativeLinkCapacity; + totQuality += absoluteQuality[i]; + } + } - // Compute quality of link relative to all others in the bond (also accounting for stated link capacity) - if (totQuality > 0.0) { - for (unsigned int i = 0; i < ZT_MAX_PEER_NETWORK_PATHS; ++i) { - if (_paths[i].p && _paths[i].bonded) { - _paths[i].relativeQuality = absoluteQuality[i] / totQuality; - // debug("[%2d], abs=%f, tot=%f, rel=%f, relcap=%f", i, absoluteQuality[i], totQuality, _paths[i].relativeQuality, _paths[i].relativeLinkCapacity); - } - } - } + // Compute quality of link relative to all others in the bond (also accounting for stated link capacity) + if (totQuality > 0.0) { + for (unsigned int i = 0; i < ZT_MAX_PEER_NETWORK_PATHS; ++i) { + if (_paths[i].p && _paths[i].bonded) { + _paths[i].relativeQuality = absoluteQuality[i] / totQuality; + // debug("[%2d], abs=%f, tot=%f, rel=%f, relcap=%f", i, absoluteQuality[i], totQuality, _paths[i].relativeQuality, _paths[i].relativeLinkCapacity); + } + } + } - // Compute summary statistics - for (unsigned int i = 0; i < ZT_MAX_PEER_NETWORK_PATHS; ++i) { - if (! _paths[i].p || ! _paths[i].allowed()) { - continue; - } - // Compute/Smooth average of real-world observations - if (_paths[i].latencySamples.count() >= ZT_QOS_SHORTTERM_SAMPLE_WIN_MIN_REQ_SIZE) { - _paths[i].latency = _paths[i].latencySamples.mean(); - } - if (_paths[i].latencySamples.count() >= ZT_QOS_SHORTTERM_SAMPLE_WIN_MIN_REQ_SIZE) { - _paths[i].latencyVariance = _paths[i].latencySamples.stddev(); - } + // Compute summary statistics + for (unsigned int i = 0; i < ZT_MAX_PEER_NETWORK_PATHS; ++i) { + if (! _paths[i].p || ! _paths[i].allowed()) { + continue; + } + // Compute/Smooth average of real-world observations + if (_paths[i].latencySamples.count() >= ZT_QOS_SHORTTERM_SAMPLE_WIN_MIN_REQ_SIZE) { + _paths[i].latency = _paths[i].latencySamples.mean(); + } + if (_paths[i].latencySamples.count() >= ZT_QOS_SHORTTERM_SAMPLE_WIN_MIN_REQ_SIZE) { + _paths[i].latencyVariance = _paths[i].latencySamples.stddev(); + } - // Write values to external path object so that it can be propagated to the user - _paths[i].p->_latencyMean = _paths[i].latency; - _paths[i].p->_latencyVariance = _paths[i].latencyVariance; - _paths[i].p->_packetLossRatio = _paths[i].packetLossRatio; - _paths[i].p->_packetErrorRatio = _paths[i].packetErrorRatio; - _paths[i].p->_bonded = _paths[i].bonded; - _paths[i].p->_eligible = _paths[i].eligible; - //_paths[i].packetErrorRatio = 1.0 - (_paths[i].packetValiditySamples.count() ? _paths[i].packetValiditySamples.mean() : 1.0); - // _valid is written elsewhere - _paths[i].p->_relativeQuality = _paths[i].relativeQuality; - _paths[i].p->_localPort = _paths[i].localPort; - } + // Write values to external path object so that it can be propagated to the user + _paths[i].p->_latencyMean = _paths[i].latency; + _paths[i].p->_latencyVariance = _paths[i].latencyVariance; + _paths[i].p->_packetLossRatio = _paths[i].packetLossRatio; + _paths[i].p->_packetErrorRatio = _paths[i].packetErrorRatio; + _paths[i].p->_bonded = _paths[i].bonded; + _paths[i].p->_eligible = _paths[i].eligible; + //_paths[i].packetErrorRatio = 1.0 - (_paths[i].packetValiditySamples.count() ? _paths[i].packetValiditySamples.mean() : 1.0); + // _valid is written elsewhere + _paths[i].p->_relativeQuality = _paths[i].relativeQuality; + _paths[i].p->_localPort = _paths[i].localPort; + } - // Flag links for avoidance - for (unsigned int i = 0; i < ZT_MAX_PEER_NETWORK_PATHS; ++i) { - if (! _paths[i].p || ! _paths[i].allowed()) { - continue; - } - bool shouldAvoid = false; - if (! _paths[i].shouldAvoid) { - if (_paths[i].latency > _qw[ZT_QOS_LAT_MAX_IDX]) { - log("avoiding link %s because (lat %6.4f > %6.4f)", pathToStr(_paths[i].p).c_str(), _paths[i].latency, _qw[ZT_QOS_LAT_MAX_IDX]); - shouldAvoid = true; - } - if (_paths[i].latencyVariance > _qw[ZT_QOS_PDV_MAX_IDX]) { - log("avoiding link %s because (pdv %6.4f > %6.4f)", pathToStr(_paths[i].p).c_str(), _paths[i].latencyVariance, _qw[ZT_QOS_PDV_MAX_IDX]); - shouldAvoid = true; - } - if (_paths[i].packetErrorRatio > _qw[ZT_QOS_PER_MAX_IDX]) { - log("avoiding link %s because (per %6.4f > %6.4f)", pathToStr(_paths[i].p).c_str(), _paths[i].packetErrorRatio, _qw[ZT_QOS_PER_MAX_IDX]); - shouldAvoid = true; - } - if (_paths[i].packetLossRatio > _qw[ZT_QOS_PLR_MAX_IDX]) { - log("avoiding link %s because (plr %6.4f > %6.4f)", pathToStr(_paths[i].p).c_str(), _paths[i].packetLossRatio, _qw[ZT_QOS_PLR_MAX_IDX]); - shouldAvoid = true; - } - _paths[i].shouldAvoid = shouldAvoid; - } - else { - if (! shouldAvoid) { - log("no longer avoiding link %s", pathToStr(_paths[i].p).c_str()); - _paths[i].shouldAvoid = false; - } - } - } + // Flag links for avoidance + for (unsigned int i = 0; i < ZT_MAX_PEER_NETWORK_PATHS; ++i) { + if (! _paths[i].p || ! _paths[i].allowed()) { + continue; + } + bool shouldAvoid = false; + if (! _paths[i].shouldAvoid) { + if (_paths[i].latency > _qw[ZT_QOS_LAT_MAX_IDX]) { + log("avoiding link %s because (lat %6.4f > %6.4f)", pathToStr(_paths[i].p).c_str(), _paths[i].latency, _qw[ZT_QOS_LAT_MAX_IDX]); + shouldAvoid = true; + } + if (_paths[i].latencyVariance > _qw[ZT_QOS_PDV_MAX_IDX]) { + log("avoiding link %s because (pdv %6.4f > %6.4f)", pathToStr(_paths[i].p).c_str(), _paths[i].latencyVariance, _qw[ZT_QOS_PDV_MAX_IDX]); + shouldAvoid = true; + } + if (_paths[i].packetErrorRatio > _qw[ZT_QOS_PER_MAX_IDX]) { + log("avoiding link %s because (per %6.4f > %6.4f)", pathToStr(_paths[i].p).c_str(), _paths[i].packetErrorRatio, _qw[ZT_QOS_PER_MAX_IDX]); + shouldAvoid = true; + } + if (_paths[i].packetLossRatio > _qw[ZT_QOS_PLR_MAX_IDX]) { + log("avoiding link %s because (plr %6.4f > %6.4f)", pathToStr(_paths[i].p).c_str(), _paths[i].packetLossRatio, _qw[ZT_QOS_PLR_MAX_IDX]); + shouldAvoid = true; + } + _paths[i].shouldAvoid = shouldAvoid; + } + else { + if (! shouldAvoid) { + log("no longer avoiding link %s", pathToStr(_paths[i].p).c_str()); + _paths[i].shouldAvoid = false; + } + } + } } void Bond::processBalanceTasks(int64_t now) { - if (! _numBondedPaths) { - return; - } - /** - * Clean up and reset flows if necessary - */ - if ((now - _lastFlowExpirationCheck) > ZT_PEER_PATH_EXPIRATION) { - Mutex::Lock _l(_flows_m); - forgetFlowsWhenNecessary(ZT_PEER_PATH_EXPIRATION, false, now); - std::map >::iterator it = _flows.begin(); - while (it != _flows.end()) { - it->second->resetByteCounts(); - ++it; - } - _lastFlowExpirationCheck = now; - } - /** - * Move (all) flows from dead paths - */ - if (_policy == ZT_BOND_POLICY_BALANCE_XOR || _policy == ZT_BOND_POLICY_BALANCE_AWARE) { - Mutex::Lock _l(_flows_m); - std::map >::iterator flow_it = _flows.begin(); - while (flow_it != _flows.end()) { - if (_paths[flow_it->second->assignedPath].p) { - int originalPathIdx = flow_it->second->assignedPath; - if (! _paths[originalPathIdx].eligible) { - log("moving all flows from dead link %s", pathToStr(_paths[originalPathIdx].p).c_str()); - if (assignFlowToBondedPath(flow_it->second, now, true)) { - _paths[originalPathIdx].assignedFlowCount--; - } - } - } - ++flow_it; - } - } - /** - * Move (some) flows from low quality paths - */ - if (_policy == ZT_BOND_POLICY_BALANCE_AWARE) { - Mutex::Lock _l(_flows_m); - std::map >::iterator flow_it = _flows.begin(); - while (flow_it != _flows.end()) { - if (_paths[flow_it->second->assignedPath].p) { - int originalPathIdx = flow_it->second->assignedPath; - if (_paths[originalPathIdx].shouldAvoid) { - if (assignFlowToBondedPath(flow_it->second, now, true)) { - _paths[originalPathIdx].assignedFlowCount--; - return; // Only move one flow at a time - } - } - } - ++flow_it; - } - } + if (! _numBondedPaths) { + return; + } + /** + * Clean up and reset flows if necessary + */ + if ((now - _lastFlowExpirationCheck) > ZT_PEER_PATH_EXPIRATION) { + Mutex::Lock _l(_flows_m); + forgetFlowsWhenNecessary(ZT_PEER_PATH_EXPIRATION, false, now); + std::map >::iterator it = _flows.begin(); + while (it != _flows.end()) { + it->second->resetByteCounts(); + ++it; + } + _lastFlowExpirationCheck = now; + } + /** + * Move (all) flows from dead paths + */ + if (_policy == ZT_BOND_POLICY_BALANCE_XOR || _policy == ZT_BOND_POLICY_BALANCE_AWARE) { + Mutex::Lock _l(_flows_m); + std::map >::iterator flow_it = _flows.begin(); + while (flow_it != _flows.end()) { + if (_paths[flow_it->second->assignedPath].p) { + int originalPathIdx = flow_it->second->assignedPath; + if (! _paths[originalPathIdx].eligible) { + log("moving all flows from dead link %s", pathToStr(_paths[originalPathIdx].p).c_str()); + if (assignFlowToBondedPath(flow_it->second, now, true)) { + _paths[originalPathIdx].assignedFlowCount--; + } + } + } + ++flow_it; + } + } + /** + * Move (some) flows from low quality paths + */ + if (_policy == ZT_BOND_POLICY_BALANCE_AWARE) { + Mutex::Lock _l(_flows_m); + std::map >::iterator flow_it = _flows.begin(); + while (flow_it != _flows.end()) { + if (_paths[flow_it->second->assignedPath].p) { + int originalPathIdx = flow_it->second->assignedPath; + if (_paths[originalPathIdx].shouldAvoid) { + if (assignFlowToBondedPath(flow_it->second, now, true)) { + _paths[originalPathIdx].assignedFlowCount--; + return; // Only move one flow at a time + } + } + } + ++flow_it; + } + } } void Bond::dequeueNextActiveBackupPath(uint64_t now) { - if (_abFailoverQueue.empty()) { - return; - } - _abPathIdx = _abFailoverQueue.front(); - _abFailoverQueue.pop_front(); - _lastActiveBackupPathChange = now; - for (int i = 0; i < ZT_MAX_PEER_NETWORK_PATHS; ++i) { - if (_paths[i].p) { - _paths[i].resetPacketCounts(); - } - } + if (_abFailoverQueue.empty()) { + return; + } + _abPathIdx = _abFailoverQueue.front(); + _abFailoverQueue.pop_front(); + _lastActiveBackupPathChange = now; + for (int i = 0; i < ZT_MAX_PEER_NETWORK_PATHS; ++i) { + if (_paths[i].p) { + _paths[i].resetPacketCounts(); + } + } } bool Bond::abForciblyRotateLink() { - Mutex::Lock _l(_paths_m); - if (_policy == ZT_BOND_POLICY_ACTIVE_BACKUP) { - int prevPathIdx = _abPathIdx; - dequeueNextActiveBackupPath(RR->node->now()); - log("active link rotated from %s to %s", pathToStr(_paths[prevPathIdx].p).c_str(), pathToStr(_paths[_abPathIdx].p).c_str()); - return true; - } - return false; + Mutex::Lock _l(_paths_m); + if (_policy == ZT_BOND_POLICY_ACTIVE_BACKUP) { + int prevPathIdx = _abPathIdx; + dequeueNextActiveBackupPath(RR->node->now()); + log("active link rotated from %s to %s", pathToStr(_paths[prevPathIdx].p).c_str(), pathToStr(_paths[_abPathIdx].p).c_str()); + return true; + } + return false; } void Bond::processActiveBackupTasks(void* tPtr, int64_t now) { - int prevActiveBackupPathIdx = _abPathIdx; - int nonPreferredPathIdx = ZT_MAX_PEER_NETWORK_PATHS; - bool foundPathOnPrimaryLink = false; - bool foundPreferredPath = false; + int prevActiveBackupPathIdx = _abPathIdx; + int nonPreferredPathIdx = ZT_MAX_PEER_NETWORK_PATHS; + bool foundPathOnPrimaryLink = false; + bool foundPreferredPath = false; - if (_abPathIdx != ZT_MAX_PEER_NETWORK_PATHS && ! _paths[_abPathIdx].p) { - _abPathIdx = ZT_MAX_PEER_NETWORK_PATHS; - log("main active-backup path has been removed"); - } + if (_abPathIdx != ZT_MAX_PEER_NETWORK_PATHS && ! _paths[_abPathIdx].p) { + _abPathIdx = ZT_MAX_PEER_NETWORK_PATHS; + log("main active-backup path has been removed"); + } - /** - * Generate periodic status report - */ - if ((now - _lastBondStatusLog) > ZT_BOND_STATUS_INTERVAL) { - _lastBondStatusLog = now; - if (_abPathIdx == ZT_MAX_PEER_NETWORK_PATHS) { - log("no active link"); - } - else if (_paths[_abPathIdx].p) { - log("active link is %s, failover queue size is %zu", pathToStr(_paths[_abPathIdx].p).c_str(), _abFailoverQueue.size()); - } - if (_abFailoverQueue.empty()) { - log("failover queue is empty, bond is no longer fault-tolerant"); - } - } - /** - * Select initial "active" active-backup link - */ - if (_abPathIdx == ZT_MAX_PEER_NETWORK_PATHS) { - /** - * [Automatic mode] - * The user has not explicitly specified links or their failover schedule, - * the bonding policy will now select the first eligible path and set it as - * its active backup path, if a substantially better path is detected the bonding - * policy will assign it as the new active backup path. If the path fails it will - * simply find the next eligible path. - */ - if (! userHasSpecifiedLinks()) { - for (int i = 0; i < ZT_MAX_PEER_NETWORK_PATHS; ++i) { - if (_paths[i].p && _paths[i].eligible) { - SharedPtr link = RR->bc->getLinkBySocket(_policyAlias, _paths[i].p->localSocket()); - if (link) { - log("found eligible link %s", pathToStr(_paths[i].p).c_str()); - _abPathIdx = i; - break; - } - } - } - } + /** + * Generate periodic status report + */ + if ((now - _lastBondStatusLog) > ZT_BOND_STATUS_INTERVAL) { + _lastBondStatusLog = now; + if (_abPathIdx == ZT_MAX_PEER_NETWORK_PATHS) { + log("no active link"); + } + else if (_paths[_abPathIdx].p) { + log("active link is %s, failover queue size is %zu", pathToStr(_paths[_abPathIdx].p).c_str(), _abFailoverQueue.size()); + } + if (_abFailoverQueue.empty()) { + log("failover queue is empty, bond is no longer fault-tolerant"); + } + } + /** + * Select initial "active" active-backup link + */ + if (_abPathIdx == ZT_MAX_PEER_NETWORK_PATHS) { + /** + * [Automatic mode] + * The user has not explicitly specified links or their failover schedule, + * the bonding policy will now select the first eligible path and set it as + * its active backup path, if a substantially better path is detected the bonding + * policy will assign it as the new active backup path. If the path fails it will + * simply find the next eligible path. + */ + if (! userHasSpecifiedLinks()) { + for (int i = 0; i < ZT_MAX_PEER_NETWORK_PATHS; ++i) { + if (_paths[i].p && _paths[i].eligible) { + SharedPtr link = RR->bc->getLinkBySocket(_policyAlias, _paths[i].p->localSocket()); + if (link) { + log("found eligible link %s", pathToStr(_paths[i].p).c_str()); + _abPathIdx = i; + break; + } + } + } + } - /** - * [Manual mode] - * The user has specified links or failover rules that the bonding policy should adhere to. - */ - else if (userHasSpecifiedLinks()) { - if (userHasSpecifiedPrimaryLink()) { - for (int i = 0; i < ZT_MAX_PEER_NETWORK_PATHS; ++i) { - if (! _paths[i].p) { - continue; - } - SharedPtr link = RR->bc->getLinkBySocket(_policyAlias, _paths[i].p->localSocket()); - if (link) { - if (_paths[i].eligible && link->primary()) { - if (! _paths[i].preferred()) { - // Found path on primary link, take note in case we don't find a preferred path - nonPreferredPathIdx = i; - foundPathOnPrimaryLink = true; - } - if (_paths[i].preferred()) { - _abPathIdx = i; - foundPathOnPrimaryLink = true; - if (_paths[_abPathIdx].p) { - SharedPtr abLink = RR->bc->getLinkBySocket(_policyAlias, _paths[_abPathIdx].p->localSocket()); - if (abLink) { - log("found preferred primary link (_abPathIdx=%d), %s", _abPathIdx, pathToStr(_paths[_abPathIdx].p).c_str()); - foundPreferredPath = true; - } - break; // Found preferred path on primary link - } - } - } - } - } - if (!foundPreferredPath && foundPathOnPrimaryLink && (nonPreferredPathIdx != ZT_MAX_PEER_NETWORK_PATHS)) { - log("found non-preferred primary link (_abPathIdx=%d)", _abPathIdx); - _abPathIdx = nonPreferredPathIdx; - } - } + /** + * [Manual mode] + * The user has specified links or failover rules that the bonding policy should adhere to. + */ + else if (userHasSpecifiedLinks()) { + if (userHasSpecifiedPrimaryLink()) { + for (int i = 0; i < ZT_MAX_PEER_NETWORK_PATHS; ++i) { + if (! _paths[i].p) { + continue; + } + SharedPtr link = RR->bc->getLinkBySocket(_policyAlias, _paths[i].p->localSocket()); + if (link) { + if (_paths[i].eligible && link->primary()) { + if (! _paths[i].preferred()) { + // Found path on primary link, take note in case we don't find a preferred path + nonPreferredPathIdx = i; + foundPathOnPrimaryLink = true; + } + if (_paths[i].preferred()) { + _abPathIdx = i; + foundPathOnPrimaryLink = true; + if (_paths[_abPathIdx].p) { + SharedPtr abLink = RR->bc->getLinkBySocket(_policyAlias, _paths[_abPathIdx].p->localSocket()); + if (abLink) { + log("found preferred primary link (_abPathIdx=%d), %s", _abPathIdx, pathToStr(_paths[_abPathIdx].p).c_str()); + foundPreferredPath = true; + } + break; // Found preferred path on primary link + } + } + } + } + } + if (! foundPreferredPath && foundPathOnPrimaryLink && (nonPreferredPathIdx != ZT_MAX_PEER_NETWORK_PATHS)) { + log("found non-preferred primary link (_abPathIdx=%d)", _abPathIdx); + _abPathIdx = nonPreferredPathIdx; + } + } - else if (! userHasSpecifiedPrimaryLink()) { - for (int i = 0; i < ZT_MAX_PEER_NETWORK_PATHS; ++i) { - if (_paths[i].p && _paths[i].eligible) { - _abPathIdx = i; - break; - } - } - if (_abPathIdx != ZT_MAX_PEER_NETWORK_PATHS) { - if (_paths[_abPathIdx].p) { - SharedPtr link = RR->bc->getLinkBySocket(_policyAlias, _paths[_abPathIdx].p->localSocket()); - if (link) { - log("select non-primary link %s", pathToStr(_paths[_abPathIdx].p).c_str()); - } - } - } - } - } - } + else if (! userHasSpecifiedPrimaryLink()) { + for (int i = 0; i < ZT_MAX_PEER_NETWORK_PATHS; ++i) { + if (_paths[i].p && _paths[i].eligible) { + _abPathIdx = i; + break; + } + } + if (_abPathIdx != ZT_MAX_PEER_NETWORK_PATHS) { + if (_paths[_abPathIdx].p) { + SharedPtr link = RR->bc->getLinkBySocket(_policyAlias, _paths[_abPathIdx].p->localSocket()); + if (link) { + log("select non-primary link %s", pathToStr(_paths[_abPathIdx].p).c_str()); + } + } + } + } + } + } - // Short-circuit if we don't have an active link yet. Everything below is optimization from the base case - if (_abPathIdx < 0 || _abPathIdx == ZT_MAX_PEER_NETWORK_PATHS || (! _paths[_abPathIdx].p)) { - return; - } + // Short-circuit if we don't have an active link yet. Everything below is optimization from the base case + if (_abPathIdx < 0 || _abPathIdx == ZT_MAX_PEER_NETWORK_PATHS || (! _paths[_abPathIdx].p)) { + return; + } - // Remove ineligible paths from the failover link queue - for (std::deque::iterator it(_abFailoverQueue.begin()); it != _abFailoverQueue.end();) { - if (! _paths[(*it)].p) { - log("link is no longer valid, removing from failover queue (%zu links remain in queue)", _abFailoverQueue.size()); - it = _abFailoverQueue.erase(it); - continue; - } - if (_paths[(*it)].p && ! _paths[(*it)].eligible) { - SharedPtr link = RR->bc->getLinkBySocket(_policyAlias, _paths[(*it)].p->localSocket()); - if (link) { - log("link %s is ineligible, removing from failover queue (%zu links remain in queue)", pathToStr(_paths[(*it)].p).c_str(), _abFailoverQueue.size()); - } - it = _abFailoverQueue.erase(it); - continue; - } - else { - ++it; - } - } - /** - * Failover instructions were provided by user, build queue according those as well as IPv - * preference, disregarding performance. - */ - if (userHasSpecifiedFailoverInstructions()) { - /** - * Clear failover scores - */ - for (int i = 0; i < ZT_MAX_PEER_NETWORK_PATHS; ++i) { - if (_paths[i].p) { - _paths[i].failoverScore = 0; - } - } - // Follow user-specified failover instructions - for (int i = 0; i < ZT_MAX_PEER_NETWORK_PATHS; ++i) { - if (! _paths[i].p || ! _paths[i].allowed() || ! _paths[i].eligible) { - continue; - } - SharedPtr link = RR->bc->getLinkBySocket(_policyAlias, _paths[i].p->localSocket()); - if (! link) { - continue; - } - int failoverScoreHandicap = _paths[i].failoverScore; - if (_paths[i].preferred()) { - failoverScoreHandicap += ZT_BOND_FAILOVER_HANDICAP_PREFERRED; - } - if (link->primary()) { - // If using "optimize" primary re-select mode, ignore user link designations - failoverScoreHandicap += ZT_BOND_FAILOVER_HANDICAP_PRIMARY; - } - if (! _paths[i].failoverScore) { - // If we didn't inherit a failover score from a "parent" that wants to use this path as a failover - int newHandicap = failoverScoreHandicap ? failoverScoreHandicap : (_paths[i].relativeQuality * 255.0); - _paths[i].failoverScore = newHandicap; - } - SharedPtr failoverLink; - if (link->failoverToLink().length()) { - failoverLink = RR->bc->getLinkByName(_policyAlias, link->failoverToLink()); - } - if (failoverLink) { - for (int j = 0; j < ZT_MAX_PEER_NETWORK_PATHS; j++) { - if (_paths[j].p && getLink(_paths[j].p) == failoverLink.ptr()) { - int inheritedHandicap = failoverScoreHandicap - 10; - int newHandicap = _paths[j].failoverScore > inheritedHandicap ? _paths[j].failoverScore : inheritedHandicap; - if (! _paths[j].preferred()) { - newHandicap--; - } - _paths[j].failoverScore = newHandicap; - } - } - } - if (_paths[i].p) { - if (_paths[i].p.ptr() != _paths[_abPathIdx].p.ptr()) { - bool bFoundPathInQueue = false; - for (std::deque::iterator it(_abFailoverQueue.begin()); it != _abFailoverQueue.end(); ++it) { - if (_paths[(*it)].p && (_paths[i].p.ptr() == _paths[(*it)].p.ptr())) { - bFoundPathInQueue = true; - } - } - if (! bFoundPathInQueue) { - _abFailoverQueue.push_back(i); - log("add link %s to failover queue (%zu links in queue)", pathToStr(_paths[i].p).c_str(), _abFailoverQueue.size()); - addPathToBond(i, 0); - } - } - } - } - } - /** - * No failover instructions provided by user, build queue according to performance - * and IPv preference. - */ - else if (! userHasSpecifiedFailoverInstructions()) { - for (int i = 0; i < ZT_MAX_PEER_NETWORK_PATHS; ++i) { - if (! _paths[i].p || ! _paths[i].allowed() || ! _paths[i].eligible) { - continue; - } - int failoverScoreHandicap = 0; - if (_paths[i].preferred()) { - failoverScoreHandicap = ZT_BOND_FAILOVER_HANDICAP_PREFERRED; - } - if (! _paths[i].eligible) { - failoverScoreHandicap = -10000; - } - SharedPtr link = getLink(_paths[i].p); - if (! link) { - continue; - } - if (link->primary() && _abLinkSelectMethod != ZT_BOND_RESELECTION_POLICY_OPTIMIZE) { - // If using "optimize" primary re-select mode, ignore user link designations - failoverScoreHandicap = ZT_BOND_FAILOVER_HANDICAP_PRIMARY; - } - /* - if (_paths[i].p.ptr() == _paths[_negotiatedPathIdx].p.ptr()) { - _paths[i].negotiated = true; - failoverScoreHandicap = ZT_BOND_FAILOVER_HANDICAP_NEGOTIATED; - } - else { - _paths[i].negotiated = false; - } - */ - _paths[i].failoverScore = _paths[i].relativeQuality + failoverScoreHandicap; - if (_paths[i].p.ptr() != _paths[_abPathIdx].p.ptr()) { - bool bFoundPathInQueue = false; - for (std::deque::iterator it(_abFailoverQueue.begin()); it != _abFailoverQueue.end(); ++it) { - if (_paths[i].p.ptr() == _paths[(*it)].p.ptr()) { - bFoundPathInQueue = true; - } - } - if (! bFoundPathInQueue) { - _abFailoverQueue.push_back(i); - log("add link %s to failover queue (%zu links in queue)", pathToStr(_paths[i].p).c_str(), _abFailoverQueue.size()); - addPathToBond(i, 0); - } - } - } - } - /* - // Sort queue based on performance - if (! _abFailoverQueue.empty()) { - for (int i = 0; i < _abFailoverQueue.size(); i++) { - int value_to_insert = _abFailoverQueue[i]; - int hole_position = i; - while (hole_position > 0 && (_abFailoverQueue[hole_position - 1] > value_to_insert)) { - _abFailoverQueue[hole_position] = _abFailoverQueue[hole_position - 1]; - hole_position = hole_position - 1; - } - _abFailoverQueue[hole_position] = value_to_insert; - } - }*/ + // Remove ineligible paths from the failover link queue + for (std::deque::iterator it(_abFailoverQueue.begin()); it != _abFailoverQueue.end();) { + if (! _paths[(*it)].p) { + log("link is no longer valid, removing from failover queue (%zu links remain in queue)", _abFailoverQueue.size()); + it = _abFailoverQueue.erase(it); + continue; + } + if (_paths[(*it)].p && ! _paths[(*it)].eligible) { + SharedPtr link = RR->bc->getLinkBySocket(_policyAlias, _paths[(*it)].p->localSocket()); + if (link) { + log("link %s is ineligible, removing from failover queue (%zu links remain in queue)", pathToStr(_paths[(*it)].p).c_str(), _abFailoverQueue.size()); + } + it = _abFailoverQueue.erase(it); + continue; + } + else { + ++it; + } + } + /** + * Failover instructions were provided by user, build queue according those as well as IPv + * preference, disregarding performance. + */ + if (userHasSpecifiedFailoverInstructions()) { + /** + * Clear failover scores + */ + for (int i = 0; i < ZT_MAX_PEER_NETWORK_PATHS; ++i) { + if (_paths[i].p) { + _paths[i].failoverScore = 0; + } + } + // Follow user-specified failover instructions + for (int i = 0; i < ZT_MAX_PEER_NETWORK_PATHS; ++i) { + if (! _paths[i].p || ! _paths[i].allowed() || ! _paths[i].eligible) { + continue; + } + SharedPtr link = RR->bc->getLinkBySocket(_policyAlias, _paths[i].p->localSocket()); + if (! link) { + continue; + } + int failoverScoreHandicap = _paths[i].failoverScore; + if (_paths[i].preferred()) { + failoverScoreHandicap += ZT_BOND_FAILOVER_HANDICAP_PREFERRED; + } + if (link->primary()) { + // If using "optimize" primary re-select mode, ignore user link designations + failoverScoreHandicap += ZT_BOND_FAILOVER_HANDICAP_PRIMARY; + } + if (! _paths[i].failoverScore) { + // If we didn't inherit a failover score from a "parent" that wants to use this path as a failover + int newHandicap = failoverScoreHandicap ? failoverScoreHandicap : (_paths[i].relativeQuality * 255.0); + _paths[i].failoverScore = newHandicap; + } + SharedPtr failoverLink; + if (link->failoverToLink().length()) { + failoverLink = RR->bc->getLinkByName(_policyAlias, link->failoverToLink()); + } + if (failoverLink) { + for (int j = 0; j < ZT_MAX_PEER_NETWORK_PATHS; j++) { + if (_paths[j].p && getLink(_paths[j].p) == failoverLink.ptr()) { + int inheritedHandicap = failoverScoreHandicap - 10; + int newHandicap = _paths[j].failoverScore > inheritedHandicap ? _paths[j].failoverScore : inheritedHandicap; + if (! _paths[j].preferred()) { + newHandicap--; + } + _paths[j].failoverScore = newHandicap; + } + } + } + if (_paths[i].p) { + if (_paths[i].p.ptr() != _paths[_abPathIdx].p.ptr()) { + bool bFoundPathInQueue = false; + for (std::deque::iterator it(_abFailoverQueue.begin()); it != _abFailoverQueue.end(); ++it) { + if (_paths[(*it)].p && (_paths[i].p.ptr() == _paths[(*it)].p.ptr())) { + bFoundPathInQueue = true; + } + } + if (! bFoundPathInQueue) { + _abFailoverQueue.push_back(i); + log("add link %s to failover queue (%zu links in queue)", pathToStr(_paths[i].p).c_str(), _abFailoverQueue.size()); + addPathToBond(i, 0); + } + } + } + } + } + /** + * No failover instructions provided by user, build queue according to performance + * and IPv preference. + */ + else if (! userHasSpecifiedFailoverInstructions()) { + for (int i = 0; i < ZT_MAX_PEER_NETWORK_PATHS; ++i) { + if (! _paths[i].p || ! _paths[i].allowed() || ! _paths[i].eligible) { + continue; + } + int failoverScoreHandicap = 0; + if (_paths[i].preferred()) { + failoverScoreHandicap = ZT_BOND_FAILOVER_HANDICAP_PREFERRED; + } + if (! _paths[i].eligible) { + failoverScoreHandicap = -10000; + } + SharedPtr link = getLink(_paths[i].p); + if (! link) { + continue; + } + if (link->primary() && _abLinkSelectMethod != ZT_BOND_RESELECTION_POLICY_OPTIMIZE) { + // If using "optimize" primary re-select mode, ignore user link designations + failoverScoreHandicap = ZT_BOND_FAILOVER_HANDICAP_PRIMARY; + } + /* + if (_paths[i].p.ptr() == _paths[_negotiatedPathIdx].p.ptr()) { + _paths[i].negotiated = true; + failoverScoreHandicap = ZT_BOND_FAILOVER_HANDICAP_NEGOTIATED; + } + else { + _paths[i].negotiated = false; + } + */ + _paths[i].failoverScore = _paths[i].relativeQuality + failoverScoreHandicap; + if (_paths[i].p.ptr() != _paths[_abPathIdx].p.ptr()) { + bool bFoundPathInQueue = false; + for (std::deque::iterator it(_abFailoverQueue.begin()); it != _abFailoverQueue.end(); ++it) { + if (_paths[i].p.ptr() == _paths[(*it)].p.ptr()) { + bFoundPathInQueue = true; + } + } + if (! bFoundPathInQueue) { + _abFailoverQueue.push_back(i); + log("add link %s to failover queue (%zu links in queue)", pathToStr(_paths[i].p).c_str(), _abFailoverQueue.size()); + addPathToBond(i, 0); + } + } + } + } + /* + // Sort queue based on performance + if (! _abFailoverQueue.empty()) { + for (int i = 0; i < _abFailoverQueue.size(); i++) { + int value_to_insert = _abFailoverQueue[i]; + int hole_position = i; + while (hole_position > 0 && (_abFailoverQueue[hole_position - 1] > value_to_insert)) { + _abFailoverQueue[hole_position] = _abFailoverQueue[hole_position - 1]; + hole_position = hole_position - 1; + } + _abFailoverQueue[hole_position] = value_to_insert; + } + }*/ - /** - * Short-circuit if we have no queued paths - */ - if (_abFailoverQueue.empty()) { - return; - } + /** + * Short-circuit if we have no queued paths + */ + if (_abFailoverQueue.empty()) { + return; + } - /** - * Fulfill primary re-select obligations - */ - if (! _paths[_abPathIdx].eligible) { // Implicit ZT_BOND_RESELECTION_POLICY_FAILURE - log("link %s has failed, select link from failover queue (%zu links in queue)", pathToStr(_paths[_abPathIdx].p).c_str(), _abFailoverQueue.size()); - if (! _abFailoverQueue.empty()) { - dequeueNextActiveBackupPath(now); - log("active link switched to %s", pathToStr(_paths[_abPathIdx].p).c_str()); - } - else { - log("failover queue is empty, no links to choose from"); - } - } - /** - * Detect change to prevent flopping during later optimization step. - */ - if (prevActiveBackupPathIdx != _abPathIdx) { - _lastActiveBackupPathChange = now; - } - if (_abFailoverQueue.empty()) { - return; // No sense in continuing since there are no links to switch to - } + /** + * Fulfill primary re-select obligations + */ + if (! _paths[_abPathIdx].eligible) { // Implicit ZT_BOND_RESELECTION_POLICY_FAILURE + log("link %s has failed, select link from failover queue (%zu links in queue)", pathToStr(_paths[_abPathIdx].p).c_str(), _abFailoverQueue.size()); + if (! _abFailoverQueue.empty()) { + dequeueNextActiveBackupPath(now); + log("active link switched to %s", pathToStr(_paths[_abPathIdx].p).c_str()); + } + else { + log("failover queue is empty, no links to choose from"); + } + } + /** + * Detect change to prevent flopping during later optimization step. + */ + if (prevActiveBackupPathIdx != _abPathIdx) { + _lastActiveBackupPathChange = now; + } + if (_abFailoverQueue.empty()) { + return; // No sense in continuing since there are no links to switch to + } - if (_abLinkSelectMethod == ZT_BOND_RESELECTION_POLICY_ALWAYS) { - SharedPtr abLink = getLink(_paths[_abPathIdx].p); - if (! _paths[_abFailoverQueue.front()].p) { - log("invalid link. not switching"); - return; - } + if (_abLinkSelectMethod == ZT_BOND_RESELECTION_POLICY_ALWAYS) { + SharedPtr abLink = getLink(_paths[_abPathIdx].p); + if (! _paths[_abFailoverQueue.front()].p) { + log("invalid link. not switching"); + return; + } - SharedPtr abFailoverLink = getLink(_paths[_abFailoverQueue.front()].p); - if (abLink && ! abLink->primary() && _paths[_abFailoverQueue.front()].p && abFailoverLink && abFailoverLink->primary()) { - dequeueNextActiveBackupPath(now); - log("switch back to available primary link %s (select mode: always)", pathToStr(_paths[_abPathIdx].p).c_str()); - } - } - if (_abLinkSelectMethod == ZT_BOND_RESELECTION_POLICY_BETTER) { - SharedPtr abLink = getLink(_paths[_abPathIdx].p); - if (abLink && ! abLink->primary()) { - // Active backup has switched to "better" primary link according to re-select policy. - SharedPtr abFailoverLink = getLink(_paths[_abFailoverQueue.front()].p); - if (_paths[_abFailoverQueue.front()].p && abFailoverLink && abFailoverLink->primary() && (_paths[_abFailoverQueue.front()].failoverScore > _paths[_abPathIdx].failoverScore)) { - dequeueNextActiveBackupPath(now); - log("switch back to user-defined primary link %s (select mode: better)", pathToStr(_paths[_abPathIdx].p).c_str()); - } - } - } - if (_abLinkSelectMethod == ZT_BOND_RESELECTION_POLICY_OPTIMIZE && ! _abFailoverQueue.empty()) { - /** - * Implement link negotiation that was previously-decided - */ - if (_paths[_abFailoverQueue.front()].negotiated) { - dequeueNextActiveBackupPath(now); - _lastPathNegotiationCheck = now; - log("switch negotiated link %s (select mode: optimize)", pathToStr(_paths[_abPathIdx].p).c_str()); - } - else { - // Try to find a better path and automatically switch to it -- not too often, though. - if ((now - _lastActiveBackupPathChange) > ZT_BOND_OPTIMIZE_INTERVAL) { - if (! _abFailoverQueue.empty()) { - int newFScore = _paths[_abFailoverQueue.front()].failoverScore; - int prevFScore = _paths[_abPathIdx].failoverScore; - // Establish a minimum switch threshold to prevent flapping - int failoverScoreDifference = _paths[_abFailoverQueue.front()].failoverScore - _paths[_abPathIdx].failoverScore; - int thresholdQuantity = (int)(ZT_BOND_ACTIVE_BACKUP_OPTIMIZE_MIN_THRESHOLD * (float)_paths[_abPathIdx].relativeQuality); - if ((failoverScoreDifference > 0) && (failoverScoreDifference > thresholdQuantity)) { - SharedPtr oldPath = _paths[_abPathIdx].p; - dequeueNextActiveBackupPath(now); - log("switch from %s (score: %d) to better link %s (score: %d) (select mode: optimize)", pathToStr(oldPath).c_str(), prevFScore, pathToStr(_paths[_abPathIdx].p).c_str(), newFScore); - } - } - } - } - } + SharedPtr abFailoverLink = getLink(_paths[_abFailoverQueue.front()].p); + if (abLink && ! abLink->primary() && _paths[_abFailoverQueue.front()].p && abFailoverLink && abFailoverLink->primary()) { + dequeueNextActiveBackupPath(now); + log("switch back to available primary link %s (select mode: always)", pathToStr(_paths[_abPathIdx].p).c_str()); + } + } + if (_abLinkSelectMethod == ZT_BOND_RESELECTION_POLICY_BETTER) { + SharedPtr abLink = getLink(_paths[_abPathIdx].p); + if (abLink && ! abLink->primary()) { + // Active backup has switched to "better" primary link according to re-select policy. + SharedPtr abFailoverLink = getLink(_paths[_abFailoverQueue.front()].p); + if (_paths[_abFailoverQueue.front()].p && abFailoverLink && abFailoverLink->primary() && (_paths[_abFailoverQueue.front()].failoverScore > _paths[_abPathIdx].failoverScore)) { + dequeueNextActiveBackupPath(now); + log("switch back to user-defined primary link %s (select mode: better)", pathToStr(_paths[_abPathIdx].p).c_str()); + } + } + } + if (_abLinkSelectMethod == ZT_BOND_RESELECTION_POLICY_OPTIMIZE && ! _abFailoverQueue.empty()) { + /** + * Implement link negotiation that was previously-decided + */ + if (_paths[_abFailoverQueue.front()].negotiated) { + dequeueNextActiveBackupPath(now); + _lastPathNegotiationCheck = now; + log("switch negotiated link %s (select mode: optimize)", pathToStr(_paths[_abPathIdx].p).c_str()); + } + else { + // Try to find a better path and automatically switch to it -- not too often, though. + if ((now - _lastActiveBackupPathChange) > ZT_BOND_OPTIMIZE_INTERVAL) { + if (! _abFailoverQueue.empty()) { + int newFScore = _paths[_abFailoverQueue.front()].failoverScore; + int prevFScore = _paths[_abPathIdx].failoverScore; + // Establish a minimum switch threshold to prevent flapping + int failoverScoreDifference = _paths[_abFailoverQueue.front()].failoverScore - _paths[_abPathIdx].failoverScore; + int thresholdQuantity = (int)(ZT_BOND_ACTIVE_BACKUP_OPTIMIZE_MIN_THRESHOLD * (float)_paths[_abPathIdx].relativeQuality); + if ((failoverScoreDifference > 0) && (failoverScoreDifference > thresholdQuantity)) { + SharedPtr oldPath = _paths[_abPathIdx].p; + dequeueNextActiveBackupPath(now); + log("switch from %s (score: %d) to better link %s (score: %d) (select mode: optimize)", pathToStr(oldPath).c_str(), prevFScore, pathToStr(_paths[_abPathIdx].p).c_str(), newFScore); + } + } + } + } + } } void Bond::initTimers() { - _lastFlowExpirationCheck = 0; - _lastFlowRebalance = 0; - _lastSentPathNegotiationRequest = 0; - _lastPathNegotiationCheck = 0; - _lastPathNegotiationReceived = 0; - _lastQoSRateCheck = 0; - _lastAckRateCheck = 0; - _lastQualityEstimation = 0; - _lastBondStatusLog = 0; - _lastSummaryDump = 0; - _lastActiveBackupPathChange = 0; - _lastFrame = 0; - _lastBackgroundTaskCheck = 0; + _lastFlowExpirationCheck = 0; + _lastFlowRebalance = 0; + _lastSentPathNegotiationRequest = 0; + _lastPathNegotiationCheck = 0; + _lastPathNegotiationReceived = 0; + _lastQoSRateCheck = 0; + _lastAckRateCheck = 0; + _lastQualityEstimation = 0; + _lastBondStatusLog = 0; + _lastSummaryDump = 0; + _lastActiveBackupPathChange = 0; + _lastFrame = 0; + _lastBackgroundTaskCheck = 0; } void Bond::setBondParameters(int policy, SharedPtr templateBond, bool useTemplate) { - // Sanity check for policy + // Sanity check for policy - _defaultPolicy = (_defaultPolicy <= ZT_BOND_POLICY_NONE || _defaultPolicy > ZT_BOND_POLICY_BALANCE_AWARE) ? ZT_BOND_POLICY_NONE : _defaultPolicy; - _policy = (policy <= ZT_BOND_POLICY_NONE || policy > ZT_BOND_POLICY_BALANCE_AWARE) ? _defaultPolicy : policy; + _defaultPolicy = (_defaultPolicy <= ZT_BOND_POLICY_NONE || _defaultPolicy > ZT_BOND_POLICY_BALANCE_AWARE) ? ZT_BOND_POLICY_NONE : _defaultPolicy; + _policy = (policy <= ZT_BOND_POLICY_NONE || policy > ZT_BOND_POLICY_BALANCE_AWARE) ? _defaultPolicy : policy; - // Check if non-leaf to prevent spamming infrastructure - ZT_PeerRole role; - if (_peer) { - role = RR->topology->role(_peer->address()); - } - _isLeaf = _peer ? (role != ZT_PEER_ROLE_PLANET && role != ZT_PEER_ROLE_MOON) : false; + // Check if non-leaf to prevent spamming infrastructure + ZT_PeerRole role; + if (_peer) { + role = RR->topology->role(_peer->address()); + } + _isLeaf = _peer ? (role != ZT_PEER_ROLE_PLANET && role != ZT_PEER_ROLE_MOON) : false; - // Path negotiation + // Path negotiation - _allowPathNegotiation = false; - _pathNegotiationCutoffCount = 0; - _localUtility = 0; - _negotiatedPathIdx = 0; + _allowPathNegotiation = false; + _pathNegotiationCutoffCount = 0; + _localUtility = 0; + _negotiatedPathIdx = 0; - // User preferences which may override the default bonding algorithm's behavior + // User preferences which may override the default bonding algorithm's behavior - _userHasSpecifiedPrimaryLink = false; - _userHasSpecifiedFailoverInstructions = false; - _userHasSpecifiedLinkCapacities = 0; + _userHasSpecifiedPrimaryLink = false; + _userHasSpecifiedFailoverInstructions = false; + _userHasSpecifiedLinkCapacities = 0; - // Bond status + // Bond status - _numAliveLinks = 0; - _numTotalLinks = 0; - _numBondedPaths = 0; + _numAliveLinks = 0; + _numTotalLinks = 0; + _numBondedPaths = 0; - // General parameters + // General parameters - _downDelay = 0; - _upDelay = 0; - _monitorInterval = 0; + _downDelay = 0; + _upDelay = 0; + _monitorInterval = 0; - // balance-aware + // balance-aware - _totalBondUnderload = 0; - _overheadBytes = 0; + _totalBondUnderload = 0; + _overheadBytes = 0; - /** - * Policy defaults - */ - _abPathIdx = ZT_MAX_PEER_NETWORK_PATHS; - _abLinkSelectMethod = ZT_BOND_RESELECTION_POLICY_ALWAYS; - _rrPacketsSentOnCurrLink = 0; - _rrIdx = 0; - _packetsPerLink = 64; + /** + * Policy defaults + */ + _abPathIdx = ZT_MAX_PEER_NETWORK_PATHS; + _abLinkSelectMethod = ZT_BOND_RESELECTION_POLICY_ALWAYS; + _rrPacketsSentOnCurrLink = 0; + _rrIdx = 0; + _packetsPerLink = 64; - // Sane quality defaults + // Sane quality defaults - _qw[ZT_QOS_LAT_MAX_IDX] = 500.0f; - _qw[ZT_QOS_PDV_MAX_IDX] = 100.0f; - _qw[ZT_QOS_PLR_MAX_IDX] = 0.001f; - _qw[ZT_QOS_PER_MAX_IDX] = 0.0001f; - _qw[ZT_QOS_LAT_WEIGHT_IDX] = 0.25f; - _qw[ZT_QOS_PDV_WEIGHT_IDX] = 0.25f; - _qw[ZT_QOS_PLR_WEIGHT_IDX] = 0.25f; - _qw[ZT_QOS_PER_WEIGHT_IDX] = 0.25f; + _qw[ZT_QOS_LAT_MAX_IDX] = 500.0f; + _qw[ZT_QOS_PDV_MAX_IDX] = 100.0f; + _qw[ZT_QOS_PLR_MAX_IDX] = 0.001f; + _qw[ZT_QOS_PER_MAX_IDX] = 0.0001f; + _qw[ZT_QOS_LAT_WEIGHT_IDX] = 0.25f; + _qw[ZT_QOS_PDV_WEIGHT_IDX] = 0.25f; + _qw[ZT_QOS_PLR_WEIGHT_IDX] = 0.25f; + _qw[ZT_QOS_PER_WEIGHT_IDX] = 0.25f; - _failoverInterval = ZT_BOND_FAILOVER_DEFAULT_INTERVAL; + _failoverInterval = ZT_BOND_FAILOVER_DEFAULT_INTERVAL; - /* If a user has specified custom parameters for this bonding policy, overlay them onto the defaults */ - if (useTemplate) { - _policyAlias = templateBond->_policyAlias; - _policy = templateBond->policy(); - _failoverInterval = templateBond->_failoverInterval >= ZT_BOND_FAILOVER_MIN_INTERVAL ? templateBond->_failoverInterval : ZT_BOND_FAILOVER_MIN_INTERVAL; - _downDelay = templateBond->_downDelay; - _upDelay = templateBond->_upDelay; - _abLinkSelectMethod = templateBond->_abLinkSelectMethod; - memcpy(_qw, templateBond->_qw, ZT_QOS_PARAMETER_SIZE * sizeof(float)); - debug("user link quality spec = {%6.3f, %6.3f, %6.3f, %6.3f, %6.3f, %6.3f, %6.3f, %6.3f}", _qw[0], _qw[1], _qw[2], _qw[3], _qw[4], _qw[5], _qw[6], _qw[7]); - } + /* If a user has specified custom parameters for this bonding policy, overlay them onto the defaults */ + if (useTemplate) { + _policyAlias = templateBond->_policyAlias; + _policy = templateBond->policy(); + _failoverInterval = templateBond->_failoverInterval >= ZT_BOND_FAILOVER_MIN_INTERVAL ? templateBond->_failoverInterval : ZT_BOND_FAILOVER_MIN_INTERVAL; + _downDelay = templateBond->_downDelay; + _upDelay = templateBond->_upDelay; + _abLinkSelectMethod = templateBond->_abLinkSelectMethod; + memcpy(_qw, templateBond->_qw, ZT_QOS_PARAMETER_SIZE * sizeof(float)); + debug("user link quality spec = {%6.3f, %6.3f, %6.3f, %6.3f, %6.3f, %6.3f, %6.3f, %6.3f}", _qw[0], _qw[1], _qw[2], _qw[3], _qw[4], _qw[5], _qw[6], _qw[7]); + } - if (! _isLeaf) { - _policy = ZT_BOND_POLICY_NONE; - } + if (! _isLeaf) { + _policy = ZT_BOND_POLICY_NONE; + } - // Timer geometry + // Timer geometry - _monitorInterval = _failoverInterval / ZT_BOND_ECHOS_PER_FAILOVER_INTERVAL; - _qualityEstimationInterval = _failoverInterval * 2; - _qosSendInterval = _failoverInterval * 2; - _ackSendInterval = _failoverInterval * 2; - _qosCutoffCount = 0; - _ackCutoffCount = 0; - _defaultPathRefractoryPeriod = 8000; + _monitorInterval = _failoverInterval / ZT_BOND_ECHOS_PER_FAILOVER_INTERVAL; + _qualityEstimationInterval = _failoverInterval * 2; + _qosSendInterval = _failoverInterval * 2; + _ackSendInterval = _failoverInterval * 2; + _qosCutoffCount = 0; + _ackCutoffCount = 0; + _defaultPathRefractoryPeriod = 8000; } void Bond::setUserLinkQualitySpec(float weights[], int len) { - if (len != ZT_QOS_PARAMETER_SIZE) { - debug("link quality spec has an invalid number of parameters (%d out of %d), ignoring", len, ZT_QOS_PARAMETER_SIZE); - return; - } - float weightTotal = 0.0; - for (unsigned int i = 4; i < ZT_QOS_PARAMETER_SIZE; ++i) { - weightTotal += weights[i]; - } - if (weightTotal > 0.99 && weightTotal < 1.01) { - memcpy(_qw, weights, len * sizeof(float)); - } + if (len != ZT_QOS_PARAMETER_SIZE) { + debug("link quality spec has an invalid number of parameters (%d out of %d), ignoring", len, ZT_QOS_PARAMETER_SIZE); + return; + } + float weightTotal = 0.0; + for (unsigned int i = 4; i < ZT_QOS_PARAMETER_SIZE; ++i) { + weightTotal += weights[i]; + } + if (weightTotal > 0.99 && weightTotal < 1.01) { + memcpy(_qw, weights, len * sizeof(float)); + } } SharedPtr Bond::getLink(const SharedPtr& path) { - return ! path ? SharedPtr() : RR->bc->getLinkBySocket(_policyAlias, path->localSocket()); + return ! path ? SharedPtr() : RR->bc->getLinkBySocket(_policyAlias, path->localSocket()); } std::string Bond::pathToStr(const SharedPtr& path) { #ifdef ZT_TRACE - if (path) { - char pathStr[64] = { 0 }; - char fullPathStr[384] = { 0 }; - path->address().toString(pathStr); - SharedPtr link = getLink(path); - if (link) { - std::string ifnameStr = std::string(link->ifname()); - snprintf(fullPathStr, 384, "%.16" PRIx64 "-%s/%s", path->localSocket(), ifnameStr.c_str(), pathStr); - return std::string(fullPathStr); - } - } - return ""; + if (path) { + char pathStr[64] = { 0 }; + char fullPathStr[384] = { 0 }; + path->address().toString(pathStr); + SharedPtr link = getLink(path); + if (link) { + std::string ifnameStr = std::string(link->ifname()); + snprintf(fullPathStr, 384, "%.16" PRIx64 "-%s/%s", path->localSocket(), ifnameStr.c_str(), pathStr); + return std::string(fullPathStr); + } + } + return ""; #else - return ""; + return ""; #endif } void Bond::dumpPathStatus(int64_t now, int pathIdx) { #ifdef ZT_TRACE - std::string aliveOrDead = _paths[pathIdx].alive ? std::string("alive") : std::string("dead"); - std::string eligibleOrNot = _paths[pathIdx].eligible ? std::string("eligible") : std::string("ineligible"); - std::string bondedOrNot = _paths[pathIdx].bonded ? std::string("bonded") : std::string("unbonded"); - log("path[%2u] --- %5s (in %7" PRId64 ", out: %7" PRId64 "), %10s, %8s, flows=%-6u lat=%-8.3f pdv=%-7.3f err=%-6.4f loss=%-6.4f qual=%-6.4f --- (%s) spare=%d", - pathIdx, - aliveOrDead.c_str(), - _paths[pathIdx].p->age(now), - _paths[pathIdx].p->_lastOut == 0 ? static_cast(0) : now - _paths[pathIdx].p->_lastOut, - eligibleOrNot.c_str(), - bondedOrNot.c_str(), - _paths[pathIdx].assignedFlowCount, - _paths[pathIdx].latency, - _paths[pathIdx].latencyVariance, - _paths[pathIdx].packetErrorRatio, - _paths[pathIdx].packetLossRatio, - _paths[pathIdx].relativeQuality, - pathToStr(_paths[pathIdx].p).c_str(), - _paths[pathIdx].isSpare()); + std::string aliveOrDead = _paths[pathIdx].alive ? std::string("alive") : std::string("dead"); + std::string eligibleOrNot = _paths[pathIdx].eligible ? std::string("eligible") : std::string("ineligible"); + std::string bondedOrNot = _paths[pathIdx].bonded ? std::string("bonded") : std::string("unbonded"); + log("path[%2u] --- %5s (in %7" PRId64 ", out: %7" PRId64 "), %10s, %8s, flows=%-6u lat=%-8.3f pdv=%-7.3f err=%-6.4f loss=%-6.4f qual=%-6.4f --- (%s) spare=%d", + pathIdx, + aliveOrDead.c_str(), + _paths[pathIdx].p->age(now), + _paths[pathIdx].p->_lastOut == 0 ? static_cast(0) : now - _paths[pathIdx].p->_lastOut, + eligibleOrNot.c_str(), + bondedOrNot.c_str(), + _paths[pathIdx].assignedFlowCount, + _paths[pathIdx].latency, + _paths[pathIdx].latencyVariance, + _paths[pathIdx].packetErrorRatio, + _paths[pathIdx].packetLossRatio, + _paths[pathIdx].relativeQuality, + pathToStr(_paths[pathIdx].p).c_str(), + _paths[pathIdx].isSpare()); #endif } void Bond::dumpInfo(int64_t now, bool force) { #ifdef ZT_TRACE - uint64_t timeSinceLastDump = now - _lastSummaryDump; - if (! force && timeSinceLastDump < ZT_BOND_STATUS_INTERVAL) { - return; - } - _lastSummaryDump = now; - float overhead = (_overheadBytes / (timeSinceLastDump / 1000.0f) / 1000.0f); - _overheadBytes = 0; - log("bond: ready=%d, bp=%d, fi=%" PRIu64 ", mi=%d, ud=%d, dd=%d, flows=%zu, leaf=%d, overhead=%f KB/s, links=(%d/%d)", - isReady(), - _policy, - _failoverInterval, - _monitorInterval, - _upDelay, - _downDelay, - _flows.size(), - _isLeaf, - overhead, - _numAliveLinks, - _numTotalLinks); - for (int i = 0; i < ZT_MAX_PEER_NETWORK_PATHS; ++i) { - if (_paths[i].p) { - dumpPathStatus(now, i); - } - } - log(""); + uint64_t timeSinceLastDump = now - _lastSummaryDump; + if (! force && timeSinceLastDump < ZT_BOND_STATUS_INTERVAL) { + return; + } + _lastSummaryDump = now; + float overhead = (_overheadBytes / (timeSinceLastDump / 1000.0f) / 1000.0f); + _overheadBytes = 0; + log("bond: ready=%d, bp=%d, fi=%" PRIu64 ", mi=%d, ud=%d, dd=%d, flows=%zu, leaf=%d, overhead=%f KB/s, links=(%d/%d)", + isReady(), + _policy, + _failoverInterval, + _monitorInterval, + _upDelay, + _downDelay, + _flows.size(), + _isLeaf, + overhead, + _numAliveLinks, + _numTotalLinks); + for (int i = 0; i < ZT_MAX_PEER_NETWORK_PATHS; ++i) { + if (_paths[i].p) { + dumpPathStatus(now, i); + } + } + log(""); #endif } -} // namespace ZeroTier +} // namespace ZeroTier diff --git a/node/Bond.hpp b/node/Bond.hpp index d5d3f673..f604002b 100644 --- a/node/Bond.hpp +++ b/node/Bond.hpp @@ -35,66 +35,66 @@ enum ZT_BondQualityWeightIndex { ZT_QOS_LAT_MAX_IDX, ZT_QOS_PDV_MAX_IDX, ZT_QOS_ * Multipath bonding policy */ enum ZT_BondBondingPolicy { - /** - * Normal operation. No fault tolerance, no load balancing - */ - ZT_BOND_POLICY_NONE = 0, + /** + * Normal operation. No fault tolerance, no load balancing + */ + ZT_BOND_POLICY_NONE = 0, - /** - * Sends traffic out on only one path at a time. Configurable immediate - * fail-over. - */ - ZT_BOND_POLICY_ACTIVE_BACKUP = 1, + /** + * Sends traffic out on only one path at a time. Configurable immediate + * fail-over. + */ + ZT_BOND_POLICY_ACTIVE_BACKUP = 1, - /** - * Sends traffic out on all paths - */ - ZT_BOND_POLICY_BROADCAST = 2, + /** + * Sends traffic out on all paths + */ + ZT_BOND_POLICY_BROADCAST = 2, - /** - * Stripes packets across all paths - */ - ZT_BOND_POLICY_BALANCE_RR = 3, + /** + * Stripes packets across all paths + */ + ZT_BOND_POLICY_BALANCE_RR = 3, - /** - * Packets destined for specific peers will always be sent over the same - * path. - */ - ZT_BOND_POLICY_BALANCE_XOR = 4, + /** + * Packets destined for specific peers will always be sent over the same + * path. + */ + ZT_BOND_POLICY_BALANCE_XOR = 4, - /** - * Balances flows among all paths according to path performance - */ - ZT_BOND_POLICY_BALANCE_AWARE = 5 + /** + * Balances flows among all paths according to path performance + */ + ZT_BOND_POLICY_BALANCE_AWARE = 5 }; /** * Multipath active re-selection policy (linkSelectMethod) */ enum ZT_BondLinkSelectMethod { - /** - * Primary link regains status as active link whenever it comes back up - * (default when links are explicitly specified) - */ - ZT_BOND_RESELECTION_POLICY_ALWAYS = 0, + /** + * Primary link regains status as active link whenever it comes back up + * (default when links are explicitly specified) + */ + ZT_BOND_RESELECTION_POLICY_ALWAYS = 0, - /** - * Primary link regains status as active link when it comes back up and - * (if) it is better than the currently-active link. - */ - ZT_BOND_RESELECTION_POLICY_BETTER = 1, + /** + * Primary link regains status as active link when it comes back up and + * (if) it is better than the currently-active link. + */ + ZT_BOND_RESELECTION_POLICY_BETTER = 1, - /** - * Primary link regains status as active link only if the currently-active - * link fails. - */ - ZT_BOND_RESELECTION_POLICY_FAILURE = 2, + /** + * Primary link regains status as active link only if the currently-active + * link fails. + */ + ZT_BOND_RESELECTION_POLICY_FAILURE = 2, - /** - * The primary link can change if a superior path is detected. - * (default if user provides no fail-over guidance) - */ - ZT_BOND_RESELECTION_POLICY_OPTIMIZE = 3 + /** + * The primary link can change if a superior path is detected. + * (default if user provides no fail-over guidance) + */ + ZT_BOND_RESELECTION_POLICY_OPTIMIZE = 3 }; /** @@ -110,204 +110,204 @@ enum ZT_BondLinkMode { ZT_BOND_SLAVE_MODE_PRIMARY = 0, ZT_BOND_SLAVE_MODE_SPARE namespace ZeroTier { class Link { - friend class SharedPtr; + friend class SharedPtr; public: - /** - * - * @param ifnameStr - * @param ipvPref - * @param capacity - * @param enabled - * @param mode - * @param failoverToLinkStr - */ - Link(std::string ifnameStr, uint8_t ipvPref, uint16_t mtu, uint32_t capacity, bool enabled, uint8_t mode, std::string failoverToLinkStr) - : _ifnameStr(ifnameStr) - , _ipvPref(ipvPref) - , _mtu(mtu) - , _capacity(capacity) - , _relativeCapacity(0.0) - , _enabled(enabled) - , _mode(mode) - , _failoverToLinkStr(failoverToLinkStr) - , _isUserSpecified(false) - { - } + /** + * + * @param ifnameStr + * @param ipvPref + * @param capacity + * @param enabled + * @param mode + * @param failoverToLinkStr + */ + Link(std::string ifnameStr, uint8_t ipvPref, uint16_t mtu, uint32_t capacity, bool enabled, uint8_t mode, std::string failoverToLinkStr) + : _ifnameStr(ifnameStr) + , _ipvPref(ipvPref) + , _mtu(mtu) + , _capacity(capacity) + , _relativeCapacity(0.0) + , _enabled(enabled) + , _mode(mode) + , _failoverToLinkStr(failoverToLinkStr) + , _isUserSpecified(false) + { + } - /** - * @return The string representation of this link's underlying interface's system name. - */ - inline std::string ifname() - { - return _ifnameStr; - } + /** + * @return The string representation of this link's underlying interface's system name. + */ + inline std::string ifname() + { + return _ifnameStr; + } - /** - * @return Whether this link is designated as a primary. - */ - inline bool primary() - { - return _mode == ZT_BOND_SLAVE_MODE_PRIMARY; - } + /** + * @return Whether this link is designated as a primary. + */ + inline bool primary() + { + return _mode == ZT_BOND_SLAVE_MODE_PRIMARY; + } - /** - * @return Whether this link is designated as a spare. - */ - inline bool spare() - { - return _mode == ZT_BOND_SLAVE_MODE_SPARE; - } + /** + * @return Whether this link is designated as a spare. + */ + inline bool spare() + { + return _mode == ZT_BOND_SLAVE_MODE_SPARE; + } - /** - * @return The name of the link interface that should be used in the event of a failure. - */ - inline std::string failoverToLink() - { - return _failoverToLinkStr; - } + /** + * @return The name of the link interface that should be used in the event of a failure. + */ + inline std::string failoverToLink() + { + return _failoverToLinkStr; + } - /** - * @return Whether this link interface was specified by the user or auto-detected. - */ - inline bool isUserSpecified() - { - return _isUserSpecified; - } + /** + * @return Whether this link interface was specified by the user or auto-detected. + */ + inline bool isUserSpecified() + { + return _isUserSpecified; + } - /** - * Signify that this link was specified by the user and not the result of auto-detection. - * - * @param isUserSpecified - */ - inline void setAsUserSpecified(bool isUserSpecified) - { - _isUserSpecified = isUserSpecified; - } + /** + * Signify that this link was specified by the user and not the result of auto-detection. + * + * @param isUserSpecified + */ + inline void setAsUserSpecified(bool isUserSpecified) + { + _isUserSpecified = isUserSpecified; + } - /** - * @return Whether or not the user has specified failover instructions. - */ - inline bool userHasSpecifiedFailoverInstructions() - { - return _failoverToLinkStr.length(); - } + /** + * @return Whether or not the user has specified failover instructions. + */ + inline bool userHasSpecifiedFailoverInstructions() + { + return _failoverToLinkStr.length(); + } - /** - * @return The capacity of the link relative to others in the bond. - */ - inline float relativeCapacity() - { - return _relativeCapacity; - } + /** + * @return The capacity of the link relative to others in the bond. + */ + inline float relativeCapacity() + { + return _relativeCapacity; + } - /** - * Sets the capacity of the link relative to others in the bond. - * - * @param relativeCapacity The capacity relative to the rest of the link. - */ - inline void setRelativeCapacity(float relativeCapacity) - { - _relativeCapacity = relativeCapacity; - } + /** + * Sets the capacity of the link relative to others in the bond. + * + * @param relativeCapacity The capacity relative to the rest of the link. + */ + inline void setRelativeCapacity(float relativeCapacity) + { + _relativeCapacity = relativeCapacity; + } - /** - * @return The absolute capacity of the link (as specified by the user.) - */ - inline uint32_t capacity() - { - return _capacity; - } + /** + * @return The absolute capacity of the link (as specified by the user.) + */ + inline uint32_t capacity() + { + return _capacity; + } - /** - * @return The address preference for this link (as specified by the user.) - */ - inline uint8_t ipvPref() - { - return _ipvPref; - } + /** + * @return The address preference for this link (as specified by the user.) + */ + inline uint8_t ipvPref() + { + return _ipvPref; + } - /** - * @return The MTU for this link (as specified by the user.) - */ - inline uint16_t mtu() - { - return _mtu; - } + /** + * @return The MTU for this link (as specified by the user.) + */ + inline uint16_t mtu() + { + return _mtu; + } - /** - * @return The mode (e.g. primary/spare) for this link (as specified by the user.) - */ - inline uint8_t mode() - { - return _mode; - } + /** + * @return The mode (e.g. primary/spare) for this link (as specified by the user.) + */ + inline uint8_t mode() + { + return _mode; + } - /** - * @return Whether this link is enabled or disabled - */ - inline uint8_t enabled() - { - return _enabled; - } + /** + * @return Whether this link is enabled or disabled + */ + inline uint8_t enabled() + { + return _enabled; + } private: - /** - * String representation of underlying interface's system name - */ - std::string _ifnameStr; + /** + * String representation of underlying interface's system name + */ + std::string _ifnameStr; - /** - * What preference (if any) a user has for IP protocol version used in - * path aggregations. Preference is expressed in the order of the digits: - * - * 0: no preference - * 4: IPv4 only - * 6: IPv6 only - * 46: IPv4 over IPv6 - * 64: IPv6 over IPv4 - */ - uint8_t _ipvPref; + /** + * What preference (if any) a user has for IP protocol version used in + * path aggregations. Preference is expressed in the order of the digits: + * + * 0: no preference + * 4: IPv4 only + * 6: IPv6 only + * 46: IPv4 over IPv6 + * 64: IPv6 over IPv4 + */ + uint8_t _ipvPref; - /** - * The physical-layer MTU for this link - */ - uint16_t _mtu; + /** + * The physical-layer MTU for this link + */ + uint16_t _mtu; - /** - * User-specified capacity of this link - */ - uint32_t _capacity; + /** + * User-specified capacity of this link + */ + uint32_t _capacity; - /** - * Speed relative to other specified links (computed by Bond) - */ - float _relativeCapacity; + /** + * Speed relative to other specified links (computed by Bond) + */ + float _relativeCapacity; - /** - * Whether this link is enabled, or (disabled (possibly bad config)) - */ - uint8_t _enabled; + /** + * Whether this link is enabled, or (disabled (possibly bad config)) + */ + uint8_t _enabled; - /** - * Whether this link is designated as a primary, a spare, or no preference. - */ - uint8_t _mode; + /** + * Whether this link is designated as a primary, a spare, or no preference. + */ + uint8_t _mode; - /** - * The specific name of the link to be used in the event that this - * link fails. - */ - std::string _failoverToLinkStr; + /** + * The specific name of the link to be used in the event that this + * link fails. + */ + std::string _failoverToLinkStr; - /** - * Whether or not this link was created as a result of manual user specification. This is - * important to know because certain policy decisions are dependent on whether the user - * intents to use a specific set of interfaces. - */ - bool _isUserSpecified; + /** + * Whether or not this link was created as a result of manual user specification. This is + * important to know because certain policy decisions are dependent on whether the user + * intents to use a specific set of interfaces. + */ + bool _isUserSpecified; - AtomicCounter __refCount; + AtomicCounter __refCount; }; class Link; @@ -315,1259 +315,1259 @@ class Peer; class Bond { public: - /** - * Stop bond's internal functions (can be resumed) - */ - void stopBond(); + /** + * Stop bond's internal functions (can be resumed) + */ + void stopBond(); - /** - * Start or resume a bond's internal functions - */ - void startBond(); + /** + * Start or resume a bond's internal functions + */ + void startBond(); - /** - * @return Whether this link is permitted to become a member of a bond. - */ - static bool linkAllowed(std::string& policyAlias, SharedPtr link); + /** + * @return Whether this link is permitted to become a member of a bond. + */ + static bool linkAllowed(std::string& policyAlias, SharedPtr link); - /** - * @return The minimum interval required to poll the active bonds to fulfill all active monitoring timing requirements. - */ - static int minReqMonitorInterval() - { - return _minReqMonitorInterval; - } + /** + * @return The minimum interval required to poll the active bonds to fulfill all active monitoring timing requirements. + */ + static int minReqMonitorInterval() + { + return _minReqMonitorInterval; + } - /** - * @return Whether the bonding layer is currently set up to be used. - */ - static bool inUse() - { - return ! _bondPolicyTemplates.empty() || _defaultPolicy; - } + /** + * @return Whether the bonding layer is currently set up to be used. + */ + static bool inUse() + { + return ! _bondPolicyTemplates.empty() || _defaultPolicy; + } - /** - * Sets a pointer to an instance of _binder used by the Bond to get interface data - */ - static void setBinder(Binder* b) - { - _binder = b; - } + /** + * Sets a pointer to an instance of _binder used by the Bond to get interface data + */ + static void setBinder(Binder* b) + { + _binder = b; + } - /** - * @param basePolicyName Bonding policy name (See ZeroTierOne.h) - * @return The bonding policy code for a given human-readable bonding policy name - */ - static int getPolicyCodeByStr(const std::string& basePolicyName) - { - if (basePolicyName == "active-backup") { - return 1; - } - if (basePolicyName == "broadcast") { - return 2; - } - if (basePolicyName == "balance-rr") { - return 3; - } - if (basePolicyName == "balance-xor") { - return 4; - } - if (basePolicyName == "balance-aware") { - return 5; - } - return 0; // "none" - } + /** + * @param basePolicyName Bonding policy name (See ZeroTierOne.h) + * @return The bonding policy code for a given human-readable bonding policy name + */ + static int getPolicyCodeByStr(const std::string& basePolicyName) + { + if (basePolicyName == "active-backup") { + return 1; + } + if (basePolicyName == "broadcast") { + return 2; + } + if (basePolicyName == "balance-rr") { + return 3; + } + if (basePolicyName == "balance-xor") { + return 4; + } + if (basePolicyName == "balance-aware") { + return 5; + } + return 0; // "none" + } - /** - * @param policy Bonding policy code (See ZeroTierOne.h) - * @return The human-readable name for the given bonding policy code - */ - static std::string getPolicyStrByCode(int policy) - { - if (policy == 1) { - return "active-backup"; - } - if (policy == 2) { - return "broadcast"; - } - if (policy == 3) { - return "balance-rr"; - } - if (policy == 4) { - return "balance-xor"; - } - if (policy == 5) { - return "balance-aware"; - } - return "none"; - } + /** + * @param policy Bonding policy code (See ZeroTierOne.h) + * @return The human-readable name for the given bonding policy code + */ + static std::string getPolicyStrByCode(int policy) + { + if (policy == 1) { + return "active-backup"; + } + if (policy == 2) { + return "broadcast"; + } + if (policy == 3) { + return "balance-rr"; + } + if (policy == 4) { + return "balance-xor"; + } + if (policy == 5) { + return "balance-aware"; + } + return "none"; + } - /** - * Sets the default bonding policy for new or undefined bonds. - * - * @param bp Bonding policy - */ - static void setBondingLayerDefaultPolicy(uint8_t bp) - { - _defaultPolicy = bp; - } + /** + * Sets the default bonding policy for new or undefined bonds. + * + * @param bp Bonding policy + */ + static void setBondingLayerDefaultPolicy(uint8_t bp) + { + _defaultPolicy = bp; + } - /** - * Sets the default (custom) bonding policy for new or undefined bonds. - * - * @param alias Human-readable string alias for bonding policy - */ - static void setBondingLayerDefaultPolicyStr(std::string alias) - { - _defaultPolicyStr = alias; - } + /** + * Sets the default (custom) bonding policy for new or undefined bonds. + * + * @param alias Human-readable string alias for bonding policy + */ + static void setBondingLayerDefaultPolicyStr(std::string alias) + { + _defaultPolicyStr = alias; + } - /** - * Add a user-defined link to a given bonding policy. - * - * @param policyAlias User-defined custom name for variant of bonding policy - * @param link Pointer to new link definition - */ - static void addCustomLink(std::string& policyAlias, SharedPtr link); + /** + * Add a user-defined link to a given bonding policy. + * + * @param policyAlias User-defined custom name for variant of bonding policy + * @param link Pointer to new link definition + */ + static void addCustomLink(std::string& policyAlias, SharedPtr link); - /** - * Add a user-defined bonding policy that is based on one of the standard types. - * - * @param newBond Pointer to custom Bond object - * @return Whether a uniquely-named custom policy was successfully added - */ - static bool addCustomPolicy(const SharedPtr& newBond); + /** + * Add a user-defined bonding policy that is based on one of the standard types. + * + * @param newBond Pointer to custom Bond object + * @return Whether a uniquely-named custom policy was successfully added + */ + static bool addCustomPolicy(const SharedPtr& newBond); - /** - * Assigns a specific bonding policy - * - * @param identity - * @param policyAlias - * @return - */ - static bool assignBondingPolicyToPeer(int64_t identity, const std::string& policyAlias); + /** + * Assigns a specific bonding policy + * + * @param identity + * @param policyAlias + * @return + */ + static bool assignBondingPolicyToPeer(int64_t identity, const std::string& policyAlias); - /** - * Get pointer to bond by a given peer ID - * - * @param peer Remote peer ID - * @return A pointer to the Bond - */ - static SharedPtr getBondByPeerId(int64_t identity); + /** + * Get pointer to bond by a given peer ID + * + * @param peer Remote peer ID + * @return A pointer to the Bond + */ + static SharedPtr getBondByPeerId(int64_t identity); - /** - * Set MTU for link by given interface name and IP address (across all bonds) - * - * @param mtu MTU to be used on this link - * @param ifStr interface name to match - * @param ipStr IP address to match - * @return Whether the MTU was set - */ - static bool setAllMtuByTuple(uint16_t mtu, const std::string& ifStr, const std::string& ipStr); + /** + * Set MTU for link by given interface name and IP address (across all bonds) + * + * @param mtu MTU to be used on this link + * @param ifStr interface name to match + * @param ipStr IP address to match + * @return Whether the MTU was set + */ + static bool setAllMtuByTuple(uint16_t mtu, const std::string& ifStr, const std::string& ipStr); - /** - * Set MTU for link by given interface name and IP address - * - * @param mtu MTU to be used on this link - * @param ifStr interface name to match - * @param ipStr IP address to match - * @return Whether the MTU was set - */ - bool setMtuByTuple(uint16_t mtu, const std::string& ifStr, const std::string& ipStr); + /** + * Set MTU for link by given interface name and IP address + * + * @param mtu MTU to be used on this link + * @param ifStr interface name to match + * @param ipStr IP address to match + * @return Whether the MTU was set + */ + bool setMtuByTuple(uint16_t mtu, const std::string& ifStr, const std::string& ipStr); - /** - * Add a new bond to the bond controller. - * - * @param renv Runtime environment - * @param peer Remote peer that this bond services - * @return A pointer to the newly created Bond - */ - static SharedPtr createBond(const RuntimeEnvironment* renv, const SharedPtr& peer); + /** + * Add a new bond to the bond controller. + * + * @param renv Runtime environment + * @param peer Remote peer that this bond services + * @return A pointer to the newly created Bond + */ + static SharedPtr createBond(const RuntimeEnvironment* renv, const SharedPtr& peer); - /** - * Remove a bond from the bond controller. - * - * @param peerId Remote peer that this bond services - */ - static void destroyBond(uint64_t peerId); + /** + * Remove a bond from the bond controller. + * + * @param peerId Remote peer that this bond services + */ + static void destroyBond(uint64_t peerId); - /** - * Periodically perform maintenance tasks for the bonding layer. - * - * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call - * @param now Current time - */ - static void processBackgroundTasks(void* tPtr, int64_t now); + /** + * Periodically perform maintenance tasks for the bonding layer. + * + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call + * @param now Current time + */ + static void processBackgroundTasks(void* tPtr, int64_t now); - /** - * Gets a reference to a physical link definition given a policy alias and a local socket. - * - * @param policyAlias Policy in use - * @param localSocket Local source socket - * @param createIfNeeded Whether a Link object is created if the name wasn't previously in the link map - * @return Physical link definition - */ - SharedPtr getLinkBySocket(const std::string& policyAlias, uint64_t localSocket, bool createIfNeeded); + /** + * Gets a reference to a physical link definition given a policy alias and a local socket. + * + * @param policyAlias Policy in use + * @param localSocket Local source socket + * @param createIfNeeded Whether a Link object is created if the name wasn't previously in the link map + * @return Physical link definition + */ + SharedPtr getLinkBySocket(const std::string& policyAlias, uint64_t localSocket, bool createIfNeeded); - /** - * Gets a reference to a physical link definition given its human-readable system name. - * - * @param policyAlias Policy in use - * @param ifname Alphanumeric human-readable name - * @return Physical link definition - */ - static SharedPtr getLinkByName(const std::string& policyAlias, const std::string& ifname); + /** + * Gets a reference to a physical link definition given its human-readable system name. + * + * @param policyAlias Policy in use + * @param ifname Alphanumeric human-readable name + * @return Physical link definition + */ + static SharedPtr getLinkByName(const std::string& policyAlias, const std::string& ifname); private: - static Phy* _phy; + static Phy* _phy; - static Mutex _bonds_m; - static Mutex _links_m; + static Mutex _bonds_m; + static Mutex _links_m; - /** - * The minimum required monitoring interval among all bonds - */ - static int _minReqMonitorInterval; + /** + * The minimum required monitoring interval among all bonds + */ + static int _minReqMonitorInterval; - /** - * The default bonding policy used for new bonds unless otherwise specified. - */ - static uint8_t _defaultPolicy; + /** + * The default bonding policy used for new bonds unless otherwise specified. + */ + static uint8_t _defaultPolicy; - /** - * The default bonding policy used for new bonds unless otherwise specified. - */ - static std::string _defaultPolicyStr; + /** + * The default bonding policy used for new bonds unless otherwise specified. + */ + static std::string _defaultPolicyStr; - /** - * All currently active bonds. - */ - static std::map > _bonds; + /** + * All currently active bonds. + */ + static std::map > _bonds; - /** - * Map of peers to custom bonding policies - */ - static std::map _policyTemplateAssignments; + /** + * Map of peers to custom bonding policies + */ + static std::map _policyTemplateAssignments; - /** - * User-defined bonding policies (can be assigned to a peer) - */ - static std::map > _bondPolicyTemplates; + /** + * User-defined bonding policies (can be assigned to a peer) + */ + static std::map > _bondPolicyTemplates; - /** - * Set of links defined for a given bonding policy - */ - static std::map > > _linkDefinitions; + /** + * Set of links defined for a given bonding policy + */ + static std::map > > _linkDefinitions; - /** - * Set of link objects mapped to their physical interfaces - */ - static std::map > > _interfaceToLinkMap; + /** + * Set of link objects mapped to their physical interfaces + */ + static std::map > > _interfaceToLinkMap; - struct NominatedPath; - struct Flow; + struct NominatedPath; + struct Flow; - friend class SharedPtr; - friend class Peer; + friend class SharedPtr; + friend class Peer; public: - void dumpInfo(int64_t now, bool force); - std::string pathToStr(const SharedPtr& path); - void dumpPathStatus(int64_t now, int pathIdx); + void dumpInfo(int64_t now, bool force); + std::string pathToStr(const SharedPtr& path); + void dumpPathStatus(int64_t now, int pathIdx); - SharedPtr getLink(const SharedPtr& path); + SharedPtr getLink(const SharedPtr& path); - /** - * Constructor - * - * - */ - Bond(const RuntimeEnvironment* renv); + /** + * Constructor + * + * + */ + Bond(const RuntimeEnvironment* renv); - /** - * Constructor. Creates a bond based off of ZT defaults - * - * @param renv Runtime environment - * @param policy Bonding policy - * @param peer - */ - Bond(const RuntimeEnvironment* renv, int policy, const SharedPtr& peer); + /** + * Constructor. Creates a bond based off of ZT defaults + * + * @param renv Runtime environment + * @param policy Bonding policy + * @param peer + */ + Bond(const RuntimeEnvironment* renv, int policy, const SharedPtr& peer); - /** - * Constructor. For use when user intends to manually specify parameters - * - * @param basePolicy - * @param policyAlias - * @param peer - */ - Bond(const RuntimeEnvironment* renv, std::string& basePolicy, std::string& policyAlias, const SharedPtr& peer); + /** + * Constructor. For use when user intends to manually specify parameters + * + * @param basePolicy + * @param policyAlias + * @param peer + */ + Bond(const RuntimeEnvironment* renv, std::string& basePolicy, std::string& policyAlias, const SharedPtr& peer); - /** - * Constructor. Creates a bond based off of a user-defined bond template - * - * @param renv Runtime environment - * @param original - * @param peer - */ - Bond(const RuntimeEnvironment* renv, SharedPtr originalBond, const SharedPtr& peer); + /** + * Constructor. Creates a bond based off of a user-defined bond template + * + * @param renv Runtime environment + * @param original + * @param peer + */ + Bond(const RuntimeEnvironment* renv, SharedPtr originalBond, const SharedPtr& peer); - /** - * @return The human-readable name of the bonding policy - */ - std::string policyAlias() - { - return _policyAlias; - } + /** + * @return The human-readable name of the bonding policy + */ + std::string policyAlias() + { + return _policyAlias; + } - /** - * Return whether this bond is able to properly process traffic - */ - bool isReady() - { - return _numBondedPaths; - } + /** + * Return whether this bond is able to properly process traffic + */ + bool isReady() + { + return _numBondedPaths; + } - /** - * Inform the bond about the path that its peer (owning object) just learned about. - * If the path is allowed to be used, it will be inducted into the bond on a trial - * period where link statistics will be collected to judge its quality. - * - * @param path Newly-learned Path which should now be handled by the Bond - * @param now Current time - */ - void nominatePathToBond(const SharedPtr& path, int64_t now); + /** + * Inform the bond about the path that its peer (owning object) just learned about. + * If the path is allowed to be used, it will be inducted into the bond on a trial + * period where link statistics will be collected to judge its quality. + * + * @param path Newly-learned Path which should now be handled by the Bond + * @param now Current time + */ + void nominatePathToBond(const SharedPtr& path, int64_t now); - /** - * Add a nominated path to the bond. This merely maps the index from the nominated set - * to a smaller set and sets the path's bonded flag to true. - * - * @param nominatedIdx The index in the nominated set - * @param bondedIdx The index in the bonded set (subset of nominated) - */ - void addPathToBond(int nominatedIdx, int bondedIdx); + /** + * Add a nominated path to the bond. This merely maps the index from the nominated set + * to a smaller set and sets the path's bonded flag to true. + * + * @param nominatedIdx The index in the nominated set + * @param bondedIdx The index in the bonded set (subset of nominated) + */ + void addPathToBond(int nominatedIdx, int bondedIdx); - /** - * Check path states and perform bond rebuilds if needed. - * - * @param now Current time - * @param rebuild Whether or not the bond should be reconstructed. - */ - void curateBond(int64_t now, bool rebuild); + /** + * Check path states and perform bond rebuilds if needed. + * + * @param now Current time + * @param rebuild Whether or not the bond should be reconstructed. + */ + void curateBond(int64_t now, bool rebuild); - /** - * Periodically perform statistical summaries of quality metrics for all paths. - * - * @param now Current time - */ - void estimatePathQuality(int64_t now); + /** + * Periodically perform statistical summaries of quality metrics for all paths. + * + * @param now Current time + */ + void estimatePathQuality(int64_t now); - /** - * Record an invalid incoming packet. This packet failed - * MAC/compression/cipher checks and will now contribute to a - * Packet Error Ratio (PER). - * - * @param path Path over which packet was received - */ - void recordIncomingInvalidPacket(const SharedPtr& path); + /** + * Record an invalid incoming packet. This packet failed + * MAC/compression/cipher checks and will now contribute to a + * Packet Error Ratio (PER). + * + * @param path Path over which packet was received + */ + void recordIncomingInvalidPacket(const SharedPtr& path); - /** - * Record statistics on outbound an packet. - * - * @param path Path over which packet is being sent - * @param packetId Packet ID - * @param payloadLength Packet data length - * @param verb Packet verb - * @param flowId Flow ID - * @param now Current time - */ - void recordOutgoingPacket(const SharedPtr& path, uint64_t packetId, uint16_t payloadLength, Packet::Verb verb, int32_t flowId, int64_t now); + /** + * Record statistics on outbound an packet. + * + * @param path Path over which packet is being sent + * @param packetId Packet ID + * @param payloadLength Packet data length + * @param verb Packet verb + * @param flowId Flow ID + * @param now Current time + */ + void recordOutgoingPacket(const SharedPtr& path, uint64_t packetId, uint16_t payloadLength, Packet::Verb verb, int32_t flowId, int64_t now); - /** - * Process the contents of an inbound VERB_QOS_MEASUREMENT to gather path quality observations. - * - * @param now Current time - * @param count Number of records - * @param rx_id table of packet IDs - * @param rx_ts table of holding times - */ - void receivedQoS(const SharedPtr& path, int64_t now, int count, uint64_t* rx_id, uint16_t* rx_ts); + /** + * Process the contents of an inbound VERB_QOS_MEASUREMENT to gather path quality observations. + * + * @param now Current time + * @param count Number of records + * @param rx_id table of packet IDs + * @param rx_ts table of holding times + */ + void receivedQoS(const SharedPtr& path, int64_t now, int count, uint64_t* rx_id, uint16_t* rx_ts); - /** - * Process the contents of an inbound VERB_ACK to gather path quality observations. - * - * @param pathIdx Path over which packet was received - * @param now Current time - * @param ackedBytes Number of bytes ACKed by this VERB_ACK - */ - void receivedAck(int pathIdx, int64_t now, int32_t ackedBytes); + /** + * Process the contents of an inbound VERB_ACK to gather path quality observations. + * + * @param pathIdx Path over which packet was received + * @param now Current time + * @param ackedBytes Number of bytes ACKed by this VERB_ACK + */ + void receivedAck(int pathIdx, int64_t now, int32_t ackedBytes); - /** - * Generate the contents of a VERB_QOS_MEASUREMENT packet. - * - * @param now Current time - * @param qosBuffer destination buffer - * @return Size of payload - */ - int32_t generateQoSPacket(int pathIdx, int64_t now, char* qosBuffer); + /** + * Generate the contents of a VERB_QOS_MEASUREMENT packet. + * + * @param now Current time + * @param qosBuffer destination buffer + * @return Size of payload + */ + int32_t generateQoSPacket(int pathIdx, int64_t now, char* qosBuffer); - /** - * Record statistics for an inbound packet. - * - * @param path Path over which packet was received - * @param packetId Packet ID - * @param payloadLength Packet data length - * @param verb Packet verb - * @param flowId Flow ID - * @param now Current time - */ - void recordIncomingPacket(const SharedPtr& path, uint64_t packetId, uint16_t payloadLength, Packet::Verb verb, int32_t flowId, int64_t now); + /** + * Record statistics for an inbound packet. + * + * @param path Path over which packet was received + * @param packetId Packet ID + * @param payloadLength Packet data length + * @param verb Packet verb + * @param flowId Flow ID + * @param now Current time + */ + void recordIncomingPacket(const SharedPtr& path, uint64_t packetId, uint16_t payloadLength, Packet::Verb verb, int32_t flowId, int64_t now); - /** - * Determines the most appropriate path for packet and flow egress. This decision is made by - * the underlying bonding policy as well as QoS-related statistical observations of path quality. - * - * @param now Current time - * @param flowId Flow ID - * @return Pointer to suggested Path - */ - SharedPtr getAppropriatePath(int64_t now, int32_t flowId); + /** + * Determines the most appropriate path for packet and flow egress. This decision is made by + * the underlying bonding policy as well as QoS-related statistical observations of path quality. + * + * @param now Current time + * @param flowId Flow ID + * @return Pointer to suggested Path + */ + SharedPtr getAppropriatePath(int64_t now, int32_t flowId); - /** - * Creates a new flow record - * - * @param np Path over which flow shall be handled - * @param flowId Flow ID - * @param entropy A byte of entropy to be used by the bonding algorithm - * @param now Current time - * @return Pointer to newly-created Flow - */ - SharedPtr createFlow(int pathIdx, int32_t flowId, unsigned char entropy, int64_t now); + /** + * Creates a new flow record + * + * @param np Path over which flow shall be handled + * @param flowId Flow ID + * @param entropy A byte of entropy to be used by the bonding algorithm + * @param now Current time + * @return Pointer to newly-created Flow + */ + SharedPtr createFlow(int pathIdx, int32_t flowId, unsigned char entropy, int64_t now); - /** - * Removes flow records that are past a certain age limit. - * - * @param age Age threshold to be forgotten - * @param oldest Whether only the oldest shall be forgotten - * @param now Current time - */ - void forgetFlowsWhenNecessary(uint64_t age, bool oldest, int64_t now); + /** + * Removes flow records that are past a certain age limit. + * + * @param age Age threshold to be forgotten + * @param oldest Whether only the oldest shall be forgotten + * @param now Current time + */ + void forgetFlowsWhenNecessary(uint64_t age, bool oldest, int64_t now); - /** - * Assigns a new flow to a bonded path - * - * @param flow Flow to be assigned - * @param now Current time - * @param reassign Whether this flow is being re-assigned to another path - */ - bool assignFlowToBondedPath(SharedPtr& flow, int64_t now, bool reassign); + /** + * Assigns a new flow to a bonded path + * + * @param flow Flow to be assigned + * @param now Current time + * @param reassign Whether this flow is being re-assigned to another path + */ + bool assignFlowToBondedPath(SharedPtr& flow, int64_t now, bool reassign); - /** - * Determine whether a path change should occur given the remote peer's reported utility and our - * local peer's known utility. This has the effect of assigning inbound and outbound traffic to - * the same path. - * - * @param now Current time - * @param path Path over which the negotiation request was received - * @param remoteUtility How much utility the remote peer claims to gain by using the declared path - */ - void processIncomingPathNegotiationRequest(uint64_t now, SharedPtr& path, int16_t remoteUtility); + /** + * Determine whether a path change should occur given the remote peer's reported utility and our + * local peer's known utility. This has the effect of assigning inbound and outbound traffic to + * the same path. + * + * @param now Current time + * @param path Path over which the negotiation request was received + * @param remoteUtility How much utility the remote peer claims to gain by using the declared path + */ + void processIncomingPathNegotiationRequest(uint64_t now, SharedPtr& path, int16_t remoteUtility); - /** - * Determine state of path synchronization and whether a negotiation request - * shall be sent to the peer. - * - * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call - * @param now Current time - */ - void pathNegotiationCheck(void* tPtr, int64_t now); + /** + * Determine state of path synchronization and whether a negotiation request + * shall be sent to the peer. + * + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call + * @param now Current time + */ + void pathNegotiationCheck(void* tPtr, int64_t now); - /** - * Sends a VERB_ACK to the remote peer. - * - * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call - * @param path Path over which packet should be sent - * @param localSocket Local source socket - * @param atAddress - * @param now Current time - */ - void sendACK(void* tPtr, int pathIdx, int64_t localSocket, const InetAddress& atAddress, int64_t now); + /** + * Sends a VERB_ACK to the remote peer. + * + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call + * @param path Path over which packet should be sent + * @param localSocket Local source socket + * @param atAddress + * @param now Current time + */ + void sendACK(void* tPtr, int pathIdx, int64_t localSocket, const InetAddress& atAddress, int64_t now); - /** - * Sends a VERB_QOS_MEASUREMENT to the remote peer. - * - * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call - * @param path Path over which packet should be sent - * @param localSocket Local source socket - * @param atAddress - * @param now Current time - */ - void sendQOS_MEASUREMENT(void* tPtr, int pathIdx, int64_t localSocket, const InetAddress& atAddress, int64_t now); + /** + * Sends a VERB_QOS_MEASUREMENT to the remote peer. + * + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call + * @param path Path over which packet should be sent + * @param localSocket Local source socket + * @param atAddress + * @param now Current time + */ + void sendQOS_MEASUREMENT(void* tPtr, int pathIdx, int64_t localSocket, const InetAddress& atAddress, int64_t now); - /** - * Sends a VERB_PATH_NEGOTIATION_REQUEST to the remote peer. - * - * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call - * @param path Path over which packet should be sent - */ - void sendPATH_NEGOTIATION_REQUEST(void* tPtr, int pathIdx); + /** + * Sends a VERB_PATH_NEGOTIATION_REQUEST to the remote peer. + * + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call + * @param path Path over which packet should be sent + */ + void sendPATH_NEGOTIATION_REQUEST(void* tPtr, int pathIdx); - /** - * - * @param now Current time - */ - void processBalanceTasks(int64_t now); + /** + * + * @param now Current time + */ + void processBalanceTasks(int64_t now); - /** - * Perform periodic tasks unique to active-backup - * - * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call - * @param now Current time - */ - void processActiveBackupTasks(void* tPtr, int64_t now); + /** + * Perform periodic tasks unique to active-backup + * + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call + * @param now Current time + */ + void processActiveBackupTasks(void* tPtr, int64_t now); - /** - * Switches the active link in an active-backup scenario to the next best during - * a failover event. - * - * @param now Current time - */ - void dequeueNextActiveBackupPath(uint64_t now); + /** + * Switches the active link in an active-backup scenario to the next best during + * a failover event. + * + * @param now Current time + */ + void dequeueNextActiveBackupPath(uint64_t now); - /** - * Zero all timers - */ - void initTimers(); + /** + * Zero all timers + */ + void initTimers(); - /** - * Set bond parameters to reasonable defaults, these may later be overwritten by - * user-specified parameters. - * - * @param policy Bonding policy - * @param templateBond - */ - void setBondParameters(int policy, SharedPtr templateBond, bool useTemplate); + /** + * Set bond parameters to reasonable defaults, these may later be overwritten by + * user-specified parameters. + * + * @param policy Bonding policy + * @param templateBond + */ + void setBondParameters(int policy, SharedPtr templateBond, bool useTemplate); - /** - * Check and assign user-specified link quality parameters to this bond. - * - * @param weights Set of user-specified parameters - * @param len Length of parameter vector - */ - void setUserLinkQualitySpec(float weights[], int len); + /** + * Check and assign user-specified link quality parameters to this bond. + * + * @param weights Set of user-specified parameters + * @param len Length of parameter vector + */ + void setUserLinkQualitySpec(float weights[], int len); - /** - * @return Whether the user has defined links for use on this bond - */ - inline bool userHasSpecifiedLinks() - { - return _userHasSpecifiedLinks; - } + /** + * @return Whether the user has defined links for use on this bond + */ + inline bool userHasSpecifiedLinks() + { + return _userHasSpecifiedLinks; + } - /** - * @return Whether the user has defined a set of failover link(s) for this bond - */ - inline bool userHasSpecifiedFailoverInstructions() - { - return _userHasSpecifiedFailoverInstructions; - }; + /** + * @return Whether the user has defined a set of failover link(s) for this bond + */ + inline bool userHasSpecifiedFailoverInstructions() + { + return _userHasSpecifiedFailoverInstructions; + }; - /** - * @return Whether the user has specified a primary link - */ - inline bool userHasSpecifiedPrimaryLink() - { - return _userHasSpecifiedPrimaryLink; - } + /** + * @return Whether the user has specified a primary link + */ + inline bool userHasSpecifiedPrimaryLink() + { + return _userHasSpecifiedPrimaryLink; + } - /** - * @return Whether the user has specified link capacities - */ - inline bool userHasSpecifiedLinkCapacities() - { - return _userHasSpecifiedLinkCapacities; - } + /** + * @return Whether the user has specified link capacities + */ + inline bool userHasSpecifiedLinkCapacities() + { + return _userHasSpecifiedLinkCapacities; + } - /** - * Periodically perform maintenance tasks for each active bond. - * - * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call - * @param now Current time - */ - void processBackgroundBondTasks(void* tPtr, int64_t now); + /** + * Periodically perform maintenance tasks for each active bond. + * + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call + * @param now Current time + */ + void processBackgroundBondTasks(void* tPtr, int64_t now); - /** - * Rate limit gate for VERB_ACK - * - * @param now Current time - * @return Whether the incoming packet should be rate-gated - */ - inline bool rateGateACK(const int64_t now) - { - _ackCutoffCount++; - int numToDrain = _lastAckRateCheck ? (now - _lastAckRateCheck) / ZT_ACK_DRAINAGE_DIVISOR : _ackCutoffCount; - _lastAckRateCheck = now; - if (_ackCutoffCount > numToDrain) { - _ackCutoffCount -= numToDrain; - } - else { - _ackCutoffCount = 0; - } - return (_ackCutoffCount < ZT_ACK_CUTOFF_LIMIT); - } + /** + * Rate limit gate for VERB_ACK + * + * @param now Current time + * @return Whether the incoming packet should be rate-gated + */ + inline bool rateGateACK(const int64_t now) + { + _ackCutoffCount++; + int numToDrain = _lastAckRateCheck ? (now - _lastAckRateCheck) / ZT_ACK_DRAINAGE_DIVISOR : _ackCutoffCount; + _lastAckRateCheck = now; + if (_ackCutoffCount > numToDrain) { + _ackCutoffCount -= numToDrain; + } + else { + _ackCutoffCount = 0; + } + return (_ackCutoffCount < ZT_ACK_CUTOFF_LIMIT); + } - /** - * Rate limit gate for VERB_QOS_MEASUREMENT - * - * @param now Current time - * @return Whether the incoming packet should be rate-gated - */ - inline bool rateGateQoS(int64_t now, SharedPtr& path) - { - char pathStr[64] = { 0 }; - path->address().toString(pathStr); - uint64_t diff = now - _lastQoSRateCheck; - if ((diff) <= (_qosSendInterval / ZT_MAX_PEER_NETWORK_PATHS)) { - ++_qosCutoffCount; - } - else { - _qosCutoffCount = 0; - } - _lastQoSRateCheck = now; - return (_qosCutoffCount < (ZT_MAX_PEER_NETWORK_PATHS * 2)); - } + /** + * Rate limit gate for VERB_QOS_MEASUREMENT + * + * @param now Current time + * @return Whether the incoming packet should be rate-gated + */ + inline bool rateGateQoS(int64_t now, SharedPtr& path) + { + char pathStr[64] = { 0 }; + path->address().toString(pathStr); + uint64_t diff = now - _lastQoSRateCheck; + if ((diff) <= (_qosSendInterval / ZT_MAX_PEER_NETWORK_PATHS)) { + ++_qosCutoffCount; + } + else { + _qosCutoffCount = 0; + } + _lastQoSRateCheck = now; + return (_qosCutoffCount < (ZT_MAX_PEER_NETWORK_PATHS * 2)); + } - /** - * Rate limit gate for VERB_PATH_NEGOTIATION_REQUEST - * - * @param now Current time - * @return Whether the incoming packet should be rate-gated - */ - inline bool rateGatePathNegotiation(int64_t now, SharedPtr& path) - { - char pathStr[64] = { 0 }; - path->address().toString(pathStr); - int diff = now - _lastPathNegotiationReceived; - if ((diff) <= (ZT_PATH_NEGOTIATION_CUTOFF_TIME / ZT_MAX_PEER_NETWORK_PATHS)) { - ++_pathNegotiationCutoffCount; - } - else { - _pathNegotiationCutoffCount = 0; - } - _lastPathNegotiationReceived = now; - return (_pathNegotiationCutoffCount < (ZT_MAX_PEER_NETWORK_PATHS * 2)); - } + /** + * Rate limit gate for VERB_PATH_NEGOTIATION_REQUEST + * + * @param now Current time + * @return Whether the incoming packet should be rate-gated + */ + inline bool rateGatePathNegotiation(int64_t now, SharedPtr& path) + { + char pathStr[64] = { 0 }; + path->address().toString(pathStr); + int diff = now - _lastPathNegotiationReceived; + if ((diff) <= (ZT_PATH_NEGOTIATION_CUTOFF_TIME / ZT_MAX_PEER_NETWORK_PATHS)) { + ++_pathNegotiationCutoffCount; + } + else { + _pathNegotiationCutoffCount = 0; + } + _lastPathNegotiationReceived = now; + return (_pathNegotiationCutoffCount < (ZT_MAX_PEER_NETWORK_PATHS * 2)); + } - /** - * @param interval Maximum amount of time user expects a failover to take on this bond. - */ - inline void setFailoverInterval(uint32_t interval) - { - _failoverInterval = interval; - } + /** + * @param interval Maximum amount of time user expects a failover to take on this bond. + */ + inline void setFailoverInterval(uint32_t interval) + { + _failoverInterval = interval; + } - /** - * @param interval Maximum amount of time user expects a failover to take on this bond. - */ - inline uint32_t getFailoverInterval() - { - return _failoverInterval; - } + /** + * @param interval Maximum amount of time user expects a failover to take on this bond. + */ + inline uint32_t getFailoverInterval() + { + return _failoverInterval; + } - /** - * @param strategy Strategy that the bond uses to prob for path aliveness and quality - */ - inline void setLinkMonitorStrategy(uint8_t strategy) - { - _linkMonitorStrategy = strategy; - } + /** + * @param strategy Strategy that the bond uses to prob for path aliveness and quality + */ + inline void setLinkMonitorStrategy(uint8_t strategy) + { + _linkMonitorStrategy = strategy; + } - /** - * @return the current up delay parameter - */ - inline uint16_t getUpDelay() - { - return _upDelay; - } + /** + * @return the current up delay parameter + */ + inline uint16_t getUpDelay() + { + return _upDelay; + } - /** - * @param upDelay Length of time before a newly-discovered path is admitted to the bond - */ - inline void setUpDelay(int upDelay) - { - if (upDelay >= 0) { - _upDelay = upDelay; - } - } + /** + * @param upDelay Length of time before a newly-discovered path is admitted to the bond + */ + inline void setUpDelay(int upDelay) + { + if (upDelay >= 0) { + _upDelay = upDelay; + } + } - /** - * @return Length of time before a newly-failed path is removed from the bond - */ - inline uint16_t getDownDelay() - { - return _downDelay; - } + /** + * @return Length of time before a newly-failed path is removed from the bond + */ + inline uint16_t getDownDelay() + { + return _downDelay; + } - /** - * @param downDelay Length of time before a newly-failed path is removed from the bond - */ - inline void setDownDelay(int downDelay) - { - if (downDelay >= 0) { - _downDelay = downDelay; - } - } + /** + * @param downDelay Length of time before a newly-failed path is removed from the bond + */ + inline void setDownDelay(int downDelay) + { + if (downDelay >= 0) { + _downDelay = downDelay; + } + } - /** - * @return The current monitoring interval for the bond - */ - inline int monitorInterval() - { - return _monitorInterval; - } + /** + * @return The current monitoring interval for the bond + */ + inline int monitorInterval() + { + return _monitorInterval; + } - /** - * Set the current monitoring interval for the bond (can be overridden with intervals specific to certain links.) - * - * @param monitorInterval How often gratuitous VERB_HELLO(s) are sent to remote peer. - */ - inline void setBondMonitorInterval(uint16_t interval) - { - _monitorInterval = interval; - } + /** + * Set the current monitoring interval for the bond (can be overridden with intervals specific to certain links.) + * + * @param monitorInterval How often gratuitous VERB_HELLO(s) are sent to remote peer. + */ + inline void setBondMonitorInterval(uint16_t interval) + { + _monitorInterval = interval; + } - /** - * @param policy Bonding policy for this bond - */ + /** + * @param policy Bonding policy for this bond + */ - inline void setPolicy(uint8_t policy) - { - _policy = policy; - } + inline void setPolicy(uint8_t policy) + { + _policy = policy; + } - /** - * @return the current bonding policy - */ - inline uint8_t policy() - { - return _policy; - } + /** + * @return the current bonding policy + */ + inline uint8_t policy() + { + return _policy; + } - /** - * @return the number of links in this bond which are considered alive - */ - inline uint8_t getNumAliveLinks() - { - return _numAliveLinks; - }; + /** + * @return the number of links in this bond which are considered alive + */ + inline uint8_t getNumAliveLinks() + { + return _numAliveLinks; + }; - /** - * @return the number of links in this bond - */ - inline uint8_t getNumTotalLinks() - { - return _numTotalLinks; - } + /** + * @return the number of links in this bond + */ + inline uint8_t getNumTotalLinks() + { + return _numTotalLinks; + } - /** - * @return Whether flow-hashing is currently supported for this bond. - */ - bool flowHashingSupported() - { - return _policy == ZT_BOND_POLICY_BALANCE_XOR || _policy == ZT_BOND_POLICY_BALANCE_AWARE; - } + /** + * @return Whether flow-hashing is currently supported for this bond. + */ + bool flowHashingSupported() + { + return _policy == ZT_BOND_POLICY_BALANCE_XOR || _policy == ZT_BOND_POLICY_BALANCE_AWARE; + } - /** - * - * @param packetsPerLink - */ - inline void setPacketsPerLink(int packetsPerLink) - { - _packetsPerLink = packetsPerLink; - } + /** + * + * @param packetsPerLink + */ + inline void setPacketsPerLink(int packetsPerLink) + { + _packetsPerLink = packetsPerLink; + } - /** - * @return Number of packets to be sent on each interface in a balance-rr bond - */ - inline int getPacketsPerLink() - { - return _packetsPerLink; - } + /** + * @return Number of packets to be sent on each interface in a balance-rr bond + */ + inline int getPacketsPerLink() + { + return _packetsPerLink; + } - /** - * - * @param linkSelectMethod - */ - inline void setLinkSelectMethod(uint8_t method) - { - _abLinkSelectMethod = method; - } + /** + * + * @param linkSelectMethod + */ + inline void setLinkSelectMethod(uint8_t method) + { + _abLinkSelectMethod = method; + } - /** - * - * @return - */ - inline uint8_t getLinkSelectMethod() - { - return _abLinkSelectMethod; - } + /** + * + * @return + */ + inline uint8_t getLinkSelectMethod() + { + return _abLinkSelectMethod; + } - /** - * - * @param allowPathNegotiation - */ - inline void setAllowPathNegotiation(bool allowPathNegotiation) - { - _allowPathNegotiation = allowPathNegotiation; - } + /** + * + * @param allowPathNegotiation + */ + inline void setAllowPathNegotiation(bool allowPathNegotiation) + { + _allowPathNegotiation = allowPathNegotiation; + } - /** - * - * @return - */ - inline bool allowPathNegotiation() - { - return _allowPathNegotiation; - } + /** + * + * @return + */ + inline bool allowPathNegotiation() + { + return _allowPathNegotiation; + } - /** - * Forcibly rotates the currently active link used in an active-backup bond to the next link in the failover queue - * - * @return True if this operation succeeded, false if otherwise - */ - bool abForciblyRotateLink(); + /** + * Forcibly rotates the currently active link used in an active-backup bond to the next link in the failover queue + * + * @return True if this operation succeeded, false if otherwise + */ + bool abForciblyRotateLink(); - /** - * Emit message to tracing system but with added timestamp and subsystem info - */ - void log(const char* fmt, ...) + /** + * Emit message to tracing system but with added timestamp and subsystem info + */ + void log(const char* fmt, ...) #ifdef __GNUC__ - __attribute__((format(printf, 2, 3))) + __attribute__((format(printf, 2, 3))) #endif - { - //if (_peerId != 0x0 && _peerId != 0x0) { return; } + { + // if (_peerId != 0x0 && _peerId != 0x0) { return; } #ifdef ZT_TRACE - time_t rawtime; - struct tm* timeinfo; - char timestamp[80]; - time(&rawtime); - timeinfo = localtime(&rawtime); - strftime(timestamp, 80, "%F %T", timeinfo); + time_t rawtime; + struct tm* timeinfo; + char timestamp[80]; + time(&rawtime); + timeinfo = localtime(&rawtime); + strftime(timestamp, 80, "%F %T", timeinfo); #define MAX_BOND_MSG_LEN 1024 - char traceMsg[MAX_BOND_MSG_LEN]; - char userMsg[MAX_BOND_MSG_LEN]; - va_list args; - va_start(args, fmt); - if (vsnprintf(userMsg, sizeof(userMsg), fmt, args) < 0) { - fprintf(stderr, "Encountered format encoding error while writing to trace log\n"); - return; - } - snprintf(traceMsg, MAX_BOND_MSG_LEN, "%s (%llx/%s) %s", timestamp, _peerId, _policyAlias.c_str(), userMsg); - va_end(args); - RR->t->bondStateMessage(NULL, traceMsg); + char traceMsg[MAX_BOND_MSG_LEN]; + char userMsg[MAX_BOND_MSG_LEN]; + va_list args; + va_start(args, fmt); + if (vsnprintf(userMsg, sizeof(userMsg), fmt, args) < 0) { + fprintf(stderr, "Encountered format encoding error while writing to trace log\n"); + return; + } + snprintf(traceMsg, MAX_BOND_MSG_LEN, "%s (%llx/%s) %s", timestamp, _peerId, _policyAlias.c_str(), userMsg); + va_end(args); + RR->t->bondStateMessage(NULL, traceMsg); #undef MAX_MSG_LEN #endif - } + } - /** - * Emit message to tracing system but with added timestamp and subsystem info - */ - void debug(const char* fmt, ...) + /** + * Emit message to tracing system but with added timestamp and subsystem info + */ + void debug(const char* fmt, ...) #ifdef __GNUC__ - __attribute__((format(printf, 2, 3))) + __attribute__((format(printf, 2, 3))) #endif - { - //if (_peerId != 0x0 && _peerId != 0x0) { return; } + { + // if (_peerId != 0x0 && _peerId != 0x0) { return; } #ifdef ZT_DEBUG - time_t rawtime; - struct tm* timeinfo; - char timestamp[80]; - time(&rawtime); - timeinfo = localtime(&rawtime); - strftime(timestamp, 80, "%F %T", timeinfo); + time_t rawtime; + struct tm* timeinfo; + char timestamp[80]; + time(&rawtime); + timeinfo = localtime(&rawtime); + strftime(timestamp, 80, "%F %T", timeinfo); #define MAX_BOND_MSG_LEN 1024 - char traceMsg[MAX_BOND_MSG_LEN]; - char userMsg[MAX_BOND_MSG_LEN]; - va_list args; - va_start(args, fmt); - if (vsnprintf(userMsg, sizeof(userMsg), fmt, args) < 0) { - fprintf(stderr, "Encountered format encoding error while writing to trace log\n"); - return; - } - snprintf(traceMsg, MAX_BOND_MSG_LEN, "%s (%llx/%s) %s", timestamp, _peerId, _policyAlias.c_str(), userMsg); - va_end(args); - RR->t->bondStateMessage(NULL, traceMsg); + char traceMsg[MAX_BOND_MSG_LEN]; + char userMsg[MAX_BOND_MSG_LEN]; + va_list args; + va_start(args, fmt); + if (vsnprintf(userMsg, sizeof(userMsg), fmt, args) < 0) { + fprintf(stderr, "Encountered format encoding error while writing to trace log\n"); + return; + } + snprintf(traceMsg, MAX_BOND_MSG_LEN, "%s (%llx/%s) %s", timestamp, _peerId, _policyAlias.c_str(), userMsg); + va_end(args); + RR->t->bondStateMessage(NULL, traceMsg); #undef MAX_MSG_LEN #endif - } + } private: - struct NominatedPath { - NominatedPath() - : lastAckSent(0) - , lastAckReceived(0) - , lastQoSReceived(0) - , unackedBytes(0) - , packetsReceivedSinceLastAck(0) - , lastQoSMeasurement(0) - , lastThroughputEstimation(0) - , lastRefractoryUpdate(0) - , lastAliveToggle(0) - , alive(false) - , eligible(true) - , lastEligibility(0) - , whenNominated(0) - , refractoryPeriod(0) - , ipvPref(0) - , mode(0) - , onlyPathOnLink(false) - , bonded(false) - , negotiated(false) - , shouldAvoid(false) - , assignedFlowCount(0) - , latency(0) - , latencyVariance(0) - , packetLossRatio(0) - , packetErrorRatio(0) - , relativeQuality(0) - , relativeLinkCapacity(0) - , failoverScore(0) - , packetsReceivedSinceLastQoS(0) - , packetsIn(0) - , packetsOut(0) - , localPort(0) - { - } + struct NominatedPath { + NominatedPath() + : lastAckSent(0) + , lastAckReceived(0) + , lastQoSReceived(0) + , unackedBytes(0) + , packetsReceivedSinceLastAck(0) + , lastQoSMeasurement(0) + , lastThroughputEstimation(0) + , lastRefractoryUpdate(0) + , lastAliveToggle(0) + , alive(false) + , eligible(true) + , lastEligibility(0) + , whenNominated(0) + , refractoryPeriod(0) + , ipvPref(0) + , mode(0) + , onlyPathOnLink(false) + , bonded(false) + , negotiated(false) + , shouldAvoid(false) + , assignedFlowCount(0) + , latency(0) + , latencyVariance(0) + , packetLossRatio(0) + , packetErrorRatio(0) + , relativeQuality(0) + , relativeLinkCapacity(0) + , failoverScore(0) + , packetsReceivedSinceLastQoS(0) + , packetsIn(0) + , packetsOut(0) + , localPort(0) + { + } - /** - * Set or update a refractory period for the path. - * - * @param punishment How much a path should be punished - * @param pathFailure Whether this call is the result of a recent path failure - */ - inline void adjustRefractoryPeriod(int64_t now, uint32_t punishment, bool pathFailure) - { - if (pathFailure) { - unsigned int suggestedRefractoryPeriod = refractoryPeriod ? punishment + (refractoryPeriod * 2) : punishment; - refractoryPeriod = std::min(suggestedRefractoryPeriod, (unsigned int)ZT_BOND_MAX_REFRACTORY_PERIOD); - lastRefractoryUpdate = 0; - } - else { - uint32_t drainRefractory = 0; - if (lastRefractoryUpdate) { - drainRefractory = (now - lastRefractoryUpdate); - } - else { - drainRefractory = (now - lastAliveToggle); - } - lastRefractoryUpdate = now; - if (refractoryPeriod > drainRefractory) { - refractoryPeriod -= drainRefractory; - } - else { - refractoryPeriod = 0; - lastRefractoryUpdate = 0; - } - } - } + /** + * Set or update a refractory period for the path. + * + * @param punishment How much a path should be punished + * @param pathFailure Whether this call is the result of a recent path failure + */ + inline void adjustRefractoryPeriod(int64_t now, uint32_t punishment, bool pathFailure) + { + if (pathFailure) { + unsigned int suggestedRefractoryPeriod = refractoryPeriod ? punishment + (refractoryPeriod * 2) : punishment; + refractoryPeriod = std::min(suggestedRefractoryPeriod, (unsigned int)ZT_BOND_MAX_REFRACTORY_PERIOD); + lastRefractoryUpdate = 0; + } + else { + uint32_t drainRefractory = 0; + if (lastRefractoryUpdate) { + drainRefractory = (now - lastRefractoryUpdate); + } + else { + drainRefractory = (now - lastAliveToggle); + } + lastRefractoryUpdate = now; + if (refractoryPeriod > drainRefractory) { + refractoryPeriod -= drainRefractory; + } + else { + refractoryPeriod = 0; + lastRefractoryUpdate = 0; + } + } + } - /** - * @return True if a path is permitted to be used in a bond (according to user pref.) - */ - inline bool allowed() - { - return (! ipvPref || ((p->_addr.isV4() && (ipvPref == 4 || ipvPref == 46 || ipvPref == 64)) || ((p->_addr.isV6() && (ipvPref == 6 || ipvPref == 46 || ipvPref == 64))))); - } + /** + * @return True if a path is permitted to be used in a bond (according to user pref.) + */ + inline bool allowed() + { + return (! ipvPref || ((p->_addr.isV4() && (ipvPref == 4 || ipvPref == 46 || ipvPref == 64)) || ((p->_addr.isV6() && (ipvPref == 6 || ipvPref == 46 || ipvPref == 64))))); + } - /** - * @return True if a path exists on a link marked as a spare - */ - inline bool isSpare() - { - return mode == ZT_BOND_SLAVE_MODE_SPARE; - } + /** + * @return True if a path exists on a link marked as a spare + */ + inline bool isSpare() + { + return mode == ZT_BOND_SLAVE_MODE_SPARE; + } - /** - * @return True if a path is preferred over another on the same physical link (according to user pref.) - */ - inline bool preferred() - { - return onlyPathOnLink || (p->_addr.isV4() && (ipvPref == 4 || ipvPref == 46)) || (p->_addr.isV6() && (ipvPref == 6 || ipvPref == 64)); - } + /** + * @return True if a path is preferred over another on the same physical link (according to user pref.) + */ + inline bool preferred() + { + return onlyPathOnLink || (p->_addr.isV4() && (ipvPref == 4 || ipvPref == 46)) || (p->_addr.isV6() && (ipvPref == 6 || ipvPref == 64)); + } - /** - * @param now Current time - * @return Whether a QoS (VERB_QOS_MEASUREMENT) packet needs to be emitted at this time - */ - inline bool needsToSendQoS(int64_t now, uint64_t qosSendInterval) - { - return ((packetsReceivedSinceLastQoS >= ZT_QOS_TABLE_SIZE) || ((now - lastQoSMeasurement) > qosSendInterval)) && packetsReceivedSinceLastQoS; - } + /** + * @param now Current time + * @return Whether a QoS (VERB_QOS_MEASUREMENT) packet needs to be emitted at this time + */ + inline bool needsToSendQoS(int64_t now, uint64_t qosSendInterval) + { + return ((packetsReceivedSinceLastQoS >= ZT_QOS_TABLE_SIZE) || ((now - lastQoSMeasurement) > qosSendInterval)) && packetsReceivedSinceLastQoS; + } - /** - * @param now Current time - * @return Whether an ACK (VERB_ACK) packet needs to be emitted at this time - */ - inline bool needsToSendAck(int64_t now, uint64_t ackSendInterval) - { - return ((now - lastAckSent) >= ackSendInterval || (packetsReceivedSinceLastAck == ZT_QOS_TABLE_SIZE)) && packetsReceivedSinceLastAck; - } + /** + * @param now Current time + * @return Whether an ACK (VERB_ACK) packet needs to be emitted at this time + */ + inline bool needsToSendAck(int64_t now, uint64_t ackSendInterval) + { + return ((now - lastAckSent) >= ackSendInterval || (packetsReceivedSinceLastAck == ZT_QOS_TABLE_SIZE)) && packetsReceivedSinceLastAck; + } - /** - * Reset packet counters - */ - inline void resetPacketCounts() - { - packetsIn = 0; - packetsOut = 0; - } + /** + * Reset packet counters + */ + inline void resetPacketCounts() + { + packetsIn = 0; + packetsOut = 0; + } - std::map qosStatsOut; // id:egress_time - std::map qosStatsIn; // id:now - std::map ackStatsIn; // id:now + std::map qosStatsOut; // id:egress_time + std::map qosStatsIn; // id:now + std::map ackStatsIn; // id:now - RingBuffer qosRecordSize; - RingBuffer qosRecordLossSamples; - RingBuffer throughputSamples; - RingBuffer packetValiditySamples; - RingBuffer throughputVarianceSamples; - RingBuffer latencySamples; + RingBuffer qosRecordSize; + RingBuffer qosRecordLossSamples; + RingBuffer throughputSamples; + RingBuffer packetValiditySamples; + RingBuffer throughputVarianceSamples; + RingBuffer latencySamples; - uint64_t lastAckSent; - uint64_t lastAckReceived; - uint64_t lastQoSReceived; - uint64_t unackedBytes; - uint64_t packetsReceivedSinceLastAck; + uint64_t lastAckSent; + uint64_t lastAckReceived; + uint64_t lastQoSReceived; + uint64_t unackedBytes; + uint64_t packetsReceivedSinceLastAck; - uint64_t lastQoSMeasurement; // Last time that a VERB_QOS_MEASUREMENT was sent out on this path. - uint64_t lastThroughputEstimation; // Last time that the path's throughput was estimated. - uint64_t lastRefractoryUpdate; // The last time that the refractory period was updated. - uint64_t lastAliveToggle; // The last time that the path was marked as "alive". - bool alive; - bool eligible; // State of eligibility at last check. Used for determining state changes. - uint64_t lastEligibility; // The last time that this path was eligible - uint64_t whenNominated; // Timestamp indicating when this path's trial period began. - uint32_t refractoryPeriod; // Amount of time that this path will be prevented from becoming a member of a bond. - uint8_t ipvPref; // IP version preference inherited from the physical link. - uint8_t mode; // Mode inherited from the physical link. - bool onlyPathOnLink; // IP version preference inherited from the physical link. - bool enabled; // Enabled state inherited from the physical link. - bool bonded; // Whether this path is currently part of a bond. - bool negotiated; // Whether this path was intentionally negotiated by either peer. - bool shouldAvoid; // Whether flows should be moved from this path. Current traffic flows will be re-allocated immediately. - uint16_t assignedFlowCount; // The number of flows currently assigned to this path. - float latency; // The mean latency (computed from a sliding window.) - float latencyVariance; // Packet delay variance (computed from a sliding window.) - float packetLossRatio; // The ratio of lost packets to received packets. - float packetErrorRatio; // The ratio of packets that failed their MAC/CRC checks to those that did not. - float relativeQuality; // The relative quality of the link. - float relativeLinkCapacity; // The relative capacity of the link. + uint64_t lastQoSMeasurement; // Last time that a VERB_QOS_MEASUREMENT was sent out on this path. + uint64_t lastThroughputEstimation; // Last time that the path's throughput was estimated. + uint64_t lastRefractoryUpdate; // The last time that the refractory period was updated. + uint64_t lastAliveToggle; // The last time that the path was marked as "alive". + bool alive; + bool eligible; // State of eligibility at last check. Used for determining state changes. + uint64_t lastEligibility; // The last time that this path was eligible + uint64_t whenNominated; // Timestamp indicating when this path's trial period began. + uint32_t refractoryPeriod; // Amount of time that this path will be prevented from becoming a member of a bond. + uint8_t ipvPref; // IP version preference inherited from the physical link. + uint8_t mode; // Mode inherited from the physical link. + bool onlyPathOnLink; // IP version preference inherited from the physical link. + bool enabled; // Enabled state inherited from the physical link. + bool bonded; // Whether this path is currently part of a bond. + bool negotiated; // Whether this path was intentionally negotiated by either peer. + bool shouldAvoid; // Whether flows should be moved from this path. Current traffic flows will be re-allocated immediately. + uint16_t assignedFlowCount; // The number of flows currently assigned to this path. + float latency; // The mean latency (computed from a sliding window.) + float latencyVariance; // Packet delay variance (computed from a sliding window.) + float packetLossRatio; // The ratio of lost packets to received packets. + float packetErrorRatio; // The ratio of packets that failed their MAC/CRC checks to those that did not. + float relativeQuality; // The relative quality of the link. + float relativeLinkCapacity; // The relative capacity of the link. - uint32_t failoverScore; // Score that indicates to what degree this path is preferred over others that are available to the bonding policy. (specifically for active-backup) - int32_t packetsReceivedSinceLastQoS; // Number of packets received since the last VERB_QOS_MEASUREMENT was sent to the remote peer. + uint32_t failoverScore; // Score that indicates to what degree this path is preferred over others that are available to the bonding policy. (specifically for active-backup) + int32_t packetsReceivedSinceLastQoS; // Number of packets received since the last VERB_QOS_MEASUREMENT was sent to the remote peer. - /** - * Counters used for tracking path load. - */ - int packetsIn; - int packetsOut; + /** + * Counters used for tracking path load. + */ + int packetsIn; + int packetsOut; - uint16_t localPort; + uint16_t localPort; - // AtomicCounter __refCount; + // AtomicCounter __refCount; - SharedPtr p; - void set(uint64_t now, const SharedPtr& path) - { - p = path; - whenNominated = now; - } - }; + SharedPtr p; + void set(uint64_t now, const SharedPtr& path) + { + p = path; + whenNominated = now; + } + }; - /** - * Paths nominated to the bond (may or may not actually be bonded) - */ - NominatedPath _paths[ZT_MAX_PEER_NETWORK_PATHS]; + /** + * Paths nominated to the bond (may or may not actually be bonded) + */ + NominatedPath _paths[ZT_MAX_PEER_NETWORK_PATHS]; - inline int getNominatedPathIdx(const SharedPtr& path) - { - for (int i = 0; i < ZT_MAX_PEER_NETWORK_PATHS; ++i) { - if (_paths[i].p == path) { - return i; - } - } - return ZT_MAX_PEER_NETWORK_PATHS; - } + inline int getNominatedPathIdx(const SharedPtr& path) + { + for (int i = 0; i < ZT_MAX_PEER_NETWORK_PATHS; ++i) { + if (_paths[i].p == path) { + return i; + } + } + return ZT_MAX_PEER_NETWORK_PATHS; + } - /** - * A protocol flow that is identified by the origin and destination port. - */ - struct Flow { - /** - * @param flowId Given flow ID - * @param now Current time - */ - Flow(int32_t flowId, int64_t now) : id(flowId), bytesIn(0), bytesOut(0), lastActivity(now), lastPathReassignment(0), assignedPath(ZT_MAX_PEER_NETWORK_PATHS) - { - } + /** + * A protocol flow that is identified by the origin and destination port. + */ + struct Flow { + /** + * @param flowId Given flow ID + * @param now Current time + */ + Flow(int32_t flowId, int64_t now) : id(flowId), bytesIn(0), bytesOut(0), lastActivity(now), lastPathReassignment(0), assignedPath(ZT_MAX_PEER_NETWORK_PATHS) + { + } - /** - * Reset flow statistics - */ - inline void resetByteCounts() - { - bytesIn = 0; - bytesOut = 0; - } + /** + * Reset flow statistics + */ + inline void resetByteCounts() + { + bytesIn = 0; + bytesOut = 0; + } - /** - * How long since a packet was sent or received in this flow - * - * @param now Current time - * @return The age of the flow in terms of last recorded activity - */ - int64_t age(int64_t now) - { - return now - lastActivity; - } + /** + * How long since a packet was sent or received in this flow + * + * @param now Current time + * @return The age of the flow in terms of last recorded activity + */ + int64_t age(int64_t now) + { + return now - lastActivity; + } - /** - * @param path Assigned path over which this flow should be handled - */ - inline void assignPath(int pathIdx, int64_t now) - { - assignedPath = pathIdx; - lastPathReassignment = now; - } + /** + * @param path Assigned path over which this flow should be handled + */ + inline void assignPath(int pathIdx, int64_t now) + { + assignedPath = pathIdx; + lastPathReassignment = now; + } - AtomicCounter __refCount; + AtomicCounter __refCount; - int32_t id; // Flow ID used for hashing and path selection - uint64_t bytesIn; // Used for tracking flow size - uint64_t bytesOut; // Used for tracking flow size - int64_t lastActivity; // The last time that this flow handled traffic - int64_t lastPathReassignment; // Time of last path assignment. Used for anti-flapping - int assignedPath; // Index of path to which this flow is assigned - }; + int32_t id; // Flow ID used for hashing and path selection + uint64_t bytesIn; // Used for tracking flow size + uint64_t bytesOut; // Used for tracking flow size + int64_t lastActivity; // The last time that this flow handled traffic + int64_t lastPathReassignment; // Time of last path assignment. Used for anti-flapping + int assignedPath; // Index of path to which this flow is assigned + }; - const RuntimeEnvironment* RR; - AtomicCounter __refCount; + const RuntimeEnvironment* RR; + AtomicCounter __refCount; - std::string _policyAlias; // Custom name given by the user to this bond type. + std::string _policyAlias; // Custom name given by the user to this bond type. - static Binder* _binder; + static Binder* _binder; - /** - * Set of indices corresponding to paths currently included in the bond proper. This - * may only be updated during a call to curateBond(). The reason for this is so that - * we can simplify the high frequency packet egress logic. - */ - int _realIdxMap[ZT_MAX_PEER_NETWORK_PATHS] = { ZT_MAX_PEER_NETWORK_PATHS }; - int _numBondedPaths; // Number of paths currently included in the _realIdxMap set. - std::map > _flows; // Flows hashed according to port and protocol - float _qw[ZT_QOS_PARAMETER_SIZE]; // Link quality specification (can be customized by user) + /** + * Set of indices corresponding to paths currently included in the bond proper. This + * may only be updated during a call to curateBond(). The reason for this is so that + * we can simplify the high frequency packet egress logic. + */ + int _realIdxMap[ZT_MAX_PEER_NETWORK_PATHS] = { ZT_MAX_PEER_NETWORK_PATHS }; + int _numBondedPaths; // Number of paths currently included in the _realIdxMap set. + std::map > _flows; // Flows hashed according to port and protocol + float _qw[ZT_QOS_PARAMETER_SIZE]; // Link quality specification (can be customized by user) - bool _run; + bool _run; - uint8_t _policy; - uint32_t _upDelay; - uint32_t _downDelay; + uint8_t _policy; + uint32_t _upDelay; + uint32_t _downDelay; - // active-backup - int _abPathIdx; // current active path - std::deque _abFailoverQueue; - uint8_t _abLinkSelectMethod; // link re-selection policy for the primary link in active-backup + // active-backup + int _abPathIdx; // current active path + std::deque _abFailoverQueue; + uint8_t _abLinkSelectMethod; // link re-selection policy for the primary link in active-backup - // balance-rr - uint8_t _rrIdx; // index to path currently in use during Round Robin operation - uint16_t _rrPacketsSentOnCurrLink; // number of packets sent on this link since the most recent path switch. - /** - * How many packets will be sent on a path before moving to the next path - * in the round-robin sequence. A value of zero will cause a random path - * selection for each outgoing packet. - */ - int _packetsPerLink; + // balance-rr + uint8_t _rrIdx; // index to path currently in use during Round Robin operation + uint16_t _rrPacketsSentOnCurrLink; // number of packets sent on this link since the most recent path switch. + /** + * How many packets will be sent on a path before moving to the next path + * in the round-robin sequence. A value of zero will cause a random path + * selection for each outgoing packet. + */ + int _packetsPerLink; - // balance-aware - uint64_t _totalBondUnderload; + // balance-aware + uint64_t _totalBondUnderload; - // dynamic link monitoring - uint8_t _linkMonitorStrategy; + // dynamic link monitoring + uint8_t _linkMonitorStrategy; - // path negotiation - int16_t _localUtility; - int _negotiatedPathIdx; - uint8_t _numSentPathNegotiationRequests; - bool _allowPathNegotiation; + // path negotiation + int16_t _localUtility; + int _negotiatedPathIdx; + uint8_t _numSentPathNegotiationRequests; + bool _allowPathNegotiation; - /** - * Timers and intervals - */ - uint64_t _failoverInterval; - uint64_t _qosSendInterval; - uint64_t _ackSendInterval; - uint64_t throughputMeasurementInterval; - uint64_t _qualityEstimationInterval; + /** + * Timers and intervals + */ + uint64_t _failoverInterval; + uint64_t _qosSendInterval; + uint64_t _ackSendInterval; + uint64_t throughputMeasurementInterval; + uint64_t _qualityEstimationInterval; - /** - * Link state reporting - */ - uint8_t _numAliveLinks; - uint8_t _numTotalLinks; + /** + * Link state reporting + */ + uint8_t _numAliveLinks; + uint8_t _numTotalLinks; - /** - * Default initial punishment inflicted on misbehaving paths. Punishment slowly - * drains linearly. For each eligibility change the remaining punishment is doubled. - */ - uint32_t _defaultPathRefractoryPeriod; - unsigned char _freeRandomByte; // Free byte of entropy that is updated on every packet egress event. - SharedPtr _peer; // Remote peer that this bond services - unsigned long long _peerId; // ID of the peer that this bond services - bool _isLeaf; + /** + * Default initial punishment inflicted on misbehaving paths. Punishment slowly + * drains linearly. For each eligibility change the remaining punishment is doubled. + */ + uint32_t _defaultPathRefractoryPeriod; + unsigned char _freeRandomByte; // Free byte of entropy that is updated on every packet egress event. + SharedPtr _peer; // Remote peer that this bond services + unsigned long long _peerId; // ID of the peer that this bond services + bool _isLeaf; - /** - * Rate-limiting - */ - uint16_t _qosCutoffCount; - uint16_t _ackCutoffCount; - uint64_t _lastQoSRateCheck; - uint64_t _lastAckRateCheck; - uint16_t _pathNegotiationCutoffCount; - uint64_t _lastPathNegotiationReceived; + /** + * Rate-limiting + */ + uint16_t _qosCutoffCount; + uint16_t _ackCutoffCount; + uint64_t _lastQoSRateCheck; + uint64_t _lastAckRateCheck; + uint16_t _pathNegotiationCutoffCount; + uint64_t _lastPathNegotiationReceived; - /** - * Recent event timestamps - */ - uint64_t _lastSummaryDump; + /** + * Recent event timestamps + */ + uint64_t _lastSummaryDump; - uint64_t _lastQualityEstimation; - uint64_t _lastBackgroundTaskCheck; - uint64_t _lastBondStatusLog; - uint64_t _lastPathNegotiationCheck; - uint64_t _lastSentPathNegotiationRequest; - uint64_t _lastFlowExpirationCheck; - uint64_t _lastFlowRebalance; - uint64_t _lastFrame; - uint64_t _lastActiveBackupPathChange; + uint64_t _lastQualityEstimation; + uint64_t _lastBackgroundTaskCheck; + uint64_t _lastBondStatusLog; + uint64_t _lastPathNegotiationCheck; + uint64_t _lastSentPathNegotiationRequest; + uint64_t _lastFlowExpirationCheck; + uint64_t _lastFlowRebalance; + uint64_t _lastFrame; + uint64_t _lastActiveBackupPathChange; - Mutex _paths_m; + Mutex _paths_m; - Mutex _flows_m; + Mutex _flows_m; - bool _userHasSpecifiedLinks; // Whether the user has specified links for this bond. - bool _userHasSpecifiedPrimaryLink; // Whether the user has specified a primary link for this bond. - bool _userHasSpecifiedFailoverInstructions; // Whether the user has specified failover instructions for this bond. - bool _userHasSpecifiedLinkCapacities; // Whether the user has specified links capacities for this bond. - /** - * How frequently (in ms) a VERB_ECHO is sent to a peer to verify that a - * path is still active. A value of zero (0) will disable active path - * monitoring; as result, all monitoring will be a function of traffic. - */ - int _monitorInterval; - bool _allowFlowHashing; // Whether or not flow hashing is allowed. + bool _userHasSpecifiedLinks; // Whether the user has specified links for this bond. + bool _userHasSpecifiedPrimaryLink; // Whether the user has specified a primary link for this bond. + bool _userHasSpecifiedFailoverInstructions; // Whether the user has specified failover instructions for this bond. + bool _userHasSpecifiedLinkCapacities; // Whether the user has specified links capacities for this bond. + /** + * How frequently (in ms) a VERB_ECHO is sent to a peer to verify that a + * path is still active. A value of zero (0) will disable active path + * monitoring; as result, all monitoring will be a function of traffic. + */ + int _monitorInterval; + bool _allowFlowHashing; // Whether or not flow hashing is allowed. - uint64_t _overheadBytes; + uint64_t _overheadBytes; }; -} // namespace ZeroTier +} // namespace ZeroTier #endif diff --git a/node/Buffer.hpp b/node/Buffer.hpp index 8dbc51ef..9eb2298f 100644 --- a/node/Buffer.hpp +++ b/node/Buffer.hpp @@ -14,18 +14,17 @@ #ifndef ZT_BUFFER_HPP #define ZT_BUFFER_HPP -#include -#include - -#include -#include -#include -#include - #include "Constants.hpp" #include "Utils.hpp" -#if defined(__GNUC__) && (!defined(ZT_NO_TYPE_PUNNING)) +#include +#include +#include +#include +#include +#include + +#if defined(__GNUC__) && (! defined(ZT_NO_TYPE_PUNNING)) #define ZT_VAR_MAY_ALIAS __attribute__((__may_alias__)) #else #define ZT_VAR_MAY_ALIAS @@ -46,441 +45,475 @@ namespace ZeroTier { * * @tparam C Total capacity */ -template -class Buffer -{ - // I love me! - template friend class Buffer; +template class Buffer { + // I love me! + template friend class Buffer; -public: - // STL container idioms - typedef unsigned char value_type; - typedef unsigned char * pointer; - typedef const char * const_pointer; - typedef char & reference; - typedef const char & const_reference; - typedef char * iterator; - typedef const char * const_iterator; - typedef unsigned int size_type; - typedef int difference_type; - typedef std::reverse_iterator reverse_iterator; - typedef std::reverse_iterator const_reverse_iterator; - inline iterator begin() { return _b; } - inline iterator end() { return (_b + _l); } - inline const_iterator begin() const { return _b; } - inline const_iterator end() const { return (_b + _l); } - inline reverse_iterator rbegin() { return reverse_iterator(begin()); } - inline reverse_iterator rend() { return reverse_iterator(end()); } - inline const_reverse_iterator rbegin() const { return const_reverse_iterator(begin()); } - inline const_reverse_iterator rend() const { return const_reverse_iterator(end()); } + public: + // STL container idioms + typedef unsigned char value_type; + typedef unsigned char* pointer; + typedef const char* const_pointer; + typedef char& reference; + typedef const char& const_reference; + typedef char* iterator; + typedef const char* const_iterator; + typedef unsigned int size_type; + typedef int difference_type; + typedef std::reverse_iterator reverse_iterator; + typedef std::reverse_iterator const_reverse_iterator; + inline iterator begin() + { + return _b; + } + inline iterator end() + { + return (_b + _l); + } + inline const_iterator begin() const + { + return _b; + } + inline const_iterator end() const + { + return (_b + _l); + } + inline reverse_iterator rbegin() + { + return reverse_iterator(begin()); + } + inline reverse_iterator rend() + { + return reverse_iterator(end()); + } + inline const_reverse_iterator rbegin() const + { + return const_reverse_iterator(begin()); + } + inline const_reverse_iterator rend() const + { + return const_reverse_iterator(end()); + } - Buffer() : - _l(0) - { - } + Buffer() : _l(0) + { + } - Buffer(unsigned int l) - { - if (l > C) { - throw ZT_EXCEPTION_OUT_OF_BOUNDS; - } - _l = l; - } + Buffer(unsigned int l) + { + if (l > C) { + throw ZT_EXCEPTION_OUT_OF_BOUNDS; + } + _l = l; + } - template - Buffer(const Buffer &b) - { - *this = b; - } + template Buffer(const Buffer& b) + { + *this = b; + } - Buffer(const void *b,unsigned int l) - { - copyFrom(b,l); - } + Buffer(const void* b, unsigned int l) + { + copyFrom(b, l); + } - template - inline Buffer &operator=(const Buffer &b) - { - if (unlikely(b._l > C)) { - throw ZT_EXCEPTION_OUT_OF_BOUNDS; - } - if (C2 == C) { - memcpy(this,&b,sizeof(Buffer)); - } else { - memcpy(_b,b._b,_l = b._l); - } - return *this; - } + template inline Buffer& operator=(const Buffer& b) + { + if (unlikely(b._l > C)) { + throw ZT_EXCEPTION_OUT_OF_BOUNDS; + } + if (C2 == C) { + memcpy(this, &b, sizeof(Buffer)); + } + else { + memcpy(_b, b._b, _l = b._l); + } + return *this; + } - inline void copyFrom(const void *b,unsigned int l) - { - if (unlikely(l > C)) { - throw ZT_EXCEPTION_OUT_OF_BOUNDS; - } - memcpy(_b,b,l); - _l = l; - } + inline void copyFrom(const void* b, unsigned int l) + { + if (unlikely(l > C)) { + throw ZT_EXCEPTION_OUT_OF_BOUNDS; + } + memcpy(_b, b, l); + _l = l; + } - unsigned char operator[](const unsigned int i) const - { - if (unlikely(i >= _l)) { - throw ZT_EXCEPTION_OUT_OF_BOUNDS; - } - return (unsigned char)_b[i]; - } + unsigned char operator[](const unsigned int i) const + { + if (unlikely(i >= _l)) { + throw ZT_EXCEPTION_OUT_OF_BOUNDS; + } + return (unsigned char)_b[i]; + } - unsigned char &operator[](const unsigned int i) - { - if (unlikely(i >= _l)) { - throw ZT_EXCEPTION_OUT_OF_BOUNDS; - } - return ((unsigned char *)_b)[i]; - } + unsigned char& operator[](const unsigned int i) + { + if (unlikely(i >= _l)) { + throw ZT_EXCEPTION_OUT_OF_BOUNDS; + } + return ((unsigned char*)_b)[i]; + } - /** - * Get a raw pointer to a field with bounds checking - * - * This isn't perfectly safe in that the caller could still overflow - * the pointer, but its use provides both a sanity check and - * documentation / reminder to the calling code to treat the returned - * pointer as being of size [l]. - * - * @param i Index of field in buffer - * @param l Length of field in bytes - * @return Pointer to field data - * @throws std::out_of_range Field extends beyond data size - */ - unsigned char *field(unsigned int i,unsigned int l) - { - if (unlikely((i + l) > _l)) { - throw ZT_EXCEPTION_OUT_OF_BOUNDS; - } - return (unsigned char *)(_b + i); - } - const unsigned char *field(unsigned int i,unsigned int l) const - { - if (unlikely((i + l) > _l)) { - throw ZT_EXCEPTION_OUT_OF_BOUNDS; - } - return (const unsigned char *)(_b + i); - } + /** + * Get a raw pointer to a field with bounds checking + * + * This isn't perfectly safe in that the caller could still overflow + * the pointer, but its use provides both a sanity check and + * documentation / reminder to the calling code to treat the returned + * pointer as being of size [l]. + * + * @param i Index of field in buffer + * @param l Length of field in bytes + * @return Pointer to field data + * @throws std::out_of_range Field extends beyond data size + */ + unsigned char* field(unsigned int i, unsigned int l) + { + if (unlikely((i + l) > _l)) { + throw ZT_EXCEPTION_OUT_OF_BOUNDS; + } + return (unsigned char*)(_b + i); + } + const unsigned char* field(unsigned int i, unsigned int l) const + { + if (unlikely((i + l) > _l)) { + throw ZT_EXCEPTION_OUT_OF_BOUNDS; + } + return (const unsigned char*)(_b + i); + } - /** - * Place a primitive integer value at a given position - * - * @param i Index to place value - * @param v Value - * @tparam T Integer type (e.g. uint16_t, int64_t) - */ - template - inline void setAt(unsigned int i,const T v) - { - if (unlikely((i + sizeof(T)) > _l)) { - throw ZT_EXCEPTION_OUT_OF_BOUNDS; - } + /** + * Place a primitive integer value at a given position + * + * @param i Index to place value + * @param v Value + * @tparam T Integer type (e.g. uint16_t, int64_t) + */ + template inline void setAt(unsigned int i, const T v) + { + if (unlikely((i + sizeof(T)) > _l)) { + throw ZT_EXCEPTION_OUT_OF_BOUNDS; + } #ifdef ZT_NO_TYPE_PUNNING - uint8_t *p = reinterpret_cast(_b + i); - for(unsigned int x=1;x<=sizeof(T);++x) { - *(p++) = (uint8_t)(v >> (8 * (sizeof(T) - x))); - } + uint8_t* p = reinterpret_cast(_b + i); + for (unsigned int x = 1; x <= sizeof(T); ++x) { + *(p++) = (uint8_t)(v >> (8 * (sizeof(T) - x))); + } #else - T *const ZT_VAR_MAY_ALIAS p = reinterpret_cast(_b + i); - *p = Utils::hton(v); + T* const ZT_VAR_MAY_ALIAS p = reinterpret_cast(_b + i); + *p = Utils::hton(v); #endif - } + } - /** - * Get a primitive integer value at a given position - * - * @param i Index to get integer - * @tparam T Integer type (e.g. uint16_t, int64_t) - * @return Integer value - */ - template - inline T at(unsigned int i) const - { - if (unlikely((i + sizeof(T)) > _l)) { - throw ZT_EXCEPTION_OUT_OF_BOUNDS; - } + /** + * Get a primitive integer value at a given position + * + * @param i Index to get integer + * @tparam T Integer type (e.g. uint16_t, int64_t) + * @return Integer value + */ + template inline T at(unsigned int i) const + { + if (unlikely((i + sizeof(T)) > _l)) { + throw ZT_EXCEPTION_OUT_OF_BOUNDS; + } #ifdef ZT_NO_TYPE_PUNNING - T v = 0; - const uint8_t *p = reinterpret_cast(_b + i); - for(unsigned int x=0;x(_b + i); + for (unsigned int x = 0; x < sizeof(T); ++x) { + v <<= 8; + v |= (T) * (p++); + } + return v; #else - const T *const ZT_VAR_MAY_ALIAS p = reinterpret_cast(_b + i); - return Utils::ntoh(*p); + const T* const ZT_VAR_MAY_ALIAS p = reinterpret_cast(_b + i); + return Utils::ntoh(*p); #endif - } + } - /** - * Append an integer type to this buffer - * - * @param v Value to append - * @tparam T Integer type (e.g. uint16_t, int64_t) - * @throws std::out_of_range Attempt to append beyond capacity - */ - template - inline void append(const T v) - { - if (unlikely((_l + sizeof(T)) > C)) { - throw ZT_EXCEPTION_OUT_OF_BOUNDS; - } + /** + * Append an integer type to this buffer + * + * @param v Value to append + * @tparam T Integer type (e.g. uint16_t, int64_t) + * @throws std::out_of_range Attempt to append beyond capacity + */ + template inline void append(const T v) + { + if (unlikely((_l + sizeof(T)) > C)) { + throw ZT_EXCEPTION_OUT_OF_BOUNDS; + } #ifdef ZT_NO_TYPE_PUNNING - uint8_t *p = reinterpret_cast(_b + _l); - for(unsigned int x=1;x<=sizeof(T);++x) { - *(p++) = (uint8_t)(v >> (8 * (sizeof(T) - x))); - } + uint8_t* p = reinterpret_cast(_b + _l); + for (unsigned int x = 1; x <= sizeof(T); ++x) { + *(p++) = (uint8_t)(v >> (8 * (sizeof(T) - x))); + } #else - T *const ZT_VAR_MAY_ALIAS p = reinterpret_cast(_b + _l); - *p = Utils::hton(v); + T* const ZT_VAR_MAY_ALIAS p = reinterpret_cast(_b + _l); + *p = Utils::hton(v); #endif - _l += sizeof(T); - } + _l += sizeof(T); + } - /** - * Append a run of bytes - * - * @param c Character value to append - * @param n Number of times to append - * @throws std::out_of_range Attempt to append beyond capacity - */ - inline void append(unsigned char c,unsigned int n) - { - if (unlikely((_l + n) > C)) { - throw ZT_EXCEPTION_OUT_OF_BOUNDS; - } - for(unsigned int i=0;i C)) { + throw ZT_EXCEPTION_OUT_OF_BOUNDS; + } + for (unsigned int i = 0; i < n; ++i) { + _b[_l++] = (char)c; + } + } - /** - * Append secure random bytes - * - * @param n Number of random bytes to append - */ - inline void appendRandom(unsigned int n) - { - if (unlikely((_l + n) > C)) { - throw ZT_EXCEPTION_OUT_OF_BOUNDS; - } - Utils::getSecureRandom(_b + _l,n); - _l += n; - } + /** + * Append secure random bytes + * + * @param n Number of random bytes to append + */ + inline void appendRandom(unsigned int n) + { + if (unlikely((_l + n) > C)) { + throw ZT_EXCEPTION_OUT_OF_BOUNDS; + } + Utils::getSecureRandom(_b + _l, n); + _l += n; + } - /** - * Append a C-array of bytes - * - * @param b Data - * @param l Length - * @throws std::out_of_range Attempt to append beyond capacity - */ - inline void append(const void *b,unsigned int l) - { - if (unlikely((_l + l) > C)) { - throw ZT_EXCEPTION_OUT_OF_BOUNDS; - } - memcpy(_b + _l,b,l); - _l += l; - } + /** + * Append a C-array of bytes + * + * @param b Data + * @param l Length + * @throws std::out_of_range Attempt to append beyond capacity + */ + inline void append(const void* b, unsigned int l) + { + if (unlikely((_l + l) > C)) { + throw ZT_EXCEPTION_OUT_OF_BOUNDS; + } + memcpy(_b + _l, b, l); + _l += l; + } - /** - * Append a C string including null termination byte - * - * @param s C string - * @throws std::out_of_range Attempt to append beyond capacity - */ - inline void appendCString(const char *s) - { - for(;;) { - if (unlikely(_l >= C)) { - throw ZT_EXCEPTION_OUT_OF_BOUNDS; - } - if (!(_b[_l++] = *(s++))) { - break; - } - } - } + /** + * Append a C string including null termination byte + * + * @param s C string + * @throws std::out_of_range Attempt to append beyond capacity + */ + inline void appendCString(const char* s) + { + for (;;) { + if (unlikely(_l >= C)) { + throw ZT_EXCEPTION_OUT_OF_BOUNDS; + } + if (! (_b[_l++] = *(s++))) { + break; + } + } + } - /** - * Append a buffer - * - * @param b Buffer to append - * @tparam C2 Capacity of second buffer (typically inferred) - * @throws std::out_of_range Attempt to append beyond capacity - */ - template - inline void append(const Buffer &b) - { - append(b._b,b._l); - } + /** + * Append a buffer + * + * @param b Buffer to append + * @tparam C2 Capacity of second buffer (typically inferred) + * @throws std::out_of_range Attempt to append beyond capacity + */ + template inline void append(const Buffer& b) + { + append(b._b, b._l); + } - /** - * Increment size and return pointer to field of specified size - * - * Nothing is actually written to the memory. This is a shortcut - * for addSize() followed by field() to reference the previous - * position and the new size. - * - * @param l Length of field to append - * @return Pointer to beginning of appended field of length 'l' - */ - inline char *appendField(unsigned int l) - { - if (unlikely((_l + l) > C)) { - throw ZT_EXCEPTION_OUT_OF_BOUNDS; - } - char *r = _b + _l; - _l += l; - return r; - } + /** + * Increment size and return pointer to field of specified size + * + * Nothing is actually written to the memory. This is a shortcut + * for addSize() followed by field() to reference the previous + * position and the new size. + * + * @param l Length of field to append + * @return Pointer to beginning of appended field of length 'l' + */ + inline char* appendField(unsigned int l) + { + if (unlikely((_l + l) > C)) { + throw ZT_EXCEPTION_OUT_OF_BOUNDS; + } + char* r = _b + _l; + _l += l; + return r; + } - /** - * Increment size by a given number of bytes - * - * The contents of new space are undefined. - * - * @param i Bytes to increment - * @throws std::out_of_range Capacity exceeded - */ - inline void addSize(unsigned int i) - { - if (unlikely((i + _l) > C)) { - throw ZT_EXCEPTION_OUT_OF_BOUNDS; - } - _l += i; - } + /** + * Increment size by a given number of bytes + * + * The contents of new space are undefined. + * + * @param i Bytes to increment + * @throws std::out_of_range Capacity exceeded + */ + inline void addSize(unsigned int i) + { + if (unlikely((i + _l) > C)) { + throw ZT_EXCEPTION_OUT_OF_BOUNDS; + } + _l += i; + } - /** - * Set size of data in buffer - * - * The contents of new space are undefined. - * - * @param i New size - * @throws std::out_of_range Size larger than capacity - */ - inline void setSize(const unsigned int i) - { - if (unlikely(i > C)) { - throw ZT_EXCEPTION_OUT_OF_BOUNDS; - } - _l = i; - } + /** + * Set size of data in buffer + * + * The contents of new space are undefined. + * + * @param i New size + * @throws std::out_of_range Size larger than capacity + */ + inline void setSize(const unsigned int i) + { + if (unlikely(i > C)) { + throw ZT_EXCEPTION_OUT_OF_BOUNDS; + } + _l = i; + } - /** - * Move everything after 'at' to the buffer's front and truncate - * - * @param at Truncate before this position - * @throws std::out_of_range Position is beyond size of buffer - */ - inline void behead(const unsigned int at) - { - if (!at) { - return; - } - if (unlikely(at > _l)) { - throw ZT_EXCEPTION_OUT_OF_BOUNDS; - } - ::memmove(_b,_b + at,_l -= at); - } + /** + * Move everything after 'at' to the buffer's front and truncate + * + * @param at Truncate before this position + * @throws std::out_of_range Position is beyond size of buffer + */ + inline void behead(const unsigned int at) + { + if (! at) { + return; + } + if (unlikely(at > _l)) { + throw ZT_EXCEPTION_OUT_OF_BOUNDS; + } + ::memmove(_b, _b + at, _l -= at); + } - /** - * Erase something from the middle of the buffer - * - * @param start Starting position - * @param length Length of block to erase - * @throws std::out_of_range Position plus length is beyond size of buffer - */ - inline void erase(const unsigned int at,const unsigned int length) - { - const unsigned int endr = at + length; - if (unlikely(endr > _l)) { - throw ZT_EXCEPTION_OUT_OF_BOUNDS; - } - ::memmove(_b + at,_b + endr,_l - endr); - _l -= length; - } + /** + * Erase something from the middle of the buffer + * + * @param start Starting position + * @param length Length of block to erase + * @throws std::out_of_range Position plus length is beyond size of buffer + */ + inline void erase(const unsigned int at, const unsigned int length) + { + const unsigned int endr = at + length; + if (unlikely(endr > _l)) { + throw ZT_EXCEPTION_OUT_OF_BOUNDS; + } + ::memmove(_b + at, _b + endr, _l - endr); + _l -= length; + } - /** - * Set buffer data length to zero - */ - inline void clear() { _l = 0; } + /** + * Set buffer data length to zero + */ + inline void clear() + { + _l = 0; + } - /** - * Zero buffer up to size() - */ - inline void zero() { memset(_b,0,_l); } + /** + * Zero buffer up to size() + */ + inline void zero() + { + memset(_b, 0, _l); + } - /** - * Zero unused capacity area - */ - inline void zeroUnused() { memset(_b + _l,0,C - _l); } + /** + * Zero unused capacity area + */ + inline void zeroUnused() + { + memset(_b + _l, 0, C - _l); + } - /** - * Unconditionally and securely zero buffer's underlying memory - */ - inline void burn() { Utils::burn(_b,sizeof(_b)); } + /** + * Unconditionally and securely zero buffer's underlying memory + */ + inline void burn() + { + Utils::burn(_b, sizeof(_b)); + } - /** - * @return Constant pointer to data in buffer - */ - inline const void *data() const { return _b; } + /** + * @return Constant pointer to data in buffer + */ + inline const void* data() const + { + return _b; + } - /** - * @return Non-constant pointer to data in buffer - */ - inline void *unsafeData() { return _b; } + /** + * @return Non-constant pointer to data in buffer + */ + inline void* unsafeData() + { + return _b; + } - /** - * @return Size of data in buffer - */ - inline unsigned int size() const { return _l; } + /** + * @return Size of data in buffer + */ + inline unsigned int size() const + { + return _l; + } - /** - * @return Capacity of buffer - */ - inline unsigned int capacity() const { return C; } + /** + * @return Capacity of buffer + */ + inline unsigned int capacity() const + { + return C; + } - template - inline bool operator==(const Buffer &b) const - { - return ((_l == b._l)&&(!memcmp(_b,b._b,_l))); - } - template - inline bool operator!=(const Buffer &b) const - { - return ((_l != b._l)||(memcmp(_b,b._b,_l))); - } - template - inline bool operator<(const Buffer &b) const - { - return (memcmp(_b,b._b,std::min(_l,b._l)) < 0); - } - template - inline bool operator>(const Buffer &b) const - { - return (b < *this); - } - template - inline bool operator<=(const Buffer &b) const - { - return !(b < *this); - } - template - inline bool operator>=(const Buffer &b) const - { - return !(*this < b); - } + template inline bool operator==(const Buffer& b) const + { + return ((_l == b._l) && (! memcmp(_b, b._b, _l))); + } + template inline bool operator!=(const Buffer& b) const + { + return ((_l != b._l) || (memcmp(_b, b._b, _l))); + } + template inline bool operator<(const Buffer& b) const + { + return (memcmp(_b, b._b, std::min(_l, b._l)) < 0); + } + template inline bool operator>(const Buffer& b) const + { + return (b < *this); + } + template inline bool operator<=(const Buffer& b) const + { + return ! (b < *this); + } + template inline bool operator>=(const Buffer& b) const + { + return ! (*this < b); + } -private: - char ZT_VAR_MAY_ALIAS _b[C]; - unsigned int _l; + private: + char ZT_VAR_MAY_ALIAS _b[C]; + unsigned int _l; }; -} // namespace ZeroTier +} // namespace ZeroTier #endif diff --git a/node/C25519.cpp b/node/C25519.cpp deleted file mode 100644 index f425540d..00000000 --- a/node/C25519.cpp +++ /dev/null @@ -1,2642 +0,0 @@ -/* -Matthew Dempsky -Public domain. -Derived from public domain code by D. J. Bernstein. -*/ - -// Modified very slightly for ZeroTier One by Adam Ierymenko -// This code remains in the public domain. - -#include -#include -#include - -#include "Constants.hpp" -#include "C25519.hpp" -#include "SHA512.hpp" -#include "Buffer.hpp" -#include "Hashtable.hpp" -#include "Mutex.hpp" - -#ifdef __WINDOWS__ -#pragma warning(disable: 4146) -#endif - -#ifdef __GNUC__ -#pragma GCC diagnostic ignored "-Wunused-function" -#endif - -namespace { - -#define crypto_int32 int32_t -#define crypto_uint32 uint32_t -#define crypto_int64 int64_t -#define crypto_uint64 uint64_t -#define crypto_hash_sha512_BYTES 64 - -////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////// - -typedef uint8_t u8; -typedef int32_t s32; -typedef int64_t limb; - -static inline void fsum(limb *output, const limb *in) { - unsigned i; - for (i = 0; i < 10; i += 2) { - output[0+i] = output[0+i] + in[0+i]; - output[1+i] = output[1+i] + in[1+i]; - } -} - -static inline void fdifference(limb *output, const limb *in) { - unsigned i; - for (i = 0; i < 10; ++i) { - output[i] = in[i] - output[i]; - } -} - -static inline void fscalar_product(limb *output, const limb *in, const limb scalar) { - unsigned i; - for (i = 0; i < 10; ++i) { - output[i] = in[i] * scalar; - } -} - -static inline void fproduct(limb *output, const limb *in2, const limb *in) { - output[0] = ((limb) ((s32) in2[0])) * ((s32) in[0]); - output[1] = ((limb) ((s32) in2[0])) * ((s32) in[1]) + - ((limb) ((s32) in2[1])) * ((s32) in[0]); - output[2] = 2 * ((limb) ((s32) in2[1])) * ((s32) in[1]) + - ((limb) ((s32) in2[0])) * ((s32) in[2]) + - ((limb) ((s32) in2[2])) * ((s32) in[0]); - output[3] = ((limb) ((s32) in2[1])) * ((s32) in[2]) + - ((limb) ((s32) in2[2])) * ((s32) in[1]) + - ((limb) ((s32) in2[0])) * ((s32) in[3]) + - ((limb) ((s32) in2[3])) * ((s32) in[0]); - output[4] = ((limb) ((s32) in2[2])) * ((s32) in[2]) + - 2 * (((limb) ((s32) in2[1])) * ((s32) in[3]) + - ((limb) ((s32) in2[3])) * ((s32) in[1])) + - ((limb) ((s32) in2[0])) * ((s32) in[4]) + - ((limb) ((s32) in2[4])) * ((s32) in[0]); - output[5] = ((limb) ((s32) in2[2])) * ((s32) in[3]) + - ((limb) ((s32) in2[3])) * ((s32) in[2]) + - ((limb) ((s32) in2[1])) * ((s32) in[4]) + - ((limb) ((s32) in2[4])) * ((s32) in[1]) + - ((limb) ((s32) in2[0])) * ((s32) in[5]) + - ((limb) ((s32) in2[5])) * ((s32) in[0]); - output[6] = 2 * (((limb) ((s32) in2[3])) * ((s32) in[3]) + - ((limb) ((s32) in2[1])) * ((s32) in[5]) + - ((limb) ((s32) in2[5])) * ((s32) in[1])) + - ((limb) ((s32) in2[2])) * ((s32) in[4]) + - ((limb) ((s32) in2[4])) * ((s32) in[2]) + - ((limb) ((s32) in2[0])) * ((s32) in[6]) + - ((limb) ((s32) in2[6])) * ((s32) in[0]); - output[7] = ((limb) ((s32) in2[3])) * ((s32) in[4]) + - ((limb) ((s32) in2[4])) * ((s32) in[3]) + - ((limb) ((s32) in2[2])) * ((s32) in[5]) + - ((limb) ((s32) in2[5])) * ((s32) in[2]) + - ((limb) ((s32) in2[1])) * ((s32) in[6]) + - ((limb) ((s32) in2[6])) * ((s32) in[1]) + - ((limb) ((s32) in2[0])) * ((s32) in[7]) + - ((limb) ((s32) in2[7])) * ((s32) in[0]); - output[8] = ((limb) ((s32) in2[4])) * ((s32) in[4]) + - 2 * (((limb) ((s32) in2[3])) * ((s32) in[5]) + - ((limb) ((s32) in2[5])) * ((s32) in[3]) + - ((limb) ((s32) in2[1])) * ((s32) in[7]) + - ((limb) ((s32) in2[7])) * ((s32) in[1])) + - ((limb) ((s32) in2[2])) * ((s32) in[6]) + - ((limb) ((s32) in2[6])) * ((s32) in[2]) + - ((limb) ((s32) in2[0])) * ((s32) in[8]) + - ((limb) ((s32) in2[8])) * ((s32) in[0]); - output[9] = ((limb) ((s32) in2[4])) * ((s32) in[5]) + - ((limb) ((s32) in2[5])) * ((s32) in[4]) + - ((limb) ((s32) in2[3])) * ((s32) in[6]) + - ((limb) ((s32) in2[6])) * ((s32) in[3]) + - ((limb) ((s32) in2[2])) * ((s32) in[7]) + - ((limb) ((s32) in2[7])) * ((s32) in[2]) + - ((limb) ((s32) in2[1])) * ((s32) in[8]) + - ((limb) ((s32) in2[8])) * ((s32) in[1]) + - ((limb) ((s32) in2[0])) * ((s32) in[9]) + - ((limb) ((s32) in2[9])) * ((s32) in[0]); - output[10] = 2 * (((limb) ((s32) in2[5])) * ((s32) in[5]) + - ((limb) ((s32) in2[3])) * ((s32) in[7]) + - ((limb) ((s32) in2[7])) * ((s32) in[3]) + - ((limb) ((s32) in2[1])) * ((s32) in[9]) + - ((limb) ((s32) in2[9])) * ((s32) in[1])) + - ((limb) ((s32) in2[4])) * ((s32) in[6]) + - ((limb) ((s32) in2[6])) * ((s32) in[4]) + - ((limb) ((s32) in2[2])) * ((s32) in[8]) + - ((limb) ((s32) in2[8])) * ((s32) in[2]); - output[11] = ((limb) ((s32) in2[5])) * ((s32) in[6]) + - ((limb) ((s32) in2[6])) * ((s32) in[5]) + - ((limb) ((s32) in2[4])) * ((s32) in[7]) + - ((limb) ((s32) in2[7])) * ((s32) in[4]) + - ((limb) ((s32) in2[3])) * ((s32) in[8]) + - ((limb) ((s32) in2[8])) * ((s32) in[3]) + - ((limb) ((s32) in2[2])) * ((s32) in[9]) + - ((limb) ((s32) in2[9])) * ((s32) in[2]); - output[12] = ((limb) ((s32) in2[6])) * ((s32) in[6]) + - 2 * (((limb) ((s32) in2[5])) * ((s32) in[7]) + - ((limb) ((s32) in2[7])) * ((s32) in[5]) + - ((limb) ((s32) in2[3])) * ((s32) in[9]) + - ((limb) ((s32) in2[9])) * ((s32) in[3])) + - ((limb) ((s32) in2[4])) * ((s32) in[8]) + - ((limb) ((s32) in2[8])) * ((s32) in[4]); - output[13] = ((limb) ((s32) in2[6])) * ((s32) in[7]) + - ((limb) ((s32) in2[7])) * ((s32) in[6]) + - ((limb) ((s32) in2[5])) * ((s32) in[8]) + - ((limb) ((s32) in2[8])) * ((s32) in[5]) + - ((limb) ((s32) in2[4])) * ((s32) in[9]) + - ((limb) ((s32) in2[9])) * ((s32) in[4]); - output[14] = 2 * (((limb) ((s32) in2[7])) * ((s32) in[7]) + - ((limb) ((s32) in2[5])) * ((s32) in[9]) + - ((limb) ((s32) in2[9])) * ((s32) in[5])) + - ((limb) ((s32) in2[6])) * ((s32) in[8]) + - ((limb) ((s32) in2[8])) * ((s32) in[6]); - output[15] = ((limb) ((s32) in2[7])) * ((s32) in[8]) + - ((limb) ((s32) in2[8])) * ((s32) in[7]) + - ((limb) ((s32) in2[6])) * ((s32) in[9]) + - ((limb) ((s32) in2[9])) * ((s32) in[6]); - output[16] = ((limb) ((s32) in2[8])) * ((s32) in[8]) + - 2 * (((limb) ((s32) in2[7])) * ((s32) in[9]) + - ((limb) ((s32) in2[9])) * ((s32) in[7])); - output[17] = ((limb) ((s32) in2[8])) * ((s32) in[9]) + - ((limb) ((s32) in2[9])) * ((s32) in[8]); - output[18] = 2 * ((limb) ((s32) in2[9])) * ((s32) in[9]); -} - -static inline void freduce_degree(limb *output) { - output[8] += output[18] << 4; - output[8] += output[18] << 1; - output[8] += output[18]; - output[7] += output[17] << 4; - output[7] += output[17] << 1; - output[7] += output[17]; - output[6] += output[16] << 4; - output[6] += output[16] << 1; - output[6] += output[16]; - output[5] += output[15] << 4; - output[5] += output[15] << 1; - output[5] += output[15]; - output[4] += output[14] << 4; - output[4] += output[14] << 1; - output[4] += output[14]; - output[3] += output[13] << 4; - output[3] += output[13] << 1; - output[3] += output[13]; - output[2] += output[12] << 4; - output[2] += output[12] << 1; - output[2] += output[12]; - output[1] += output[11] << 4; - output[1] += output[11] << 1; - output[1] += output[11]; - output[0] += output[10] << 4; - output[0] += output[10] << 1; - output[0] += output[10]; -} - -#if (-1 & 3) != 3 -#error "This code only works on a two's complement system" -#endif - -static inline limb div_by_2_26(const limb v) -{ - /* High word of v; no shift needed. */ - const uint32_t highword = (uint32_t) (((uint64_t) v) >> 32); - /* Set to all 1s if v was negative; else set to 0s. */ - const int32_t sign = ((int32_t) highword) >> 31; - /* Set to 0x3ffffff if v was negative; else set to 0. */ - const int32_t roundoff = ((uint32_t) sign) >> 6; - /* Should return v / (1<<26) */ - return (v + roundoff) >> 26; -} - -static inline limb div_by_2_25(const limb v) -{ - /* High word of v; no shift needed*/ - const uint32_t highword = (uint32_t) (((uint64_t) v) >> 32); - /* Set to all 1s if v was negative; else set to 0s. */ - const int32_t sign = ((int32_t) highword) >> 31; - /* Set to 0x1ffffff if v was negative; else set to 0. */ - const int32_t roundoff = ((uint32_t) sign) >> 7; - /* Should return v / (1<<25) */ - return (v + roundoff) >> 25; -} - -static inline void freduce_coefficients(limb *output) { - unsigned i; - - output[10] = 0; - - for (i = 0; i < 10; i += 2) { - limb over = div_by_2_26(output[i]); - /* The entry condition (that |output[i]| < 280*2^54) means that over is, at - * most, 280*2^28 in the first iteration of this loop. This is added to the - * next limb and we can approximate the resulting bound of that limb by - * 281*2^54. */ - output[i] -= over << 26; - output[i+1] += over; - - /* For the first iteration, |output[i+1]| < 281*2^54, thus |over| < - * 281*2^29. When this is added to the next limb, the resulting bound can - * be approximated as 281*2^54. - * - * For subsequent iterations of the loop, 281*2^54 remains a conservative - * bound and no overflow occurs. */ - over = div_by_2_25(output[i+1]); - output[i+1] -= over << 25; - output[i+2] += over; - } - /* Now |output[10]| < 281*2^29 and all other coefficients are reduced. */ - output[0] += output[10] << 4; - output[0] += output[10] << 1; - output[0] += output[10]; - - output[10] = 0; - - /* Now output[1..9] are reduced, and |output[0]| < 2^26 + 19*281*2^29 - * So |over| will be no more than 2^16. */ - { - limb over = div_by_2_26(output[0]); - output[0] -= over << 26; - output[1] += over; - } - - /* Now output[0,2..9] are reduced, and |output[1]| < 2^25 + 2^16 < 2^26. The - * bound on |output[1]| is sufficient to meet our needs. */ -} - -static inline void fmul(limb *output, const limb *in, const limb *in2) { - limb t[19]; - fproduct(t, in, in2); - /* |t[i]| < 14*2^54 */ - freduce_degree(t); - freduce_coefficients(t); - /* |t[i]| < 2^26 */ - memcpy(output, t, sizeof(limb) * 10); -} - -static inline void fsquare_inner(limb *output, const limb *in) { - output[0] = ((limb) ((s32) in[0])) * ((s32) in[0]); - output[1] = 2 * ((limb) ((s32) in[0])) * ((s32) in[1]); - output[2] = 2 * (((limb) ((s32) in[1])) * ((s32) in[1]) + - ((limb) ((s32) in[0])) * ((s32) in[2])); - output[3] = 2 * (((limb) ((s32) in[1])) * ((s32) in[2]) + - ((limb) ((s32) in[0])) * ((s32) in[3])); - output[4] = ((limb) ((s32) in[2])) * ((s32) in[2]) + - 4 * ((limb) ((s32) in[1])) * ((s32) in[3]) + - 2 * ((limb) ((s32) in[0])) * ((s32) in[4]); - output[5] = 2 * (((limb) ((s32) in[2])) * ((s32) in[3]) + - ((limb) ((s32) in[1])) * ((s32) in[4]) + - ((limb) ((s32) in[0])) * ((s32) in[5])); - output[6] = 2 * (((limb) ((s32) in[3])) * ((s32) in[3]) + - ((limb) ((s32) in[2])) * ((s32) in[4]) + - ((limb) ((s32) in[0])) * ((s32) in[6]) + - 2 * ((limb) ((s32) in[1])) * ((s32) in[5])); - output[7] = 2 * (((limb) ((s32) in[3])) * ((s32) in[4]) + - ((limb) ((s32) in[2])) * ((s32) in[5]) + - ((limb) ((s32) in[1])) * ((s32) in[6]) + - ((limb) ((s32) in[0])) * ((s32) in[7])); - output[8] = ((limb) ((s32) in[4])) * ((s32) in[4]) + - 2 * (((limb) ((s32) in[2])) * ((s32) in[6]) + - ((limb) ((s32) in[0])) * ((s32) in[8]) + - 2 * (((limb) ((s32) in[1])) * ((s32) in[7]) + - ((limb) ((s32) in[3])) * ((s32) in[5]))); - output[9] = 2 * (((limb) ((s32) in[4])) * ((s32) in[5]) + - ((limb) ((s32) in[3])) * ((s32) in[6]) + - ((limb) ((s32) in[2])) * ((s32) in[7]) + - ((limb) ((s32) in[1])) * ((s32) in[8]) + - ((limb) ((s32) in[0])) * ((s32) in[9])); - output[10] = 2 * (((limb) ((s32) in[5])) * ((s32) in[5]) + - ((limb) ((s32) in[4])) * ((s32) in[6]) + - ((limb) ((s32) in[2])) * ((s32) in[8]) + - 2 * (((limb) ((s32) in[3])) * ((s32) in[7]) + - ((limb) ((s32) in[1])) * ((s32) in[9]))); - output[11] = 2 * (((limb) ((s32) in[5])) * ((s32) in[6]) + - ((limb) ((s32) in[4])) * ((s32) in[7]) + - ((limb) ((s32) in[3])) * ((s32) in[8]) + - ((limb) ((s32) in[2])) * ((s32) in[9])); - output[12] = ((limb) ((s32) in[6])) * ((s32) in[6]) + - 2 * (((limb) ((s32) in[4])) * ((s32) in[8]) + - 2 * (((limb) ((s32) in[5])) * ((s32) in[7]) + - ((limb) ((s32) in[3])) * ((s32) in[9]))); - output[13] = 2 * (((limb) ((s32) in[6])) * ((s32) in[7]) + - ((limb) ((s32) in[5])) * ((s32) in[8]) + - ((limb) ((s32) in[4])) * ((s32) in[9])); - output[14] = 2 * (((limb) ((s32) in[7])) * ((s32) in[7]) + - ((limb) ((s32) in[6])) * ((s32) in[8]) + - 2 * ((limb) ((s32) in[5])) * ((s32) in[9])); - output[15] = 2 * (((limb) ((s32) in[7])) * ((s32) in[8]) + - ((limb) ((s32) in[6])) * ((s32) in[9])); - output[16] = ((limb) ((s32) in[8])) * ((s32) in[8]) + - 4 * ((limb) ((s32) in[7])) * ((s32) in[9]); - output[17] = 2 * ((limb) ((s32) in[8])) * ((s32) in[9]); - output[18] = 2 * ((limb) ((s32) in[9])) * ((s32) in[9]); -} - -static void fsquare(limb *output, const limb *in) { - limb t[19]; - fsquare_inner(t, in); - /* |t[i]| < 14*2^54 because the largest product of two limbs will be < - * 2^(27+27) and fsquare_inner adds together, at most, 14 of those - * products. */ - freduce_degree(t); - freduce_coefficients(t); - /* |t[i]| < 2^26 */ - memcpy(output, t, sizeof(limb) * 10); -} - -static inline void fexpand(limb *output, const u8 *input) { -#define F(n,start,shift,mask) \ - output[n] = ((((limb) input[start + 0]) | \ - ((limb) input[start + 1]) << 8 | \ - ((limb) input[start + 2]) << 16 | \ - ((limb) input[start + 3]) << 24) >> shift) & mask; - F(0, 0, 0, 0x3ffffff); - F(1, 3, 2, 0x1ffffff); - F(2, 6, 3, 0x3ffffff); - F(3, 9, 5, 0x1ffffff); - F(4, 12, 6, 0x3ffffff); - F(5, 16, 0, 0x1ffffff); - F(6, 19, 1, 0x3ffffff); - F(7, 22, 3, 0x1ffffff); - F(8, 25, 4, 0x3ffffff); - F(9, 28, 6, 0x1ffffff); -#undef F -} - -#if (-32 >> 1) != -16 -#error "This code only works when >> does sign-extension on negative numbers" -#endif - -static inline s32 s32_eq(s32 a, s32 b) { - a = ~(a ^ b); - a &= a << 16; - a &= a << 8; - a &= a << 4; - a &= a << 2; - a &= a << 1; - return a >> 31; -} - -static inline s32 s32_gte(s32 a, s32 b) { - a -= b; - /* a >= 0 iff a >= b. */ - return ~(a >> 31); -} - -static inline void fcontract(u8 *output, limb *input_limbs) { - int i; - int j; - s32 input[10]; - s32 mask; - - /* |input_limbs[i]| < 2^26, so it's valid to convert to an s32. */ - for (i = 0; i < 10; i++) { - input[i] = input_limbs[i]; - } - - for (j = 0; j < 2; ++j) { - for (i = 0; i < 9; ++i) { - if ((i & 1) == 1) { - /* This calculation is a time-invariant way to make input[i] - * non-negative by borrowing from the next-larger limb. */ - const s32 mask = input[i] >> 31; - const s32 carry = -((input[i] & mask) >> 25); - input[i] = input[i] + (carry << 25); - input[i+1] = input[i+1] - carry; - } else { - const s32 mask = input[i] >> 31; - const s32 carry = -((input[i] & mask) >> 26); - input[i] = input[i] + (carry << 26); - input[i+1] = input[i+1] - carry; - } - } - - /* There's no greater limb for input[9] to borrow from, but we can multiply - * by 19 and borrow from input[0], which is valid mod 2^255-19. */ - { - const s32 mask = input[9] >> 31; - const s32 carry = -((input[9] & mask) >> 25); - input[9] = input[9] + (carry << 25); - input[0] = input[0] - (carry * 19); - } - - /* After the first iteration, input[1..9] are non-negative and fit within - * 25 or 26 bits, depending on position. However, input[0] may be - * negative. */ - } - - /* The first borrow-propagation pass above ended with every limb - except (possibly) input[0] non-negative. - - If input[0] was negative after the first pass, then it was because of a - carry from input[9]. On entry, input[9] < 2^26 so the carry was, at most, - one, since (2**26-1) >> 25 = 1. Thus input[0] >= -19. - - In the second pass, each limb is decreased by at most one. Thus the second - borrow-propagation pass could only have wrapped around to decrease - input[0] again if the first pass left input[0] negative *and* input[1] - through input[9] were all zero. In that case, input[1] is now 2^25 - 1, - and this last borrow-propagation step will leave input[1] non-negative. */ - { - const s32 mask = input[0] >> 31; - const s32 carry = -((input[0] & mask) >> 26); - input[0] = input[0] + (carry << 26); - input[1] = input[1] - carry; - } - - /* All input[i] are now non-negative. However, there might be values between - * 2^25 and 2^26 in a limb which is, nominally, 25 bits wide. */ - for (j = 0; j < 2; j++) { - for (i = 0; i < 9; i++) { - if ((i & 1) == 1) { - const s32 carry = input[i] >> 25; - input[i] &= 0x1ffffff; - input[i+1] += carry; - } else { - const s32 carry = input[i] >> 26; - input[i] &= 0x3ffffff; - input[i+1] += carry; - } - } - - { - const s32 carry = input[9] >> 25; - input[9] &= 0x1ffffff; - input[0] += 19*carry; - } - } - - /* If the first carry-chain pass, just above, ended up with a carry from - * input[9], and that caused input[0] to be out-of-bounds, then input[0] was - * < 2^26 + 2*19, because the carry was, at most, two. - * - * If the second pass carried from input[9] again then input[0] is < 2*19 and - * the input[9] -> input[0] carry didn't push input[0] out of bounds. */ - - /* It still remains the case that input might be between 2^255-19 and 2^255. - * In this case, input[1..9] must take their maximum value and input[0] must - * be >= (2^255-19) & 0x3ffffff, which is 0x3ffffed. */ - mask = s32_gte(input[0], 0x3ffffed); - for (i = 1; i < 10; i++) { - if ((i & 1) == 1) { - mask &= s32_eq(input[i], 0x1ffffff); - } else { - mask &= s32_eq(input[i], 0x3ffffff); - } - } - - /* mask is either 0xffffffff (if input >= 2^255-19) and zero otherwise. Thus - * this conditionally subtracts 2^255-19. */ - input[0] -= mask & 0x3ffffed; - - for (i = 1; i < 10; i++) { - if ((i & 1) == 1) { - input[i] -= mask & 0x1ffffff; - } else { - input[i] -= mask & 0x3ffffff; - } - } - - input[1] <<= 2; - input[2] <<= 3; - input[3] <<= 5; - input[4] <<= 6; - input[6] <<= 1; - input[7] <<= 3; - input[8] <<= 4; - input[9] <<= 6; -#define F(i, s) \ - output[s+0] |= input[i] & 0xff; \ - output[s+1] = (input[i] >> 8) & 0xff; \ - output[s+2] = (input[i] >> 16) & 0xff; \ - output[s+3] = (input[i] >> 24) & 0xff; - output[0] = 0; - output[16] = 0; - F(0,0); - F(1,3); - F(2,6); - F(3,9); - F(4,12); - F(5,16); - F(6,19); - F(7,22); - F(8,25); - F(9,28); -#undef F -} - -static inline void fmonty(limb *x2, limb *z2, /* output 2Q */ - limb *x3, limb *z3, /* output Q + Q' */ - limb *x, limb *z, /* input Q */ - limb *xprime, limb *zprime, /* input Q' */ - const limb *qmqp /* input Q - Q' */) { - limb origx[10], origxprime[10], zzz[19], xx[19], zz[19], xxprime[19], - zzprime[19], zzzprime[19], xxxprime[19]; - - memcpy(origx, x, 10 * sizeof(limb)); - fsum(x, z); - /* |x[i]| < 2^27 */ - fdifference(z, origx); /* does x - z */ - /* |z[i]| < 2^27 */ - - memcpy(origxprime, xprime, sizeof(limb) * 10); - fsum(xprime, zprime); - /* |xprime[i]| < 2^27 */ - fdifference(zprime, origxprime); - /* |zprime[i]| < 2^27 */ - fproduct(xxprime, xprime, z); - /* |xxprime[i]| < 14*2^54: the largest product of two limbs will be < - * 2^(27+27) and fproduct adds together, at most, 14 of those products. - * (Approximating that to 2^58 doesn't work out.) */ - fproduct(zzprime, x, zprime); - /* |zzprime[i]| < 14*2^54 */ - freduce_degree(xxprime); - freduce_coefficients(xxprime); - /* |xxprime[i]| < 2^26 */ - freduce_degree(zzprime); - freduce_coefficients(zzprime); - /* |zzprime[i]| < 2^26 */ - memcpy(origxprime, xxprime, sizeof(limb) * 10); - fsum(xxprime, zzprime); - /* |xxprime[i]| < 2^27 */ - fdifference(zzprime, origxprime); - /* |zzprime[i]| < 2^27 */ - fsquare(xxxprime, xxprime); - /* |xxxprime[i]| < 2^26 */ - fsquare(zzzprime, zzprime); - /* |zzzprime[i]| < 2^26 */ - fproduct(zzprime, zzzprime, qmqp); - /* |zzprime[i]| < 14*2^52 */ - freduce_degree(zzprime); - freduce_coefficients(zzprime); - /* |zzprime[i]| < 2^26 */ - memcpy(x3, xxxprime, sizeof(limb) * 10); - memcpy(z3, zzprime, sizeof(limb) * 10); - - fsquare(xx, x); - /* |xx[i]| < 2^26 */ - fsquare(zz, z); - /* |zz[i]| < 2^26 */ - fproduct(x2, xx, zz); - /* |x2[i]| < 14*2^52 */ - freduce_degree(x2); - freduce_coefficients(x2); - /* |x2[i]| < 2^26 */ - fdifference(zz, xx); // does zz = xx - zz - /* |zz[i]| < 2^27 */ - memset(zzz + 10, 0, sizeof(limb) * 9); - fscalar_product(zzz, zz, 121665); - /* |zzz[i]| < 2^(27+17) */ - /* No need to call freduce_degree here: - fscalar_product doesn't increase the degree of its input. */ - freduce_coefficients(zzz); - /* |zzz[i]| < 2^26 */ - fsum(zzz, xx); - /* |zzz[i]| < 2^27 */ - fproduct(z2, zz, zzz); - /* |z2[i]| < 14*2^(26+27) */ - freduce_degree(z2); - freduce_coefficients(z2); - /* |z2|i| < 2^26 */ -} - -static inline void swap_conditional(limb a[19], limb b[19], limb iswap) { - unsigned i; - const s32 swap = (s32) -iswap; - - for (i = 0; i < 10; ++i) { - const s32 x = swap & ( ((s32)a[i]) ^ ((s32)b[i]) ); - a[i] = ((s32)a[i]) ^ x; - b[i] = ((s32)b[i]) ^ x; - } -} - -static inline void cmult(limb *resultx, limb *resultz, const u8 *n, const limb *q) { - limb a[19] = {0}, b[19] = {1}, c[19] = {1}, d[19] = {0}; - limb *nqpqx = a, *nqpqz = b, *nqx = c, *nqz = d, *t; - limb e[19] = {0}, f[19] = {1}, g[19] = {0}, h[19] = {1}; - limb *nqpqx2 = e, *nqpqz2 = f, *nqx2 = g, *nqz2 = h; - - unsigned i, j; - - memcpy(nqpqx, q, sizeof(limb) * 10); - - for (i = 0; i < 32; ++i) { - u8 byte = n[31 - i]; - for (j = 0; j < 8; ++j) { - const limb bit = byte >> 7; - - swap_conditional(nqx, nqpqx, bit); - swap_conditional(nqz, nqpqz, bit); - fmonty(nqx2, nqz2, - nqpqx2, nqpqz2, - nqx, nqz, - nqpqx, nqpqz, - q); - swap_conditional(nqx2, nqpqx2, bit); - swap_conditional(nqz2, nqpqz2, bit); - - t = nqx; - nqx = nqx2; - nqx2 = t; - t = nqz; - nqz = nqz2; - nqz2 = t; - t = nqpqx; - nqpqx = nqpqx2; - nqpqx2 = t; - t = nqpqz; - nqpqz = nqpqz2; - nqpqz2 = t; - - byte <<= 1; - } - } - - memcpy(resultx, nqx, sizeof(limb) * 10); - memcpy(resultz, nqz, sizeof(limb) * 10); -} - -static inline void crecip(limb *out, const limb *z) { - limb z2[10]; - limb z9[10]; - limb z11[10]; - limb z2_5_0[10]; - limb z2_10_0[10]; - limb z2_20_0[10]; - limb z2_50_0[10]; - limb z2_100_0[10]; - limb t0[10]; - limb t1[10]; - int i; - - /* 2 */ fsquare(z2,z); - /* 4 */ fsquare(t1,z2); - /* 8 */ fsquare(t0,t1); - /* 9 */ fmul(z9,t0,z); - /* 11 */ fmul(z11,z9,z2); - /* 22 */ fsquare(t0,z11); - /* 2^5 - 2^0 = 31 */ fmul(z2_5_0,t0,z9); - - /* 2^6 - 2^1 */ fsquare(t0,z2_5_0); - /* 2^7 - 2^2 */ fsquare(t1,t0); - /* 2^8 - 2^3 */ fsquare(t0,t1); - /* 2^9 - 2^4 */ fsquare(t1,t0); - /* 2^10 - 2^5 */ fsquare(t0,t1); - /* 2^10 - 2^0 */ fmul(z2_10_0,t0,z2_5_0); - - /* 2^11 - 2^1 */ fsquare(t0,z2_10_0); - /* 2^12 - 2^2 */ fsquare(t1,t0); - /* 2^20 - 2^10 */ for (i = 2;i < 10;i += 2) { fsquare(t0,t1); fsquare(t1,t0); } - /* 2^20 - 2^0 */ fmul(z2_20_0,t1,z2_10_0); - - /* 2^21 - 2^1 */ fsquare(t0,z2_20_0); - /* 2^22 - 2^2 */ fsquare(t1,t0); - /* 2^40 - 2^20 */ for (i = 2;i < 20;i += 2) { fsquare(t0,t1); fsquare(t1,t0); } - /* 2^40 - 2^0 */ fmul(t0,t1,z2_20_0); - - /* 2^41 - 2^1 */ fsquare(t1,t0); - /* 2^42 - 2^2 */ fsquare(t0,t1); - /* 2^50 - 2^10 */ for (i = 2;i < 10;i += 2) { fsquare(t1,t0); fsquare(t0,t1); } - /* 2^50 - 2^0 */ fmul(z2_50_0,t0,z2_10_0); - - /* 2^51 - 2^1 */ fsquare(t0,z2_50_0); - /* 2^52 - 2^2 */ fsquare(t1,t0); - /* 2^100 - 2^50 */ for (i = 2;i < 50;i += 2) { fsquare(t0,t1); fsquare(t1,t0); } - /* 2^100 - 2^0 */ fmul(z2_100_0,t1,z2_50_0); - - /* 2^101 - 2^1 */ fsquare(t1,z2_100_0); - /* 2^102 - 2^2 */ fsquare(t0,t1); - /* 2^200 - 2^100 */ for (i = 2;i < 100;i += 2) { fsquare(t1,t0); fsquare(t0,t1); } - /* 2^200 - 2^0 */ fmul(t1,t0,z2_100_0); - - /* 2^201 - 2^1 */ fsquare(t0,t1); - /* 2^202 - 2^2 */ fsquare(t1,t0); - /* 2^250 - 2^50 */ for (i = 2;i < 50;i += 2) { fsquare(t0,t1); fsquare(t1,t0); } - /* 2^250 - 2^0 */ fmul(t0,t1,z2_50_0); - - /* 2^251 - 2^1 */ fsquare(t1,t0); - /* 2^252 - 2^2 */ fsquare(t0,t1); - /* 2^253 - 2^3 */ fsquare(t1,t0); - /* 2^254 - 2^4 */ fsquare(t0,t1); - /* 2^255 - 2^5 */ fsquare(t1,t0); - /* 2^255 - 21 */ fmul(out,t1,z11); -} - -static void crypto_scalarmult(u8 *mypublic, const u8 *secret, const u8 *basepoint) { - limb bp[10], x[10], z[11], zmone[10]; - uint8_t e[32]; - int i; - - for (i = 0; i < 32; ++i) { - e[i] = secret[i]; - } - e[0] &= 248; - e[31] &= 127; - e[31] |= 64; - - fexpand(bp, basepoint); - cmult(x, z, e, bp); - crecip(zmone, z); - fmul(z, x, zmone); - fcontract(mypublic, z); -} - -static const unsigned char base[32] = {9}; -static inline void crypto_scalarmult_base(unsigned char *q,const unsigned char *n) -{ - crypto_scalarmult(q,n,base); -} - -////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////// - -// Ed25519 ref from: http://bench.cr.yp.to/supercop.html - -typedef struct -{ - crypto_uint32 v[32]; -} -fe25519; - -typedef struct -{ - crypto_uint32 v[32]; -} -sc25519; - -typedef struct -{ - crypto_uint32 v[16]; -} -shortsc25519; - -typedef struct -{ - fe25519 x; - fe25519 y; - fe25519 z; - fe25519 t; -} ge25519; - -#define ge25519_p3 ge25519 - -typedef struct -{ - fe25519 x; - fe25519 z; - fe25519 y; - fe25519 t; -} ge25519_p1p1; - -typedef struct -{ - fe25519 x; - fe25519 y; - fe25519 z; -} ge25519_p2; - -typedef struct -{ - fe25519 x; - fe25519 y; -} ge25519_aff; - -static inline void fe25519_sub(fe25519 *r, const fe25519 *x, const fe25519 *y); - -static inline crypto_uint32 equal(crypto_uint32 a,crypto_uint32 b) /* 16-bit inputs */ -{ - crypto_uint32 x = a ^ b; /* 0: yes; 1..65535: no */ - x -= 1; /* 4294967295: yes; 0..65534: no */ - x >>= 31; /* 1: yes; 0: no */ - return x; -} - -static inline crypto_uint32 ge(crypto_uint32 a,crypto_uint32 b) /* 16-bit inputs */ -{ - unsigned int x = a; - x -= (unsigned int) b; /* 0..65535: yes; 4294901761..4294967295: no */ - x >>= 31; /* 0: yes; 1: no */ - x ^= 1; /* 1: yes; 0: no */ - return x; -} - -static inline crypto_uint32 times19(crypto_uint32 a) -{ - return (a << 4) + (a << 1) + a; -} - -static inline crypto_uint32 times38(crypto_uint32 a) -{ - return (a << 5) + (a << 2) + (a << 1); -} - -static inline void reduce_add_sub(fe25519 *r) -{ - crypto_uint32 t; - int i,rep; - - for(rep=0;rep<4;rep++) { - t = r->v[31] >> 7; - r->v[31] &= 127; - t = times19(t); - r->v[0] += t; - for(i=0;i<31;i++) { - t = r->v[i] >> 8; - r->v[i+1] += t; - r->v[i] &= 255; - } - } -} - -static inline void reduce_mul(fe25519 *r) -{ - crypto_uint32 t; - int i,rep; - - for(rep=0;rep<2;rep++) { - t = r->v[31] >> 7; - r->v[31] &= 127; - t = times19(t); - r->v[0] += t; - for(i=0;i<31;i++) { - t = r->v[i] >> 8; - r->v[i+1] += t; - r->v[i] &= 255; - } - } -} - -/* reduction modulo 2^255-19 */ -static inline void fe25519_freeze(fe25519 *r) -{ - int i; - crypto_uint32 m = equal(r->v[31],127); - for(i=30;i>0;i--) { - m &= equal(r->v[i],255); - } - m &= ge(r->v[0],237); - - m = -m; - - r->v[31] -= m&127; - for(i=30;i>0;i--) { - r->v[i] -= m&255; - } - r->v[0] -= m&237; -} - -static inline void fe25519_unpack(fe25519 *r, const unsigned char x[32]) -{ - int i; - for(i=0;i<32;i++) { - r->v[i] = x[i]; - } - r->v[31] &= 127; -} - -/* Assumes input x being reduced below 2^255 */ -static inline void fe25519_pack(unsigned char r[32], const fe25519 *x) -{ - int i; - fe25519 y = *x; - fe25519_freeze(&y); - for(i=0;i<32;i++) { - r[i] = y.v[i]; - } -} - -static inline int fe25519_iseq_vartime(const fe25519 *x, const fe25519 *y) -{ - int i; - fe25519 t1 = *x; - fe25519 t2 = *y; - fe25519_freeze(&t1); - fe25519_freeze(&t2); - for(i=0;i<32;i++) { - if (t1.v[i] != t2.v[i]) { - return 0; - } - } - return 1; -} - -static inline void fe25519_cmov(fe25519 *r, const fe25519 *x, unsigned char b) -{ - int i; - crypto_uint32 mask = b; - mask = -mask; - for(i=0;i<32;i++) { - r->v[i] ^= mask & (x->v[i] ^ r->v[i]); - } -} - -static inline unsigned char fe25519_getparity(const fe25519 *x) -{ - fe25519 t = *x; - fe25519_freeze(&t); - return t.v[0] & 1; -} - -static inline void fe25519_setone(fe25519 *r) -{ - int i; - r->v[0] = 1; - for(i=1;i<32;i++) { - r->v[i]=0; - } -} - -static inline void fe25519_setzero(fe25519 *r) -{ - int i; - for(i=0;i<32;i++) { - r->v[i]=0; - } -} - -static inline void fe25519_neg(fe25519 *r, const fe25519 *x) -{ - fe25519 t; - int i; - for(i=0;i<32;i++) { - t.v[i]=x->v[i]; - } - fe25519_setzero(r); - fe25519_sub(r, r, &t); -} - -static inline void fe25519_add(fe25519 *r, const fe25519 *x, const fe25519 *y) -{ - int i; - for(i=0;i<32;i++) { - r->v[i] = x->v[i] + y->v[i]; - } - reduce_add_sub(r); -} - -static inline void fe25519_sub(fe25519 *r, const fe25519 *x, const fe25519 *y) -{ - int i; - crypto_uint32 t[32]; - t[0] = x->v[0] + 0x1da; - t[31] = x->v[31] + 0xfe; - for(i=1;i<31;i++) { - t[i] = x->v[i] + 0x1fe; - } - for(i=0;i<32;i++) { - r->v[i] = t[i] - y->v[i]; - } - reduce_add_sub(r); -} - -static inline void fe25519_mul(fe25519 *r, const fe25519 *x, const fe25519 *y) -{ - int i,j; - crypto_uint32 t[63]; - for(i=0;i<63;i++) { - t[i] = 0; - } - - for(i=0;i<32;i++) { - for(j=0;j<32;j++) { - t[i+j] += x->v[i] * y->v[j]; - } - } - - for(i=32;i<63;i++) { - r->v[i-32] = t[i-32] + times38(t[i]); - } - r->v[31] = t[31]; /* result now in r[0]...r[31] */ - - reduce_mul(r); -} - -static inline void fe25519_square(fe25519 *r, const fe25519 *x) -{ - fe25519_mul(r, x, x); -} - -static inline void fe25519_invert(fe25519 *r, const fe25519 *x) -{ - fe25519 z2; - fe25519 z9; - fe25519 z11; - fe25519 z2_5_0; - fe25519 z2_10_0; - fe25519 z2_20_0; - fe25519 z2_50_0; - fe25519 z2_100_0; - fe25519 t0; - fe25519 t1; - int i; - - /* 2 */ fe25519_square(&z2,x); - /* 4 */ fe25519_square(&t1,&z2); - /* 8 */ fe25519_square(&t0,&t1); - /* 9 */ fe25519_mul(&z9,&t0,x); - /* 11 */ fe25519_mul(&z11,&z9,&z2); - /* 22 */ fe25519_square(&t0,&z11); - /* 2^5 - 2^0 = 31 */ fe25519_mul(&z2_5_0,&t0,&z9); - - /* 2^6 - 2^1 */ fe25519_square(&t0,&z2_5_0); - /* 2^7 - 2^2 */ fe25519_square(&t1,&t0); - /* 2^8 - 2^3 */ fe25519_square(&t0,&t1); - /* 2^9 - 2^4 */ fe25519_square(&t1,&t0); - /* 2^10 - 2^5 */ fe25519_square(&t0,&t1); - /* 2^10 - 2^0 */ fe25519_mul(&z2_10_0,&t0,&z2_5_0); - - /* 2^11 - 2^1 */ fe25519_square(&t0,&z2_10_0); - /* 2^12 - 2^2 */ fe25519_square(&t1,&t0); - /* 2^20 - 2^10 */ for (i = 2;i < 10;i += 2) { fe25519_square(&t0,&t1); fe25519_square(&t1,&t0); } - /* 2^20 - 2^0 */ fe25519_mul(&z2_20_0,&t1,&z2_10_0); - - /* 2^21 - 2^1 */ fe25519_square(&t0,&z2_20_0); - /* 2^22 - 2^2 */ fe25519_square(&t1,&t0); - /* 2^40 - 2^20 */ for (i = 2;i < 20;i += 2) { fe25519_square(&t0,&t1); fe25519_square(&t1,&t0); } - /* 2^40 - 2^0 */ fe25519_mul(&t0,&t1,&z2_20_0); - - /* 2^41 - 2^1 */ fe25519_square(&t1,&t0); - /* 2^42 - 2^2 */ fe25519_square(&t0,&t1); - /* 2^50 - 2^10 */ for (i = 2;i < 10;i += 2) { fe25519_square(&t1,&t0); fe25519_square(&t0,&t1); } - /* 2^50 - 2^0 */ fe25519_mul(&z2_50_0,&t0,&z2_10_0); - - /* 2^51 - 2^1 */ fe25519_square(&t0,&z2_50_0); - /* 2^52 - 2^2 */ fe25519_square(&t1,&t0); - /* 2^100 - 2^50 */ for (i = 2;i < 50;i += 2) { fe25519_square(&t0,&t1); fe25519_square(&t1,&t0); } - /* 2^100 - 2^0 */ fe25519_mul(&z2_100_0,&t1,&z2_50_0); - - /* 2^101 - 2^1 */ fe25519_square(&t1,&z2_100_0); - /* 2^102 - 2^2 */ fe25519_square(&t0,&t1); - /* 2^200 - 2^100 */ for (i = 2;i < 100;i += 2) { fe25519_square(&t1,&t0); fe25519_square(&t0,&t1); } - /* 2^200 - 2^0 */ fe25519_mul(&t1,&t0,&z2_100_0); - - /* 2^201 - 2^1 */ fe25519_square(&t0,&t1); - /* 2^202 - 2^2 */ fe25519_square(&t1,&t0); - /* 2^250 - 2^50 */ for (i = 2;i < 50;i += 2) { fe25519_square(&t0,&t1); fe25519_square(&t1,&t0); } - /* 2^250 - 2^0 */ fe25519_mul(&t0,&t1,&z2_50_0); - - /* 2^251 - 2^1 */ fe25519_square(&t1,&t0); - /* 2^252 - 2^2 */ fe25519_square(&t0,&t1); - /* 2^253 - 2^3 */ fe25519_square(&t1,&t0); - /* 2^254 - 2^4 */ fe25519_square(&t0,&t1); - /* 2^255 - 2^5 */ fe25519_square(&t1,&t0); - /* 2^255 - 21 */ fe25519_mul(r,&t1,&z11); -} - -static inline void fe25519_pow2523(fe25519 *r, const fe25519 *x) -{ - fe25519 z2; - fe25519 z9; - fe25519 z11; - fe25519 z2_5_0; - fe25519 z2_10_0; - fe25519 z2_20_0; - fe25519 z2_50_0; - fe25519 z2_100_0; - fe25519 t; - int i; - - /* 2 */ fe25519_square(&z2,x); - /* 4 */ fe25519_square(&t,&z2); - /* 8 */ fe25519_square(&t,&t); - /* 9 */ fe25519_mul(&z9,&t,x); - /* 11 */ fe25519_mul(&z11,&z9,&z2); - /* 22 */ fe25519_square(&t,&z11); - /* 2^5 - 2^0 = 31 */ fe25519_mul(&z2_5_0,&t,&z9); - - /* 2^6 - 2^1 */ fe25519_square(&t,&z2_5_0); - /* 2^10 - 2^5 */ for (i = 1;i < 5;i++) { fe25519_square(&t,&t); } - /* 2^10 - 2^0 */ fe25519_mul(&z2_10_0,&t,&z2_5_0); - - /* 2^11 - 2^1 */ fe25519_square(&t,&z2_10_0); - /* 2^20 - 2^10 */ for (i = 1;i < 10;i++) { fe25519_square(&t,&t); } - /* 2^20 - 2^0 */ fe25519_mul(&z2_20_0,&t,&z2_10_0); - - /* 2^21 - 2^1 */ fe25519_square(&t,&z2_20_0); - /* 2^40 - 2^20 */ for (i = 1;i < 20;i++) { fe25519_square(&t,&t); } - /* 2^40 - 2^0 */ fe25519_mul(&t,&t,&z2_20_0); - - /* 2^41 - 2^1 */ fe25519_square(&t,&t); - /* 2^50 - 2^10 */ for (i = 1;i < 10;i++) { fe25519_square(&t,&t); } - /* 2^50 - 2^0 */ fe25519_mul(&z2_50_0,&t,&z2_10_0); - - /* 2^51 - 2^1 */ fe25519_square(&t,&z2_50_0); - /* 2^100 - 2^50 */ for (i = 1;i < 50;i++) { fe25519_square(&t,&t); } - /* 2^100 - 2^0 */ fe25519_mul(&z2_100_0,&t,&z2_50_0); - - /* 2^101 - 2^1 */ fe25519_square(&t,&z2_100_0); - /* 2^200 - 2^100 */ for (i = 1;i < 100;i++) { fe25519_square(&t,&t); } - /* 2^200 - 2^0 */ fe25519_mul(&t,&t,&z2_100_0); - - /* 2^201 - 2^1 */ fe25519_square(&t,&t); - /* 2^250 - 2^50 */ for (i = 1;i < 50;i++) { fe25519_square(&t,&t); } - /* 2^250 - 2^0 */ fe25519_mul(&t,&t,&z2_50_0); - - /* 2^251 - 2^1 */ fe25519_square(&t,&t); - /* 2^252 - 2^2 */ fe25519_square(&t,&t); - /* 2^252 - 3 */ fe25519_mul(r,&t,x); -} - -static const crypto_uint32 m[32] = {0xED, 0xD3, 0xF5, 0x5C, 0x1A, 0x63, 0x12, 0x58, 0xD6, 0x9C, 0xF7, 0xA2, 0xDE, 0xF9, 0xDE, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10}; -static const crypto_uint32 mu[33] = {0x1B, 0x13, 0x2C, 0x0A, 0xA3, 0xE5, 0x9C, 0xED, 0xA7, 0x29, 0x63, 0x08, 0x5D, 0x21, 0x06, 0x21, 0xEB, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F}; - -static inline crypto_uint32 lt(crypto_uint32 a,crypto_uint32 b) /* 16-bit inputs */ -{ - unsigned int x = a; - x -= (unsigned int) b; /* 0..65535: no; 4294901761..4294967295: yes */ - x >>= 31; /* 0: no; 1: yes */ - return x; -} - -/* Reduce coefficients of r before calling reduce_add_sub */ -static inline void reduce_add_sub(sc25519 *r) -{ - crypto_uint32 pb = 0; - crypto_uint32 b; - crypto_uint32 mask; - int i; - unsigned char t[32]; - - for(i=0;i<32;i++) { - pb += m[i]; - b = lt(r->v[i],pb); - t[i] = r->v[i]-pb+(b<<8); - pb = b; - } - mask = b - 1; - for(i=0;i<32;i++) { - r->v[i] ^= mask & (r->v[i] ^ t[i]); - } -} - -/* Reduce coefficients of x before calling barrett_reduce */ -static inline void barrett_reduce(sc25519 *r, const crypto_uint32 x[64]) -{ - /* See HAC, Alg. 14.42 */ - int i,j; - crypto_uint32 q2[66]; - crypto_uint32 *q3 = q2 + 33; - crypto_uint32 r1[33]; - crypto_uint32 r2[33]; - crypto_uint32 carry; - crypto_uint32 pb = 0; - crypto_uint32 b; - - for (i = 0;i < 66;++i) { - q2[i] = 0; - } - for (i = 0;i < 33;++i) { - r2[i] = 0; - } - - for(i=0;i<33;i++) { - for(j=0;j<33;j++) { - if(i+j >= 31) { - q2[i+j] += mu[i]*x[j+31]; - } - } - } - carry = q2[31] >> 8; - q2[32] += carry; - carry = q2[32] >> 8; - q2[33] += carry; - - for(i=0;i<33;i++) { - r1[i] = x[i]; - } - for(i=0;i<32;i++) { - for(j=0;j<33;j++) { - if(i+j < 33) { - r2[i+j] += m[i]*q3[j]; - } - } - } - - for(i=0;i<32;i++) { - carry = r2[i] >> 8; - r2[i+1] += carry; - r2[i] &= 0xff; - } - - for(i=0;i<32;i++) { - pb += r2[i]; - b = lt(r1[i],pb); - r->v[i] = r1[i]-pb+(b<<8); - pb = b; - } - - /* XXX: Can it really happen that r<0?, See HAC, Alg 14.42, Step 3 - * If so: Handle it here! - */ - - reduce_add_sub(r); - reduce_add_sub(r); -} - -static inline void sc25519_from32bytes(sc25519 *r, const unsigned char x[32]) -{ - int i; - crypto_uint32 t[64]; - for(i=0;i<32;i++) { - t[i] = x[i]; - } - for(i=32;i<64;++i) { - t[i] = 0; - } - barrett_reduce(r, t); -} - -static inline void sc25519_from64bytes(sc25519 *r, const unsigned char x[64]) -{ - int i; - crypto_uint32 t[64]; - for(i=0;i<64;i++) { - t[i] = x[i]; - } - barrett_reduce(r, t); -} - -static inline void sc25519_to32bytes(unsigned char r[32], const sc25519 *x) -{ - int i; - for(i=0;i<32;i++) { - r[i] = x->v[i]; - } -} - -static inline void sc25519_add(sc25519 *r, const sc25519 *x, const sc25519 *y) -{ - int i, carry; - for(i=0;i<32;i++) { - r->v[i] = x->v[i] + y->v[i]; - } - for(i=0;i<31;i++) { - carry = r->v[i] >> 8; - r->v[i+1] += carry; - r->v[i] &= 0xff; - } - reduce_add_sub(r); -} - -static inline void sc25519_mul(sc25519 *r, const sc25519 *x, const sc25519 *y) -{ - int i,j,carry; - crypto_uint32 t[64]; - for(i=0;i<64;i++) { - t[i] = 0; - } - - for(i=0;i<32;i++) { - for(j=0;j<32;j++) { - t[i+j] += x->v[i] * y->v[j]; - } - } - - for(i=0;i<63;i++) { - carry = t[i] >> 8; - t[i+1] += carry; - t[i] &= 0xff; - } - - barrett_reduce(r, t); -} - -static inline void sc25519_window3(signed char r[85], const sc25519 *s) -{ - char carry; - int i; - for(i=0;i<10;i++) { - r[8*i+0] = s->v[3*i+0] & 7; - r[8*i+1] = (s->v[3*i+0] >> 3) & 7; - r[8*i+2] = (s->v[3*i+0] >> 6) & 7; - r[8*i+2] ^= (s->v[3*i+1] << 2) & 7; - r[8*i+3] = (s->v[3*i+1] >> 1) & 7; - r[8*i+4] = (s->v[3*i+1] >> 4) & 7; - r[8*i+5] = (s->v[3*i+1] >> 7) & 7; - r[8*i+5] ^= (s->v[3*i+2] << 1) & 7; - r[8*i+6] = (s->v[3*i+2] >> 2) & 7; - r[8*i+7] = (s->v[3*i+2] >> 5) & 7; - } - r[8*i+0] = s->v[3*i+0] & 7; - r[8*i+1] = (s->v[3*i+0] >> 3) & 7; - r[8*i+2] = (s->v[3*i+0] >> 6) & 7; - r[8*i+2] ^= (s->v[3*i+1] << 2) & 7; - r[8*i+3] = (s->v[3*i+1] >> 1) & 7; - r[8*i+4] = (s->v[3*i+1] >> 4) & 7; - - /* Making it signed */ - carry = 0; - for(i=0;i<84;i++) { - r[i] += carry; - r[i+1] += r[i] >> 3; - r[i] &= 7; - carry = r[i] >> 2; - r[i] -= carry<<3; - } - r[84] += carry; -} - -static inline void sc25519_2interleave2(unsigned char r[127], const sc25519 *s1, const sc25519 *s2) -{ - int i; - for(i=0;i<31;i++) { - r[4*i] = ( s1->v[i] & 3) ^ (( s2->v[i] & 3) << 2); - r[4*i+1] = ((s1->v[i] >> 2) & 3) ^ (((s2->v[i] >> 2) & 3) << 2); - r[4*i+2] = ((s1->v[i] >> 4) & 3) ^ (((s2->v[i] >> 4) & 3) << 2); - r[4*i+3] = ((s1->v[i] >> 6) & 3) ^ (((s2->v[i] >> 6) & 3) << 2); - } - r[124] = ( s1->v[31] & 3) ^ (( s2->v[31] & 3) << 2); - r[125] = ((s1->v[31] >> 2) & 3) ^ (((s2->v[31] >> 2) & 3) << 2); - r[126] = ((s1->v[31] >> 4) & 3) ^ (((s2->v[31] >> 4) & 3) << 2); -} - -/* d */ -static const fe25519 ge25519_ecd = {{0xA3, 0x78, 0x59, 0x13, 0xCA, 0x4D, 0xEB, 0x75, 0xAB, 0xD8, 0x41, 0x41, 0x4D, 0x0A, 0x70, 0x00, - 0x98, 0xE8, 0x79, 0x77, 0x79, 0x40, 0xC7, 0x8C, 0x73, 0xFE, 0x6F, 0x2B, 0xEE, 0x6C, 0x03, 0x52}}; -/* 2*d */ -static const fe25519 ge25519_ec2d = {{0x59, 0xF1, 0xB2, 0x26, 0x94, 0x9B, 0xD6, 0xEB, 0x56, 0xB1, 0x83, 0x82, 0x9A, 0x14, 0xE0, 0x00, - 0x30, 0xD1, 0xF3, 0xEE, 0xF2, 0x80, 0x8E, 0x19, 0xE7, 0xFC, 0xDF, 0x56, 0xDC, 0xD9, 0x06, 0x24}}; -/* sqrt(-1) */ -static const fe25519 ge25519_sqrtm1 = {{0xB0, 0xA0, 0x0E, 0x4A, 0x27, 0x1B, 0xEE, 0xC4, 0x78, 0xE4, 0x2F, 0xAD, 0x06, 0x18, 0x43, 0x2F, - 0xA7, 0xD7, 0xFB, 0x3D, 0x99, 0x00, 0x4D, 0x2B, 0x0B, 0xDF, 0xC1, 0x4F, 0x80, 0x24, 0x83, 0x2B}}; - -/* Packed coordinates of the base point */ -static const ge25519 ge25519_base = {{{0x1A, 0xD5, 0x25, 0x8F, 0x60, 0x2D, 0x56, 0xC9, 0xB2, 0xA7, 0x25, 0x95, 0x60, 0xC7, 0x2C, 0x69, - 0x5C, 0xDC, 0xD6, 0xFD, 0x31, 0xE2, 0xA4, 0xC0, 0xFE, 0x53, 0x6E, 0xCD, 0xD3, 0x36, 0x69, 0x21}}, - {{0x58, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, - 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0xA3, 0xDD, 0xB7, 0xA5, 0xB3, 0x8A, 0xDE, 0x6D, 0xF5, 0x52, 0x51, 0x77, 0x80, 0x9F, 0xF0, 0x20, - 0x7D, 0xE3, 0xAB, 0x64, 0x8E, 0x4E, 0xEA, 0x66, 0x65, 0x76, 0x8B, 0xD7, 0x0F, 0x5F, 0x87, 0x67}}}; - -/* Multiples of the base point in affine representation */ -static const ge25519_aff ge25519_base_multiples_affine[425] = { -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0x1a, 0xd5, 0x25, 0x8f, 0x60, 0x2d, 0x56, 0xc9, 0xb2, 0xa7, 0x25, 0x95, 0x60, 0xc7, 0x2c, 0x69, 0x5c, 0xdc, 0xd6, 0xfd, 0x31, 0xe2, 0xa4, 0xc0, 0xfe, 0x53, 0x6e, 0xcd, 0xd3, 0x36, 0x69, 0x21}} , - {{0x58, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66}}}, -{{{0x0e, 0xce, 0x43, 0x28, 0x4e, 0xa1, 0xc5, 0x83, 0x5f, 0xa4, 0xd7, 0x15, 0x45, 0x8e, 0x0d, 0x08, 0xac, 0xe7, 0x33, 0x18, 0x7d, 0x3b, 0x04, 0x3d, 0x6c, 0x04, 0x5a, 0x9f, 0x4c, 0x38, 0xab, 0x36}} , - {{0xc9, 0xa3, 0xf8, 0x6a, 0xae, 0x46, 0x5f, 0x0e, 0x56, 0x51, 0x38, 0x64, 0x51, 0x0f, 0x39, 0x97, 0x56, 0x1f, 0xa2, 0xc9, 0xe8, 0x5e, 0xa2, 0x1d, 0xc2, 0x29, 0x23, 0x09, 0xf3, 0xcd, 0x60, 0x22}}}, -{{{0x5c, 0xe2, 0xf8, 0xd3, 0x5f, 0x48, 0x62, 0xac, 0x86, 0x48, 0x62, 0x81, 0x19, 0x98, 0x43, 0x63, 0x3a, 0xc8, 0xda, 0x3e, 0x74, 0xae, 0xf4, 0x1f, 0x49, 0x8f, 0x92, 0x22, 0x4a, 0x9c, 0xae, 0x67}} , - {{0xd4, 0xb4, 0xf5, 0x78, 0x48, 0x68, 0xc3, 0x02, 0x04, 0x03, 0x24, 0x67, 0x17, 0xec, 0x16, 0x9f, 0xf7, 0x9e, 0x26, 0x60, 0x8e, 0xa1, 0x26, 0xa1, 0xab, 0x69, 0xee, 0x77, 0xd1, 0xb1, 0x67, 0x12}}}, -{{{0x70, 0xf8, 0xc9, 0xc4, 0x57, 0xa6, 0x3a, 0x49, 0x47, 0x15, 0xce, 0x93, 0xc1, 0x9e, 0x73, 0x1a, 0xf9, 0x20, 0x35, 0x7a, 0xb8, 0xd4, 0x25, 0x83, 0x46, 0xf1, 0xcf, 0x56, 0xdb, 0xa8, 0x3d, 0x20}} , - {{0x2f, 0x11, 0x32, 0xca, 0x61, 0xab, 0x38, 0xdf, 0xf0, 0x0f, 0x2f, 0xea, 0x32, 0x28, 0xf2, 0x4c, 0x6c, 0x71, 0xd5, 0x80, 0x85, 0xb8, 0x0e, 0x47, 0xe1, 0x95, 0x15, 0xcb, 0x27, 0xe8, 0xd0, 0x47}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0xc8, 0x84, 0xa5, 0x08, 0xbc, 0xfd, 0x87, 0x3b, 0x99, 0x8b, 0x69, 0x80, 0x7b, 0xc6, 0x3a, 0xeb, 0x93, 0xcf, 0x4e, 0xf8, 0x5c, 0x2d, 0x86, 0x42, 0xb6, 0x71, 0xd7, 0x97, 0x5f, 0xe1, 0x42, 0x67}} , - {{0xb4, 0xb9, 0x37, 0xfc, 0xa9, 0x5b, 0x2f, 0x1e, 0x93, 0xe4, 0x1e, 0x62, 0xfc, 0x3c, 0x78, 0x81, 0x8f, 0xf3, 0x8a, 0x66, 0x09, 0x6f, 0xad, 0x6e, 0x79, 0x73, 0xe5, 0xc9, 0x00, 0x06, 0xd3, 0x21}}}, -{{{0xf8, 0xf9, 0x28, 0x6c, 0x6d, 0x59, 0xb2, 0x59, 0x74, 0x23, 0xbf, 0xe7, 0x33, 0x8d, 0x57, 0x09, 0x91, 0x9c, 0x24, 0x08, 0x15, 0x2b, 0xe2, 0xb8, 0xee, 0x3a, 0xe5, 0x27, 0x06, 0x86, 0xa4, 0x23}} , - {{0xeb, 0x27, 0x67, 0xc1, 0x37, 0xab, 0x7a, 0xd8, 0x27, 0x9c, 0x07, 0x8e, 0xff, 0x11, 0x6a, 0xb0, 0x78, 0x6e, 0xad, 0x3a, 0x2e, 0x0f, 0x98, 0x9f, 0x72, 0xc3, 0x7f, 0x82, 0xf2, 0x96, 0x96, 0x70}}}, -{{{0x81, 0x6b, 0x88, 0xe8, 0x1e, 0xc7, 0x77, 0x96, 0x0e, 0xa1, 0xa9, 0x52, 0xe0, 0xd8, 0x0e, 0x61, 0x9e, 0x79, 0x2d, 0x95, 0x9c, 0x8d, 0x96, 0xe0, 0x06, 0x40, 0x5d, 0x87, 0x28, 0x5f, 0x98, 0x70}} , - {{0xf1, 0x79, 0x7b, 0xed, 0x4f, 0x44, 0xb2, 0xe7, 0x08, 0x0d, 0xc2, 0x08, 0x12, 0xd2, 0x9f, 0xdf, 0xcd, 0x93, 0x20, 0x8a, 0xcf, 0x33, 0xca, 0x6d, 0x89, 0xb9, 0x77, 0xc8, 0x93, 0x1b, 0x4e, 0x60}}}, -{{{0x26, 0x4f, 0x7e, 0x97, 0xf6, 0x40, 0xdd, 0x4f, 0xfc, 0x52, 0x78, 0xf9, 0x90, 0x31, 0x03, 0xe6, 0x7d, 0x56, 0x39, 0x0b, 0x1d, 0x56, 0x82, 0x85, 0xf9, 0x1a, 0x42, 0x17, 0x69, 0x6c, 0xcf, 0x39}} , - {{0x69, 0xd2, 0x06, 0x3a, 0x4f, 0x39, 0x2d, 0xf9, 0x38, 0x40, 0x8c, 0x4c, 0xe7, 0x05, 0x12, 0xb4, 0x78, 0x8b, 0xf8, 0xc0, 0xec, 0x93, 0xde, 0x7a, 0x6b, 0xce, 0x2c, 0xe1, 0x0e, 0xa9, 0x34, 0x44}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0x0b, 0xa4, 0x3c, 0xb0, 0x0f, 0x7a, 0x51, 0xf1, 0x78, 0xd6, 0xd9, 0x6a, 0xfd, 0x46, 0xe8, 0xb8, 0xa8, 0x79, 0x1d, 0x87, 0xf9, 0x90, 0xf2, 0x9c, 0x13, 0x29, 0xf8, 0x0b, 0x20, 0x64, 0xfa, 0x05}} , - {{0x26, 0x09, 0xda, 0x17, 0xaf, 0x95, 0xd6, 0xfb, 0x6a, 0x19, 0x0d, 0x6e, 0x5e, 0x12, 0xf1, 0x99, 0x4c, 0xaa, 0xa8, 0x6f, 0x79, 0x86, 0xf4, 0x72, 0x28, 0x00, 0x26, 0xf9, 0xea, 0x9e, 0x19, 0x3d}}}, -{{{0x87, 0xdd, 0xcf, 0xf0, 0x5b, 0x49, 0xa2, 0x5d, 0x40, 0x7a, 0x23, 0x26, 0xa4, 0x7a, 0x83, 0x8a, 0xb7, 0x8b, 0xd2, 0x1a, 0xbf, 0xea, 0x02, 0x24, 0x08, 0x5f, 0x7b, 0xa9, 0xb1, 0xbe, 0x9d, 0x37}} , - {{0xfc, 0x86, 0x4b, 0x08, 0xee, 0xe7, 0xa0, 0xfd, 0x21, 0x45, 0x09, 0x34, 0xc1, 0x61, 0x32, 0x23, 0xfc, 0x9b, 0x55, 0x48, 0x53, 0x99, 0xf7, 0x63, 0xd0, 0x99, 0xce, 0x01, 0xe0, 0x9f, 0xeb, 0x28}}}, -{{{0x47, 0xfc, 0xab, 0x5a, 0x17, 0xf0, 0x85, 0x56, 0x3a, 0x30, 0x86, 0x20, 0x28, 0x4b, 0x8e, 0x44, 0x74, 0x3a, 0x6e, 0x02, 0xf1, 0x32, 0x8f, 0x9f, 0x3f, 0x08, 0x35, 0xe9, 0xca, 0x16, 0x5f, 0x6e}} , - {{0x1c, 0x59, 0x1c, 0x65, 0x5d, 0x34, 0xa4, 0x09, 0xcd, 0x13, 0x9c, 0x70, 0x7d, 0xb1, 0x2a, 0xc5, 0x88, 0xaf, 0x0b, 0x60, 0xc7, 0x9f, 0x34, 0x8d, 0xd6, 0xb7, 0x7f, 0xea, 0x78, 0x65, 0x8d, 0x77}}}, -{{{0x56, 0xa5, 0xc2, 0x0c, 0xdd, 0xbc, 0xb8, 0x20, 0x6d, 0x57, 0x61, 0xb5, 0xfb, 0x78, 0xb5, 0xd4, 0x49, 0x54, 0x90, 0x26, 0xc1, 0xcb, 0xe9, 0xe6, 0xbf, 0xec, 0x1d, 0x4e, 0xed, 0x07, 0x7e, 0x5e}} , - {{0xc7, 0xf6, 0x6c, 0x56, 0x31, 0x20, 0x14, 0x0e, 0xa8, 0xd9, 0x27, 0xc1, 0x9a, 0x3d, 0x1b, 0x7d, 0x0e, 0x26, 0xd3, 0x81, 0xaa, 0xeb, 0xf5, 0x6b, 0x79, 0x02, 0xf1, 0x51, 0x5c, 0x75, 0x55, 0x0f}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0x0a, 0x34, 0xcd, 0x82, 0x3c, 0x33, 0x09, 0x54, 0xd2, 0x61, 0x39, 0x30, 0x9b, 0xfd, 0xef, 0x21, 0x26, 0xd4, 0x70, 0xfa, 0xee, 0xf9, 0x31, 0x33, 0x73, 0x84, 0xd0, 0xb3, 0x81, 0xbf, 0xec, 0x2e}} , - {{0xe8, 0x93, 0x8b, 0x00, 0x64, 0xf7, 0x9c, 0xb8, 0x74, 0xe0, 0xe6, 0x49, 0x48, 0x4d, 0x4d, 0x48, 0xb6, 0x19, 0xa1, 0x40, 0xb7, 0xd9, 0x32, 0x41, 0x7c, 0x82, 0x37, 0xa1, 0x2d, 0xdc, 0xd2, 0x54}}}, -{{{0x68, 0x2b, 0x4a, 0x5b, 0xd5, 0xc7, 0x51, 0x91, 0x1d, 0xe1, 0x2a, 0x4b, 0xc4, 0x47, 0xf1, 0xbc, 0x7a, 0xb3, 0xcb, 0xc8, 0xb6, 0x7c, 0xac, 0x90, 0x05, 0xfd, 0xf3, 0xf9, 0x52, 0x3a, 0x11, 0x6b}} , - {{0x3d, 0xc1, 0x27, 0xf3, 0x59, 0x43, 0x95, 0x90, 0xc5, 0x96, 0x79, 0xf5, 0xf4, 0x95, 0x65, 0x29, 0x06, 0x9c, 0x51, 0x05, 0x18, 0xda, 0xb8, 0x2e, 0x79, 0x7e, 0x69, 0x59, 0x71, 0x01, 0xeb, 0x1a}}}, -{{{0x15, 0x06, 0x49, 0xb6, 0x8a, 0x3c, 0xea, 0x2f, 0x34, 0x20, 0x14, 0xc3, 0xaa, 0xd6, 0xaf, 0x2c, 0x3e, 0xbd, 0x65, 0x20, 0xe2, 0x4d, 0x4b, 0x3b, 0xeb, 0x9f, 0x4a, 0xc3, 0xad, 0xa4, 0x3b, 0x60}} , - {{0xbc, 0x58, 0xe6, 0xc0, 0x95, 0x2a, 0x2a, 0x81, 0x9a, 0x7a, 0xf3, 0xd2, 0x06, 0xbe, 0x48, 0xbc, 0x0c, 0xc5, 0x46, 0xe0, 0x6a, 0xd4, 0xac, 0x0f, 0xd9, 0xcc, 0x82, 0x34, 0x2c, 0xaf, 0xdb, 0x1f}}}, -{{{0xf7, 0x17, 0x13, 0xbd, 0xfb, 0xbc, 0xd2, 0xec, 0x45, 0xb3, 0x15, 0x31, 0xe9, 0xaf, 0x82, 0x84, 0x3d, 0x28, 0xc6, 0xfc, 0x11, 0xf5, 0x41, 0xb5, 0x8b, 0xd3, 0x12, 0x76, 0x52, 0xe7, 0x1a, 0x3c}} , - {{0x4e, 0x36, 0x11, 0x07, 0xa2, 0x15, 0x20, 0x51, 0xc4, 0x2a, 0xc3, 0x62, 0x8b, 0x5e, 0x7f, 0xa6, 0x0f, 0xf9, 0x45, 0x85, 0x6c, 0x11, 0x86, 0xb7, 0x7e, 0xe5, 0xd7, 0xf9, 0xc3, 0x91, 0x1c, 0x05}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0xea, 0xd6, 0xde, 0x29, 0x3a, 0x00, 0xb9, 0x02, 0x59, 0xcb, 0x26, 0xc4, 0xba, 0x99, 0xb1, 0x97, 0x2f, 0x8e, 0x00, 0x92, 0x26, 0x4f, 0x52, 0xeb, 0x47, 0x1b, 0x89, 0x8b, 0x24, 0xc0, 0x13, 0x7d}} , - {{0xd5, 0x20, 0x5b, 0x80, 0xa6, 0x80, 0x20, 0x95, 0xc3, 0xe9, 0x9f, 0x8e, 0x87, 0x9e, 0x1e, 0x9e, 0x7a, 0xc7, 0xcc, 0x75, 0x6c, 0xa5, 0xf1, 0x91, 0x1a, 0xa8, 0x01, 0x2c, 0xab, 0x76, 0xa9, 0x59}}}, -{{{0xde, 0xc9, 0xb1, 0x31, 0x10, 0x16, 0xaa, 0x35, 0x14, 0x6a, 0xd4, 0xb5, 0x34, 0x82, 0x71, 0xd2, 0x4a, 0x5d, 0x9a, 0x1f, 0x53, 0x26, 0x3c, 0xe5, 0x8e, 0x8d, 0x33, 0x7f, 0xff, 0xa9, 0xd5, 0x17}} , - {{0x89, 0xaf, 0xf6, 0xa4, 0x64, 0xd5, 0x10, 0xe0, 0x1d, 0xad, 0xef, 0x44, 0xbd, 0xda, 0x83, 0xac, 0x7a, 0xa8, 0xf0, 0x1c, 0x07, 0xf9, 0xc3, 0x43, 0x6c, 0x3f, 0xb7, 0xd3, 0x87, 0x22, 0x02, 0x73}}}, -{{{0x64, 0x1d, 0x49, 0x13, 0x2f, 0x71, 0xec, 0x69, 0x87, 0xd0, 0x42, 0xee, 0x13, 0xec, 0xe3, 0xed, 0x56, 0x7b, 0xbf, 0xbd, 0x8c, 0x2f, 0x7d, 0x7b, 0x9d, 0x28, 0xec, 0x8e, 0x76, 0x2f, 0x6f, 0x08}} , - {{0x22, 0xf5, 0x5f, 0x4d, 0x15, 0xef, 0xfc, 0x4e, 0x57, 0x03, 0x36, 0x89, 0xf0, 0xeb, 0x5b, 0x91, 0xd6, 0xe2, 0xca, 0x01, 0xa5, 0xee, 0x52, 0xec, 0xa0, 0x3c, 0x8f, 0x33, 0x90, 0x5a, 0x94, 0x72}}}, -{{{0x8a, 0x4b, 0xe7, 0x38, 0xbc, 0xda, 0xc2, 0xb0, 0x85, 0xe1, 0x4a, 0xfe, 0x2d, 0x44, 0x84, 0xcb, 0x20, 0x6b, 0x2d, 0xbf, 0x11, 0x9c, 0xd7, 0xbe, 0xd3, 0x3e, 0x5f, 0xbf, 0x68, 0xbc, 0xa8, 0x07}} , - {{0x01, 0x89, 0x28, 0x22, 0x6a, 0x78, 0xaa, 0x29, 0x03, 0xc8, 0x74, 0x95, 0x03, 0x3e, 0xdc, 0xbd, 0x07, 0x13, 0xa8, 0xa2, 0x20, 0x2d, 0xb3, 0x18, 0x70, 0x42, 0xfd, 0x7a, 0xc4, 0xd7, 0x49, 0x72}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0x02, 0xff, 0x32, 0x2b, 0x5c, 0x93, 0x54, 0x32, 0xe8, 0x57, 0x54, 0x1a, 0x8b, 0x33, 0x60, 0x65, 0xd3, 0x67, 0xa4, 0xc1, 0x26, 0xc4, 0xa4, 0x34, 0x1f, 0x9b, 0xa7, 0xa9, 0xf4, 0xd9, 0x4f, 0x5b}} , - {{0x46, 0x8d, 0xb0, 0x33, 0x54, 0x26, 0x5b, 0x68, 0xdf, 0xbb, 0xc5, 0xec, 0xc2, 0xf9, 0x3c, 0x5a, 0x37, 0xc1, 0x8e, 0x27, 0x47, 0xaa, 0x49, 0x5a, 0xf8, 0xfb, 0x68, 0x04, 0x23, 0xd1, 0xeb, 0x40}}}, -{{{0x65, 0xa5, 0x11, 0x84, 0x8a, 0x67, 0x9d, 0x9e, 0xd1, 0x44, 0x68, 0x7a, 0x34, 0xe1, 0x9f, 0xa3, 0x54, 0xcd, 0x07, 0xca, 0x79, 0x1f, 0x54, 0x2f, 0x13, 0x70, 0x4e, 0xee, 0xa2, 0xfa, 0xe7, 0x5d}} , - {{0x36, 0xec, 0x54, 0xf8, 0xce, 0xe4, 0x85, 0xdf, 0xf6, 0x6f, 0x1d, 0x90, 0x08, 0xbc, 0xe8, 0xc0, 0x92, 0x2d, 0x43, 0x6b, 0x92, 0xa9, 0x8e, 0xab, 0x0a, 0x2e, 0x1c, 0x1e, 0x64, 0x23, 0x9f, 0x2c}}}, -{{{0xa7, 0xd6, 0x2e, 0xd5, 0xcc, 0xd4, 0xcb, 0x5a, 0x3b, 0xa7, 0xf9, 0x46, 0x03, 0x1d, 0xad, 0x2b, 0x34, 0x31, 0x90, 0x00, 0x46, 0x08, 0x82, 0x14, 0xc4, 0xe0, 0x9c, 0xf0, 0xe3, 0x55, 0x43, 0x31}} , - {{0x60, 0xd6, 0xdd, 0x78, 0xe6, 0xd4, 0x22, 0x42, 0x1f, 0x00, 0xf9, 0xb1, 0x6a, 0x63, 0xe2, 0x92, 0x59, 0xd1, 0x1a, 0xb7, 0x00, 0x54, 0x29, 0xc9, 0xc1, 0xf6, 0x6f, 0x7a, 0xc5, 0x3c, 0x5f, 0x65}}}, -{{{0x27, 0x4f, 0xd0, 0x72, 0xb1, 0x11, 0x14, 0x27, 0x15, 0x94, 0x48, 0x81, 0x7e, 0x74, 0xd8, 0x32, 0xd5, 0xd1, 0x11, 0x28, 0x60, 0x63, 0x36, 0x32, 0x37, 0xb5, 0x13, 0x1c, 0xa0, 0x37, 0xe3, 0x74}} , - {{0xf1, 0x25, 0x4e, 0x11, 0x96, 0x67, 0xe6, 0x1c, 0xc2, 0xb2, 0x53, 0xe2, 0xda, 0x85, 0xee, 0xb2, 0x9f, 0x59, 0xf3, 0xba, 0xbd, 0xfa, 0xcf, 0x6e, 0xf9, 0xda, 0xa4, 0xb3, 0x02, 0x8f, 0x64, 0x08}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0x34, 0x94, 0xf2, 0x64, 0x54, 0x47, 0x37, 0x07, 0x40, 0x8a, 0x20, 0xba, 0x4a, 0x55, 0xd7, 0x3f, 0x47, 0xba, 0x25, 0x23, 0x14, 0xb0, 0x2c, 0xe8, 0x55, 0xa8, 0xa6, 0xef, 0x51, 0xbd, 0x6f, 0x6a}} , - {{0x71, 0xd6, 0x16, 0x76, 0xb2, 0x06, 0xea, 0x79, 0xf5, 0xc4, 0xc3, 0x52, 0x7e, 0x61, 0xd1, 0xe1, 0xad, 0x70, 0x78, 0x1d, 0x16, 0x11, 0xf8, 0x7c, 0x2b, 0xfc, 0x55, 0x9f, 0x52, 0xf8, 0xf5, 0x16}}}, -{{{0x34, 0x96, 0x9a, 0xf6, 0xc5, 0xe0, 0x14, 0x03, 0x24, 0x0e, 0x4c, 0xad, 0x9e, 0x9a, 0x70, 0x23, 0x96, 0xb2, 0xf1, 0x2e, 0x9d, 0xc3, 0x32, 0x9b, 0x54, 0xa5, 0x73, 0xde, 0x88, 0xb1, 0x3e, 0x24}} , - {{0xf6, 0xe2, 0x4c, 0x1f, 0x5b, 0xb2, 0xaf, 0x82, 0xa5, 0xcf, 0x81, 0x10, 0x04, 0xef, 0xdb, 0xa2, 0xcc, 0x24, 0xb2, 0x7e, 0x0b, 0x7a, 0xeb, 0x01, 0xd8, 0x52, 0xf4, 0x51, 0x89, 0x29, 0x79, 0x37}}}, -{{{0x74, 0xde, 0x12, 0xf3, 0x68, 0xb7, 0x66, 0xc3, 0xee, 0x68, 0xdc, 0x81, 0xb5, 0x55, 0x99, 0xab, 0xd9, 0x28, 0x63, 0x6d, 0x8b, 0x40, 0x69, 0x75, 0x6c, 0xcd, 0x5c, 0x2a, 0x7e, 0x32, 0x7b, 0x29}} , - {{0x02, 0xcc, 0x22, 0x74, 0x4d, 0x19, 0x07, 0xc0, 0xda, 0xb5, 0x76, 0x51, 0x2a, 0xaa, 0xa6, 0x0a, 0x5f, 0x26, 0xd4, 0xbc, 0xaf, 0x48, 0x88, 0x7f, 0x02, 0xbc, 0xf2, 0xe1, 0xcf, 0xe9, 0xdd, 0x15}}}, -{{{0xed, 0xb5, 0x9a, 0x8c, 0x9a, 0xdd, 0x27, 0xf4, 0x7f, 0x47, 0xd9, 0x52, 0xa7, 0xcd, 0x65, 0xa5, 0x31, 0x22, 0xed, 0xa6, 0x63, 0x5b, 0x80, 0x4a, 0xad, 0x4d, 0xed, 0xbf, 0xee, 0x49, 0xb3, 0x06}} , - {{0xf8, 0x64, 0x8b, 0x60, 0x90, 0xe9, 0xde, 0x44, 0x77, 0xb9, 0x07, 0x36, 0x32, 0xc2, 0x50, 0xf5, 0x65, 0xdf, 0x48, 0x4c, 0x37, 0xaa, 0x68, 0xab, 0x9a, 0x1f, 0x3e, 0xff, 0x89, 0x92, 0xa0, 0x07}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0x7d, 0x4f, 0x9c, 0x19, 0xc0, 0x4a, 0x31, 0xec, 0xf9, 0xaa, 0xeb, 0xb2, 0x16, 0x9c, 0xa3, 0x66, 0x5f, 0xd1, 0xd4, 0xed, 0xb8, 0x92, 0x1c, 0xab, 0xda, 0xea, 0xd9, 0x57, 0xdf, 0x4c, 0x2a, 0x48}} , - {{0x4b, 0xb0, 0x4e, 0x6e, 0x11, 0x3b, 0x51, 0xbd, 0x6a, 0xfd, 0xe4, 0x25, 0xa5, 0x5f, 0x11, 0x3f, 0x98, 0x92, 0x51, 0x14, 0xc6, 0x5f, 0x3c, 0x0b, 0xa8, 0xf7, 0xc2, 0x81, 0x43, 0xde, 0x91, 0x73}}}, -{{{0x3c, 0x8f, 0x9f, 0x33, 0x2a, 0x1f, 0x43, 0x33, 0x8f, 0x68, 0xff, 0x1f, 0x3d, 0x73, 0x6b, 0xbf, 0x68, 0xcc, 0x7d, 0x13, 0x6c, 0x24, 0x4b, 0xcc, 0x4d, 0x24, 0x0d, 0xfe, 0xde, 0x86, 0xad, 0x3b}} , - {{0x79, 0x51, 0x81, 0x01, 0xdc, 0x73, 0x53, 0xe0, 0x6e, 0x9b, 0xea, 0x68, 0x3f, 0x5c, 0x14, 0x84, 0x53, 0x8d, 0x4b, 0xc0, 0x9f, 0x9f, 0x89, 0x2b, 0x8c, 0xba, 0x86, 0xfa, 0xf2, 0xcd, 0xe3, 0x2d}}}, -{{{0x06, 0xf9, 0x29, 0x5a, 0xdb, 0x3d, 0x84, 0x52, 0xab, 0xcc, 0x6b, 0x60, 0x9d, 0xb7, 0x4a, 0x0e, 0x36, 0x63, 0x91, 0xad, 0xa0, 0x95, 0xb0, 0x97, 0x89, 0x4e, 0xcf, 0x7d, 0x3c, 0xe5, 0x7c, 0x28}} , - {{0x2e, 0x69, 0x98, 0xfd, 0xc6, 0xbd, 0xcc, 0xca, 0xdf, 0x9a, 0x44, 0x7e, 0x9d, 0xca, 0x89, 0x6d, 0xbf, 0x27, 0xc2, 0xf8, 0xcd, 0x46, 0x00, 0x2b, 0xb5, 0x58, 0x4e, 0xb7, 0x89, 0x09, 0xe9, 0x2d}}}, -{{{0x54, 0xbe, 0x75, 0xcb, 0x05, 0xb0, 0x54, 0xb7, 0xe7, 0x26, 0x86, 0x4a, 0xfc, 0x19, 0xcf, 0x27, 0x46, 0xd4, 0x22, 0x96, 0x5a, 0x11, 0xe8, 0xd5, 0x1b, 0xed, 0x71, 0xc5, 0x5d, 0xc8, 0xaf, 0x45}} , - {{0x40, 0x7b, 0x77, 0x57, 0x49, 0x9e, 0x80, 0x39, 0x23, 0xee, 0x81, 0x0b, 0x22, 0xcf, 0xdb, 0x7a, 0x2f, 0x14, 0xb8, 0x57, 0x8f, 0xa1, 0x39, 0x1e, 0x77, 0xfc, 0x0b, 0xa6, 0xbf, 0x8a, 0x0c, 0x6c}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0x77, 0x3a, 0xd4, 0xd8, 0x27, 0xcf, 0xe8, 0xa1, 0x72, 0x9d, 0xca, 0xdd, 0x0d, 0x96, 0xda, 0x79, 0xed, 0x56, 0x42, 0x15, 0x60, 0xc7, 0x1c, 0x6b, 0x26, 0x30, 0xf6, 0x6a, 0x95, 0x67, 0xf3, 0x0a}} , - {{0xc5, 0x08, 0xa4, 0x2b, 0x2f, 0xbd, 0x31, 0x81, 0x2a, 0xa6, 0xb6, 0xe4, 0x00, 0x91, 0xda, 0x3d, 0xb2, 0xb0, 0x96, 0xce, 0x8a, 0xd2, 0x8d, 0x70, 0xb3, 0xd3, 0x34, 0x01, 0x90, 0x8d, 0x10, 0x21}}}, -{{{0x33, 0x0d, 0xe7, 0xba, 0x4f, 0x07, 0xdf, 0x8d, 0xea, 0x7d, 0xa0, 0xc5, 0xd6, 0xb1, 0xb0, 0xe5, 0x57, 0x1b, 0x5b, 0xf5, 0x45, 0x13, 0x14, 0x64, 0x5a, 0xeb, 0x5c, 0xfc, 0x54, 0x01, 0x76, 0x2b}} , - {{0x02, 0x0c, 0xc2, 0xaf, 0x96, 0x36, 0xfe, 0x4a, 0xe2, 0x54, 0x20, 0x6a, 0xeb, 0xb2, 0x9f, 0x62, 0xd7, 0xce, 0xa2, 0x3f, 0x20, 0x11, 0x34, 0x37, 0xe0, 0x42, 0xed, 0x6f, 0xf9, 0x1a, 0xc8, 0x7d}}}, -{{{0xd8, 0xb9, 0x11, 0xe8, 0x36, 0x3f, 0x42, 0xc1, 0xca, 0xdc, 0xd3, 0xf1, 0xc8, 0x23, 0x3d, 0x4f, 0x51, 0x7b, 0x9d, 0x8d, 0xd8, 0xe4, 0xa0, 0xaa, 0xf3, 0x04, 0xd6, 0x11, 0x93, 0xc8, 0x35, 0x45}} , - {{0x61, 0x36, 0xd6, 0x08, 0x90, 0xbf, 0xa7, 0x7a, 0x97, 0x6c, 0x0f, 0x84, 0xd5, 0x33, 0x2d, 0x37, 0xc9, 0x6a, 0x80, 0x90, 0x3d, 0x0a, 0xa2, 0xaa, 0xe1, 0xb8, 0x84, 0xba, 0x61, 0x36, 0xdd, 0x69}}}, -{{{0x6b, 0xdb, 0x5b, 0x9c, 0xc6, 0x92, 0xbc, 0x23, 0xaf, 0xc5, 0xb8, 0x75, 0xf8, 0x42, 0xfa, 0xd6, 0xb6, 0x84, 0x94, 0x63, 0x98, 0x93, 0x48, 0x78, 0x38, 0xcd, 0xbb, 0x18, 0x34, 0xc3, 0xdb, 0x67}} , - {{0x96, 0xf3, 0x3a, 0x09, 0x56, 0xb0, 0x6f, 0x7c, 0x51, 0x1e, 0x1b, 0x39, 0x48, 0xea, 0xc9, 0x0c, 0x25, 0xa2, 0x7a, 0xca, 0xe7, 0x92, 0xfc, 0x59, 0x30, 0xa3, 0x89, 0x85, 0xdf, 0x6f, 0x43, 0x38}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0x79, 0x84, 0x44, 0x19, 0xbd, 0xe9, 0x54, 0xc4, 0xc0, 0x6e, 0x2a, 0xa8, 0xa8, 0x9b, 0x43, 0xd5, 0x71, 0x22, 0x5f, 0xdc, 0x01, 0xfa, 0xdf, 0xb3, 0xb8, 0x47, 0x4b, 0x0a, 0xa5, 0x44, 0xea, 0x29}} , - {{0x05, 0x90, 0x50, 0xaf, 0x63, 0x5f, 0x9d, 0x9e, 0xe1, 0x9d, 0x38, 0x97, 0x1f, 0x6c, 0xac, 0x30, 0x46, 0xb2, 0x6a, 0x19, 0xd1, 0x4b, 0xdb, 0xbb, 0x8c, 0xda, 0x2e, 0xab, 0xc8, 0x5a, 0x77, 0x6c}}}, -{{{0x2b, 0xbe, 0xaf, 0xa1, 0x6d, 0x2f, 0x0b, 0xb1, 0x8f, 0xe3, 0xe0, 0x38, 0xcd, 0x0b, 0x41, 0x1b, 0x4a, 0x15, 0x07, 0xf3, 0x6f, 0xdc, 0xb8, 0xe9, 0xde, 0xb2, 0xa3, 0x40, 0x01, 0xa6, 0x45, 0x1e}} , - {{0x76, 0x0a, 0xda, 0x8d, 0x2c, 0x07, 0x3f, 0x89, 0x7d, 0x04, 0xad, 0x43, 0x50, 0x6e, 0xd2, 0x47, 0xcb, 0x8a, 0xe6, 0x85, 0x1a, 0x24, 0xf3, 0xd2, 0x60, 0xfd, 0xdf, 0x73, 0xa4, 0x0d, 0x73, 0x0e}}}, -{{{0xfd, 0x67, 0x6b, 0x71, 0x9b, 0x81, 0x53, 0x39, 0x39, 0xf4, 0xb8, 0xd5, 0xc3, 0x30, 0x9b, 0x3b, 0x7c, 0xa3, 0xf0, 0xd0, 0x84, 0x21, 0xd6, 0xbf, 0xb7, 0x4c, 0x87, 0x13, 0x45, 0x2d, 0xa7, 0x55}} , - {{0x5d, 0x04, 0xb3, 0x40, 0x28, 0x95, 0x2d, 0x30, 0x83, 0xec, 0x5e, 0xe4, 0xff, 0x75, 0xfe, 0x79, 0x26, 0x9d, 0x1d, 0x36, 0xcd, 0x0a, 0x15, 0xd2, 0x24, 0x14, 0x77, 0x71, 0xd7, 0x8a, 0x1b, 0x04}}}, -{{{0x5d, 0x93, 0xc9, 0xbe, 0xaa, 0x90, 0xcd, 0x9b, 0xfb, 0x73, 0x7e, 0xb0, 0x64, 0x98, 0x57, 0x44, 0x42, 0x41, 0xb1, 0xaf, 0xea, 0xc1, 0xc3, 0x22, 0xff, 0x60, 0x46, 0xcb, 0x61, 0x81, 0x70, 0x61}} , - {{0x0d, 0x82, 0xb9, 0xfe, 0x21, 0xcd, 0xc4, 0xf5, 0x98, 0x0c, 0x4e, 0x72, 0xee, 0x87, 0x49, 0xf8, 0xa1, 0x95, 0xdf, 0x8f, 0x2d, 0xbd, 0x21, 0x06, 0x7c, 0x15, 0xe8, 0x12, 0x6d, 0x93, 0xd6, 0x38}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0x91, 0xf7, 0x51, 0xd9, 0xef, 0x7d, 0x42, 0x01, 0x13, 0xe9, 0xb8, 0x7f, 0xa6, 0x49, 0x17, 0x64, 0x21, 0x80, 0x83, 0x2c, 0x63, 0x4c, 0x60, 0x09, 0x59, 0x91, 0x92, 0x77, 0x39, 0x51, 0xf4, 0x48}} , - {{0x60, 0xd5, 0x22, 0x83, 0x08, 0x2f, 0xff, 0x99, 0x3e, 0x69, 0x6d, 0x88, 0xda, 0xe7, 0x5b, 0x52, 0x26, 0x31, 0x2a, 0xe5, 0x89, 0xde, 0x68, 0x90, 0xb6, 0x22, 0x5a, 0xbd, 0xd3, 0x85, 0x53, 0x31}}}, -{{{0xd8, 0xce, 0xdc, 0xf9, 0x3c, 0x4b, 0xa2, 0x1d, 0x2c, 0x2f, 0x36, 0xbe, 0x7a, 0xfc, 0xcd, 0xbc, 0xdc, 0xf9, 0x30, 0xbd, 0xff, 0x05, 0xc7, 0xe4, 0x8e, 0x17, 0x62, 0xf8, 0x4d, 0xa0, 0x56, 0x79}} , - {{0x82, 0xe7, 0xf6, 0xba, 0x53, 0x84, 0x0a, 0xa3, 0x34, 0xff, 0x3c, 0xa3, 0x6a, 0xa1, 0x37, 0xea, 0xdd, 0xb6, 0x95, 0xb3, 0x78, 0x19, 0x76, 0x1e, 0x55, 0x2f, 0x77, 0x2e, 0x7f, 0xc1, 0xea, 0x5e}}}, -{{{0x83, 0xe1, 0x6e, 0xa9, 0x07, 0x33, 0x3e, 0x83, 0xff, 0xcb, 0x1c, 0x9f, 0xb1, 0xa3, 0xb4, 0xc9, 0xe1, 0x07, 0x97, 0xff, 0xf8, 0x23, 0x8f, 0xce, 0x40, 0xfd, 0x2e, 0x5e, 0xdb, 0x16, 0x43, 0x2d}} , - {{0xba, 0x38, 0x02, 0xf7, 0x81, 0x43, 0x83, 0xa3, 0x20, 0x4f, 0x01, 0x3b, 0x8a, 0x04, 0x38, 0x31, 0xc6, 0x0f, 0xc8, 0xdf, 0xd7, 0xfa, 0x2f, 0x88, 0x3f, 0xfc, 0x0c, 0x76, 0xc4, 0xa6, 0x45, 0x72}}}, -{{{0xbb, 0x0c, 0xbc, 0x6a, 0xa4, 0x97, 0x17, 0x93, 0x2d, 0x6f, 0xde, 0x72, 0x10, 0x1c, 0x08, 0x2c, 0x0f, 0x80, 0x32, 0x68, 0x27, 0xd4, 0xab, 0xdd, 0xc5, 0x58, 0x61, 0x13, 0x6d, 0x11, 0x1e, 0x4d}} , - {{0x1a, 0xb9, 0xc9, 0x10, 0xfb, 0x1e, 0x4e, 0xf4, 0x84, 0x4b, 0x8a, 0x5e, 0x7b, 0x4b, 0xe8, 0x43, 0x8c, 0x8f, 0x00, 0xb5, 0x54, 0x13, 0xc5, 0x5c, 0xb6, 0x35, 0x4e, 0x9d, 0xe4, 0x5b, 0x41, 0x6d}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0x15, 0x7d, 0x12, 0x48, 0x82, 0x14, 0x42, 0xcd, 0x32, 0xd4, 0x4b, 0xc1, 0x72, 0x61, 0x2a, 0x8c, 0xec, 0xe2, 0xf8, 0x24, 0x45, 0x94, 0xe3, 0xbe, 0xdd, 0x67, 0xa8, 0x77, 0x5a, 0xae, 0x5b, 0x4b}} , - {{0xcb, 0x77, 0x9a, 0x20, 0xde, 0xb8, 0x23, 0xd9, 0xa0, 0x0f, 0x8c, 0x7b, 0xa5, 0xcb, 0xae, 0xb6, 0xec, 0x42, 0x67, 0x0e, 0x58, 0xa4, 0x75, 0x98, 0x21, 0x71, 0x84, 0xb3, 0xe0, 0x76, 0x94, 0x73}}}, -{{{0xdf, 0xfc, 0x69, 0x28, 0x23, 0x3f, 0x5b, 0xf8, 0x3b, 0x24, 0x37, 0xf3, 0x1d, 0xd5, 0x22, 0x6b, 0xd0, 0x98, 0xa8, 0x6c, 0xcf, 0xff, 0x06, 0xe1, 0x13, 0xdf, 0xb9, 0xc1, 0x0c, 0xa9, 0xbf, 0x33}} , - {{0xd9, 0x81, 0xda, 0xb2, 0x4f, 0x82, 0x9d, 0x43, 0x81, 0x09, 0xf1, 0xd2, 0x01, 0xef, 0xac, 0xf4, 0x2d, 0x7d, 0x01, 0x09, 0xf1, 0xff, 0xa5, 0x9f, 0xe5, 0xca, 0x27, 0x63, 0xdb, 0x20, 0xb1, 0x53}}}, -{{{0x67, 0x02, 0xe8, 0xad, 0xa9, 0x34, 0xd4, 0xf0, 0x15, 0x81, 0xaa, 0xc7, 0x4d, 0x87, 0x94, 0xea, 0x75, 0xe7, 0x4c, 0x94, 0x04, 0x0e, 0x69, 0x87, 0xe7, 0x51, 0x91, 0x10, 0x03, 0xc7, 0xbe, 0x56}} , - {{0x32, 0xfb, 0x86, 0xec, 0x33, 0x6b, 0x2e, 0x51, 0x2b, 0xc8, 0xfa, 0x6c, 0x70, 0x47, 0x7e, 0xce, 0x05, 0x0c, 0x71, 0xf3, 0xb4, 0x56, 0xa6, 0xdc, 0xcc, 0x78, 0x07, 0x75, 0xd0, 0xdd, 0xb2, 0x6a}}}, -{{{0xc6, 0xef, 0xb9, 0xc0, 0x2b, 0x22, 0x08, 0x1e, 0x71, 0x70, 0xb3, 0x35, 0x9c, 0x7a, 0x01, 0x92, 0x44, 0x9a, 0xf6, 0xb0, 0x58, 0x95, 0xc1, 0x9b, 0x02, 0xed, 0x2d, 0x7c, 0x34, 0x29, 0x49, 0x44}} , - {{0x45, 0x62, 0x1d, 0x2e, 0xff, 0x2a, 0x1c, 0x21, 0xa4, 0x25, 0x7b, 0x0d, 0x8c, 0x15, 0x39, 0xfc, 0x8f, 0x7c, 0xa5, 0x7d, 0x1e, 0x25, 0xa3, 0x45, 0xd6, 0xab, 0xbd, 0xcb, 0xc5, 0x5e, 0x78, 0x77}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0xd0, 0xd3, 0x42, 0xed, 0x1d, 0x00, 0x3c, 0x15, 0x2c, 0x9c, 0x77, 0x81, 0xd2, 0x73, 0xd1, 0x06, 0xd5, 0xc4, 0x7f, 0x94, 0xbb, 0x92, 0x2d, 0x2c, 0x4b, 0x45, 0x4b, 0xe9, 0x2a, 0x89, 0x6b, 0x2b}} , - {{0xd2, 0x0c, 0x88, 0xc5, 0x48, 0x4d, 0xea, 0x0d, 0x4a, 0xc9, 0x52, 0x6a, 0x61, 0x79, 0xe9, 0x76, 0xf3, 0x85, 0x52, 0x5c, 0x1b, 0x2c, 0xe1, 0xd6, 0xc4, 0x0f, 0x18, 0x0e, 0x4e, 0xf6, 0x1c, 0x7f}}}, -{{{0xb4, 0x04, 0x2e, 0x42, 0xcb, 0x1f, 0x2b, 0x11, 0x51, 0x7b, 0x08, 0xac, 0xaa, 0x3e, 0x9e, 0x52, 0x60, 0xb7, 0xc2, 0x61, 0x57, 0x8c, 0x84, 0xd5, 0x18, 0xa6, 0x19, 0xfc, 0xb7, 0x75, 0x91, 0x1b}} , - {{0xe8, 0x68, 0xca, 0x44, 0xc8, 0x38, 0x38, 0xcc, 0x53, 0x0a, 0x32, 0x35, 0xcc, 0x52, 0xcb, 0x0e, 0xf7, 0xc5, 0xe7, 0xec, 0x3d, 0x85, 0xcc, 0x58, 0xe2, 0x17, 0x47, 0xff, 0x9f, 0xa5, 0x30, 0x17}}}, -{{{0xe3, 0xae, 0xc8, 0xc1, 0x71, 0x75, 0x31, 0x00, 0x37, 0x41, 0x5c, 0x0e, 0x39, 0xda, 0x73, 0xa0, 0xc7, 0x97, 0x36, 0x6c, 0x5b, 0xf2, 0xee, 0x64, 0x0a, 0x3d, 0x89, 0x1e, 0x1d, 0x49, 0x8c, 0x37}} , - {{0x4c, 0xe6, 0xb0, 0xc1, 0xa5, 0x2a, 0x82, 0x09, 0x08, 0xad, 0x79, 0x9c, 0x56, 0xf6, 0xf9, 0xc1, 0xd7, 0x7c, 0x39, 0x7f, 0x93, 0xca, 0x11, 0x55, 0xbf, 0x07, 0x1b, 0x82, 0x29, 0x69, 0x95, 0x5c}}}, -{{{0x87, 0xee, 0xa6, 0x56, 0x9e, 0xc2, 0x9a, 0x56, 0x24, 0x42, 0x85, 0x4d, 0x98, 0x31, 0x1e, 0x60, 0x4d, 0x87, 0x85, 0x04, 0xae, 0x46, 0x12, 0xf9, 0x8e, 0x7f, 0xe4, 0x7f, 0xf6, 0x1c, 0x37, 0x01}} , - {{0x73, 0x4c, 0xb6, 0xc5, 0xc4, 0xe9, 0x6c, 0x85, 0x48, 0x4a, 0x5a, 0xac, 0xd9, 0x1f, 0x43, 0xf8, 0x62, 0x5b, 0xee, 0x98, 0x2a, 0x33, 0x8e, 0x79, 0xce, 0x61, 0x06, 0x35, 0xd8, 0xd7, 0xca, 0x71}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0x72, 0xd3, 0xae, 0xa6, 0xca, 0x8f, 0xcd, 0xcc, 0x78, 0x8e, 0x19, 0x4d, 0xa7, 0xd2, 0x27, 0xe9, 0xa4, 0x3c, 0x16, 0x5b, 0x84, 0x80, 0xf9, 0xd0, 0xcc, 0x6a, 0x1e, 0xca, 0x1e, 0x67, 0xbd, 0x63}} , - {{0x7b, 0x6e, 0x2a, 0xd2, 0x87, 0x48, 0xff, 0xa1, 0xca, 0xe9, 0x15, 0x85, 0xdc, 0xdb, 0x2c, 0x39, 0x12, 0x91, 0xa9, 0x20, 0xaa, 0x4f, 0x29, 0xf4, 0x15, 0x7a, 0xd2, 0xf5, 0x32, 0xcc, 0x60, 0x04}}}, -{{{0xe5, 0x10, 0x47, 0x3b, 0xfa, 0x90, 0xfc, 0x30, 0xb5, 0xea, 0x6f, 0x56, 0x8f, 0xfb, 0x0e, 0xa7, 0x3b, 0xc8, 0xb2, 0xff, 0x02, 0x7a, 0x33, 0x94, 0x93, 0x2a, 0x03, 0xe0, 0x96, 0x3a, 0x6c, 0x0f}} , - {{0x5a, 0x63, 0x67, 0xe1, 0x9b, 0x47, 0x78, 0x9f, 0x38, 0x79, 0xac, 0x97, 0x66, 0x1d, 0x5e, 0x51, 0xee, 0x24, 0x42, 0xe8, 0x58, 0x4b, 0x8a, 0x03, 0x75, 0x86, 0x37, 0x86, 0xe2, 0x97, 0x4e, 0x3d}}}, -{{{0x3f, 0x75, 0x8e, 0xb4, 0xff, 0xd8, 0xdd, 0xd6, 0x37, 0x57, 0x9d, 0x6d, 0x3b, 0xbd, 0xd5, 0x60, 0x88, 0x65, 0x9a, 0xb9, 0x4a, 0x68, 0x84, 0xa2, 0x67, 0xdd, 0x17, 0x25, 0x97, 0x04, 0x8b, 0x5e}} , - {{0xbb, 0x40, 0x5e, 0xbc, 0x16, 0x92, 0x05, 0xc4, 0xc0, 0x4e, 0x72, 0x90, 0x0e, 0xab, 0xcf, 0x8a, 0xed, 0xef, 0xb9, 0x2d, 0x3b, 0xf8, 0x43, 0x5b, 0xba, 0x2d, 0xeb, 0x2f, 0x52, 0xd2, 0xd1, 0x5a}}}, -{{{0x40, 0xb4, 0xab, 0xe6, 0xad, 0x9f, 0x46, 0x69, 0x4a, 0xb3, 0x8e, 0xaa, 0xea, 0x9c, 0x8a, 0x20, 0x16, 0x5d, 0x8c, 0x13, 0xbd, 0xf6, 0x1d, 0xc5, 0x24, 0xbd, 0x90, 0x2a, 0x1c, 0xc7, 0x13, 0x3b}} , - {{0x54, 0xdc, 0x16, 0x0d, 0x18, 0xbe, 0x35, 0x64, 0x61, 0x52, 0x02, 0x80, 0xaf, 0x05, 0xf7, 0xa6, 0x42, 0xd3, 0x8f, 0x2e, 0x79, 0x26, 0xa8, 0xbb, 0xb2, 0x17, 0x48, 0xb2, 0x7a, 0x0a, 0x89, 0x14}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0x20, 0xa8, 0x88, 0xe3, 0x91, 0xc0, 0x6e, 0xbb, 0x8a, 0x27, 0x82, 0x51, 0x83, 0xb2, 0x28, 0xa9, 0x83, 0xeb, 0xa6, 0xa9, 0x4d, 0x17, 0x59, 0x22, 0x54, 0x00, 0x50, 0x45, 0xcb, 0x48, 0x4b, 0x18}} , - {{0x33, 0x7c, 0xe7, 0x26, 0xba, 0x4d, 0x32, 0xfe, 0x53, 0xf4, 0xfa, 0x83, 0xe3, 0xa5, 0x79, 0x66, 0x73, 0xef, 0x80, 0x23, 0x68, 0xc2, 0x60, 0xdd, 0xa9, 0x33, 0xdc, 0x03, 0x7a, 0xe0, 0xe0, 0x3e}}}, -{{{0x34, 0x5c, 0x13, 0xfb, 0xc0, 0xe3, 0x78, 0x2b, 0x54, 0x58, 0x22, 0x9b, 0x76, 0x81, 0x7f, 0x93, 0x9c, 0x25, 0x3c, 0xd2, 0xe9, 0x96, 0x21, 0x26, 0x08, 0xf5, 0xed, 0x95, 0x11, 0xae, 0x04, 0x5a}} , - {{0xb9, 0xe8, 0xc5, 0x12, 0x97, 0x1f, 0x83, 0xfe, 0x3e, 0x94, 0x99, 0xd4, 0x2d, 0xf9, 0x52, 0x59, 0x5c, 0x82, 0xa6, 0xf0, 0x75, 0x7e, 0xe8, 0xec, 0xcc, 0xac, 0x18, 0x21, 0x09, 0x67, 0x66, 0x67}}}, -{{{0xb3, 0x40, 0x29, 0xd1, 0xcb, 0x1b, 0x08, 0x9e, 0x9c, 0xb7, 0x53, 0xb9, 0x3b, 0x71, 0x08, 0x95, 0x12, 0x1a, 0x58, 0xaf, 0x7e, 0x82, 0x52, 0x43, 0x4f, 0x11, 0x39, 0xf4, 0x93, 0x1a, 0x26, 0x05}} , - {{0x6e, 0x44, 0xa3, 0xf9, 0x64, 0xaf, 0xe7, 0x6d, 0x7d, 0xdf, 0x1e, 0xac, 0x04, 0xea, 0x3b, 0x5f, 0x9b, 0xe8, 0x24, 0x9d, 0x0e, 0xe5, 0x2e, 0x3e, 0xdf, 0xa9, 0xf7, 0xd4, 0x50, 0x71, 0xf0, 0x78}}}, -{{{0x3e, 0xa8, 0x38, 0xc2, 0x57, 0x56, 0x42, 0x9a, 0xb1, 0xe2, 0xf8, 0x45, 0xaa, 0x11, 0x48, 0x5f, 0x17, 0xc4, 0x54, 0x27, 0xdc, 0x5d, 0xaa, 0xdd, 0x41, 0xbc, 0xdf, 0x81, 0xb9, 0x53, 0xee, 0x52}} , - {{0xc3, 0xf1, 0xa7, 0x6d, 0xb3, 0x5f, 0x92, 0x6f, 0xcc, 0x91, 0xb8, 0x95, 0x05, 0xdf, 0x3c, 0x64, 0x57, 0x39, 0x61, 0x51, 0xad, 0x8c, 0x38, 0x7b, 0xc8, 0xde, 0x00, 0x34, 0xbe, 0xa1, 0xb0, 0x7e}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0x25, 0x24, 0x1d, 0x8a, 0x67, 0x20, 0xee, 0x42, 0xeb, 0x38, 0xed, 0x0b, 0x8b, 0xcd, 0x46, 0x9d, 0x5e, 0x6b, 0x1e, 0x24, 0x9d, 0x12, 0x05, 0x1a, 0xcc, 0x05, 0x4e, 0x92, 0x38, 0xe1, 0x1f, 0x50}} , - {{0x4e, 0xee, 0x1c, 0x91, 0xe6, 0x11, 0xbd, 0x8e, 0x55, 0x1a, 0x18, 0x75, 0x66, 0xaf, 0x4d, 0x7b, 0x0f, 0xae, 0x6d, 0x85, 0xca, 0x82, 0x58, 0x21, 0x9c, 0x18, 0xe0, 0xed, 0xec, 0x22, 0x80, 0x2f}}}, -{{{0x68, 0x3b, 0x0a, 0x39, 0x1d, 0x6a, 0x15, 0x57, 0xfc, 0xf0, 0x63, 0x54, 0xdb, 0x39, 0xdb, 0xe8, 0x5c, 0x64, 0xff, 0xa0, 0x09, 0x4f, 0x3b, 0xb7, 0x32, 0x60, 0x99, 0x94, 0xfd, 0x94, 0x82, 0x2d}} , - {{0x24, 0xf6, 0x5a, 0x44, 0xf1, 0x55, 0x2c, 0xdb, 0xea, 0x7c, 0x84, 0x7c, 0x01, 0xac, 0xe3, 0xfd, 0xc9, 0x27, 0xc1, 0x5a, 0xb9, 0xde, 0x4f, 0x5a, 0x90, 0xdd, 0xc6, 0x67, 0xaa, 0x6f, 0x8a, 0x3a}}}, -{{{0x78, 0x52, 0x87, 0xc9, 0x97, 0x63, 0xb1, 0xdd, 0x54, 0x5f, 0xc1, 0xf8, 0xf1, 0x06, 0xa6, 0xa8, 0xa3, 0x88, 0x82, 0xd4, 0xcb, 0xa6, 0x19, 0xdd, 0xd1, 0x11, 0x87, 0x08, 0x17, 0x4c, 0x37, 0x2a}} , - {{0xa1, 0x0c, 0xf3, 0x08, 0x43, 0xd9, 0x24, 0x1e, 0x83, 0xa7, 0xdf, 0x91, 0xca, 0xbd, 0x69, 0x47, 0x8d, 0x1b, 0xe2, 0xb9, 0x4e, 0xb5, 0xe1, 0x76, 0xb3, 0x1c, 0x93, 0x03, 0xce, 0x5f, 0xb3, 0x5a}}}, -{{{0x1d, 0xda, 0xe4, 0x61, 0x03, 0x50, 0xa9, 0x8b, 0x68, 0x18, 0xef, 0xb2, 0x1c, 0x84, 0x3b, 0xa2, 0x44, 0x95, 0xa3, 0x04, 0x3b, 0xd6, 0x99, 0x00, 0xaf, 0x76, 0x42, 0x67, 0x02, 0x7d, 0x85, 0x56}} , - {{0xce, 0x72, 0x0e, 0x29, 0x84, 0xb2, 0x7d, 0xd2, 0x45, 0xbe, 0x57, 0x06, 0xed, 0x7f, 0xcf, 0xed, 0xcd, 0xef, 0x19, 0xd6, 0xbc, 0x15, 0x79, 0x64, 0xd2, 0x18, 0xe3, 0x20, 0x67, 0x3a, 0x54, 0x0b}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0x52, 0xfd, 0x04, 0xc5, 0xfb, 0x99, 0xe7, 0xe8, 0xfb, 0x8c, 0xe1, 0x42, 0x03, 0xef, 0x9d, 0xd9, 0x9e, 0x4d, 0xf7, 0x80, 0xcf, 0x2e, 0xcc, 0x9b, 0x45, 0xc9, 0x7b, 0x7a, 0xbc, 0x37, 0xa8, 0x52}} , - {{0x96, 0x11, 0x41, 0x8a, 0x47, 0x91, 0xfe, 0xb6, 0xda, 0x7a, 0x54, 0x63, 0xd1, 0x14, 0x35, 0x05, 0x86, 0x8c, 0xa9, 0x36, 0x3f, 0xf2, 0x85, 0x54, 0x4e, 0x92, 0xd8, 0x85, 0x01, 0x46, 0xd6, 0x50}}}, -{{{0x53, 0xcd, 0xf3, 0x86, 0x40, 0xe6, 0x39, 0x42, 0x95, 0xd6, 0xcb, 0x45, 0x1a, 0x20, 0xc8, 0x45, 0x4b, 0x32, 0x69, 0x04, 0xb1, 0xaf, 0x20, 0x46, 0xc7, 0x6b, 0x23, 0x5b, 0x69, 0xee, 0x30, 0x3f}} , - {{0x70, 0x83, 0x47, 0xc0, 0xdb, 0x55, 0x08, 0xa8, 0x7b, 0x18, 0x6d, 0xf5, 0x04, 0x5a, 0x20, 0x0c, 0x4a, 0x8c, 0x60, 0xae, 0xae, 0x0f, 0x64, 0x55, 0x55, 0x2e, 0xd5, 0x1d, 0x53, 0x31, 0x42, 0x41}}}, -{{{0xca, 0xfc, 0x88, 0x6b, 0x96, 0x78, 0x0a, 0x8b, 0x83, 0xdc, 0xbc, 0xaf, 0x40, 0xb6, 0x8d, 0x7f, 0xef, 0xb4, 0xd1, 0x3f, 0xcc, 0xa2, 0x74, 0xc9, 0xc2, 0x92, 0x55, 0x00, 0xab, 0xdb, 0xbf, 0x4f}} , - {{0x93, 0x1c, 0x06, 0x2d, 0x66, 0x65, 0x02, 0xa4, 0x97, 0x18, 0xfd, 0x00, 0xe7, 0xab, 0x03, 0xec, 0xce, 0xc1, 0xbf, 0x37, 0xf8, 0x13, 0x53, 0xa5, 0xe5, 0x0c, 0x3a, 0xa8, 0x55, 0xb9, 0xff, 0x68}}}, -{{{0xe4, 0xe6, 0x6d, 0x30, 0x7d, 0x30, 0x35, 0xc2, 0x78, 0x87, 0xf9, 0xfc, 0x6b, 0x5a, 0xc3, 0xb7, 0x65, 0xd8, 0x2e, 0xc7, 0xa5, 0x0c, 0xc6, 0xdc, 0x12, 0xaa, 0xd6, 0x4f, 0xc5, 0x38, 0xbc, 0x0e}} , - {{0xe2, 0x3c, 0x76, 0x86, 0x38, 0xf2, 0x7b, 0x2c, 0x16, 0x78, 0x8d, 0xf5, 0xa4, 0x15, 0xda, 0xdb, 0x26, 0x85, 0xa0, 0x56, 0xdd, 0x1d, 0xe3, 0xb3, 0xfd, 0x40, 0xef, 0xf2, 0xd9, 0xa1, 0xb3, 0x04}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0xdb, 0x49, 0x0e, 0xe6, 0x58, 0x10, 0x7a, 0x52, 0xda, 0xb5, 0x7d, 0x37, 0x6a, 0x3e, 0xa1, 0x78, 0xce, 0xc7, 0x1c, 0x24, 0x23, 0xdb, 0x7d, 0xfb, 0x8c, 0x8d, 0xdc, 0x30, 0x67, 0x69, 0x75, 0x3b}} , - {{0xa9, 0xea, 0x6d, 0x16, 0x16, 0x60, 0xf4, 0x60, 0x87, 0x19, 0x44, 0x8c, 0x4a, 0x8b, 0x3e, 0xfb, 0x16, 0x00, 0x00, 0x54, 0xa6, 0x9e, 0x9f, 0xef, 0xcf, 0xd9, 0xd2, 0x4c, 0x74, 0x31, 0xd0, 0x34}}}, -{{{0xa4, 0xeb, 0x04, 0xa4, 0x8c, 0x8f, 0x71, 0x27, 0x95, 0x85, 0x5d, 0x55, 0x4b, 0xb1, 0x26, 0x26, 0xc8, 0xae, 0x6a, 0x7d, 0xa2, 0x21, 0xca, 0xce, 0x38, 0xab, 0x0f, 0xd0, 0xd5, 0x2b, 0x6b, 0x00}} , - {{0xe5, 0x67, 0x0c, 0xf1, 0x3a, 0x9a, 0xea, 0x09, 0x39, 0xef, 0xd1, 0x30, 0xbc, 0x33, 0xba, 0xb1, 0x6a, 0xc5, 0x27, 0x08, 0x7f, 0x54, 0x80, 0x3d, 0xab, 0xf6, 0x15, 0x7a, 0xc2, 0x40, 0x73, 0x72}}}, -{{{0x84, 0x56, 0x82, 0xb6, 0x12, 0x70, 0x7f, 0xf7, 0xf0, 0xbd, 0x5b, 0xa9, 0xd5, 0xc5, 0x5f, 0x59, 0xbf, 0x7f, 0xb3, 0x55, 0x22, 0x02, 0xc9, 0x44, 0x55, 0x87, 0x8f, 0x96, 0x98, 0x64, 0x6d, 0x15}} , - {{0xb0, 0x8b, 0xaa, 0x1e, 0xec, 0xc7, 0xa5, 0x8f, 0x1f, 0x92, 0x04, 0xc6, 0x05, 0xf6, 0xdf, 0xa1, 0xcc, 0x1f, 0x81, 0xf5, 0x0e, 0x9c, 0x57, 0xdc, 0xe3, 0xbb, 0x06, 0x87, 0x1e, 0xfe, 0x23, 0x6c}}}, -{{{0xd8, 0x2b, 0x5b, 0x16, 0xea, 0x20, 0xf1, 0xd3, 0x68, 0x8f, 0xae, 0x5b, 0xd0, 0xa9, 0x1a, 0x19, 0xa8, 0x36, 0xfb, 0x2b, 0x57, 0x88, 0x7d, 0x90, 0xd5, 0xa6, 0xf3, 0xdc, 0x38, 0x89, 0x4e, 0x1f}} , - {{0xcc, 0x19, 0xda, 0x9b, 0x3b, 0x43, 0x48, 0x21, 0x2e, 0x23, 0x4d, 0x3d, 0xae, 0xf8, 0x8c, 0xfc, 0xdd, 0xa6, 0x74, 0x37, 0x65, 0xca, 0xee, 0x1a, 0x19, 0x8e, 0x9f, 0x64, 0x6f, 0x0c, 0x8b, 0x5a}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0x25, 0xb9, 0xc2, 0xf0, 0x72, 0xb8, 0x15, 0x16, 0xcc, 0x8d, 0x3c, 0x6f, 0x25, 0xed, 0xf4, 0x46, 0x2e, 0x0c, 0x60, 0x0f, 0xe2, 0x84, 0x34, 0x55, 0x89, 0x59, 0x34, 0x1b, 0xf5, 0x8d, 0xfe, 0x08}} , - {{0xf8, 0xab, 0x93, 0xbc, 0x44, 0xba, 0x1b, 0x75, 0x4b, 0x49, 0x6f, 0xd0, 0x54, 0x2e, 0x63, 0xba, 0xb5, 0xea, 0xed, 0x32, 0x14, 0xc9, 0x94, 0xd8, 0xc5, 0xce, 0xf4, 0x10, 0x68, 0xe0, 0x38, 0x27}}}, -{{{0x74, 0x1c, 0x14, 0x9b, 0xd4, 0x64, 0x61, 0x71, 0x5a, 0xb6, 0x21, 0x33, 0x4f, 0xf7, 0x8e, 0xba, 0xa5, 0x48, 0x9a, 0xc7, 0xfa, 0x9a, 0xf0, 0xb4, 0x62, 0xad, 0xf2, 0x5e, 0xcc, 0x03, 0x24, 0x1a}} , - {{0xf5, 0x76, 0xfd, 0xe4, 0xaf, 0xb9, 0x03, 0x59, 0xce, 0x63, 0xd2, 0x3b, 0x1f, 0xcd, 0x21, 0x0c, 0xad, 0x44, 0xa5, 0x97, 0xac, 0x80, 0x11, 0x02, 0x9b, 0x0c, 0xe5, 0x8b, 0xcd, 0xfb, 0x79, 0x77}}}, -{{{0x15, 0xbe, 0x9a, 0x0d, 0xba, 0x38, 0x72, 0x20, 0x8a, 0xf5, 0xbe, 0x59, 0x93, 0x79, 0xb7, 0xf6, 0x6a, 0x0c, 0x38, 0x27, 0x1a, 0x60, 0xf4, 0x86, 0x3b, 0xab, 0x5a, 0x00, 0xa0, 0xce, 0x21, 0x7d}} , - {{0x6c, 0xba, 0x14, 0xc5, 0xea, 0x12, 0x9e, 0x2e, 0x82, 0x63, 0xce, 0x9b, 0x4a, 0xe7, 0x1d, 0xec, 0xf1, 0x2e, 0x51, 0x1c, 0xf4, 0xd0, 0x69, 0x15, 0x42, 0x9d, 0xa3, 0x3f, 0x0e, 0xbf, 0xe9, 0x5c}}}, -{{{0xe4, 0x0d, 0xf4, 0xbd, 0xee, 0x31, 0x10, 0xed, 0xcb, 0x12, 0x86, 0xad, 0xd4, 0x2f, 0x90, 0x37, 0x32, 0xc3, 0x0b, 0x73, 0xec, 0x97, 0x85, 0xa4, 0x01, 0x1c, 0x76, 0x35, 0xfe, 0x75, 0xdd, 0x71}} , - {{0x11, 0xa4, 0x88, 0x9f, 0x3e, 0x53, 0x69, 0x3b, 0x1b, 0xe0, 0xf7, 0xba, 0x9b, 0xad, 0x4e, 0x81, 0x5f, 0xb5, 0x5c, 0xae, 0xbe, 0x67, 0x86, 0x37, 0x34, 0x8e, 0x07, 0x32, 0x45, 0x4a, 0x67, 0x39}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0x90, 0x70, 0x58, 0x20, 0x03, 0x1e, 0x67, 0xb2, 0xc8, 0x9b, 0x58, 0xc5, 0xb1, 0xeb, 0x2d, 0x4a, 0xde, 0x82, 0x8c, 0xf2, 0xd2, 0x14, 0xb8, 0x70, 0x61, 0x4e, 0x73, 0xd6, 0x0b, 0x6b, 0x0d, 0x30}} , - {{0x81, 0xfc, 0x55, 0x5c, 0xbf, 0xa7, 0xc4, 0xbd, 0xe2, 0xf0, 0x4b, 0x8f, 0xe9, 0x7d, 0x99, 0xfa, 0xd3, 0xab, 0xbc, 0xc7, 0x83, 0x2b, 0x04, 0x7f, 0x0c, 0x19, 0x43, 0x03, 0x3d, 0x07, 0xca, 0x40}}}, -{{{0xf9, 0xc8, 0xbe, 0x8c, 0x16, 0x81, 0x39, 0x96, 0xf6, 0x17, 0x58, 0xc8, 0x30, 0x58, 0xfb, 0xc2, 0x03, 0x45, 0xd2, 0x52, 0x76, 0xe0, 0x6a, 0x26, 0x28, 0x5c, 0x88, 0x59, 0x6a, 0x5a, 0x54, 0x42}} , - {{0x07, 0xb5, 0x2e, 0x2c, 0x67, 0x15, 0x9b, 0xfb, 0x83, 0x69, 0x1e, 0x0f, 0xda, 0xd6, 0x29, 0xb1, 0x60, 0xe0, 0xb2, 0xba, 0x69, 0xa2, 0x9e, 0xbd, 0xbd, 0xe0, 0x1c, 0xbd, 0xcd, 0x06, 0x64, 0x70}}}, -{{{0x41, 0xfa, 0x8c, 0xe1, 0x89, 0x8f, 0x27, 0xc8, 0x25, 0x8f, 0x6f, 0x5f, 0x55, 0xf8, 0xde, 0x95, 0x6d, 0x2f, 0x75, 0x16, 0x2b, 0x4e, 0x44, 0xfd, 0x86, 0x6e, 0xe9, 0x70, 0x39, 0x76, 0x97, 0x7e}} , - {{0x17, 0x62, 0x6b, 0x14, 0xa1, 0x7c, 0xd0, 0x79, 0x6e, 0xd8, 0x8a, 0xa5, 0x6d, 0x8c, 0x93, 0xd2, 0x3f, 0xec, 0x44, 0x8d, 0x6e, 0x91, 0x01, 0x8c, 0x8f, 0xee, 0x01, 0x8f, 0xc0, 0xb4, 0x85, 0x0e}}}, -{{{0x02, 0x3a, 0x70, 0x41, 0xe4, 0x11, 0x57, 0x23, 0xac, 0xe6, 0xfc, 0x54, 0x7e, 0xcd, 0xd7, 0x22, 0xcb, 0x76, 0x9f, 0x20, 0xce, 0xa0, 0x73, 0x76, 0x51, 0x3b, 0xa4, 0xf8, 0xe3, 0x62, 0x12, 0x6c}} , - {{0x7f, 0x00, 0x9c, 0x26, 0x0d, 0x6f, 0x48, 0x7f, 0x3a, 0x01, 0xed, 0xc5, 0x96, 0xb0, 0x1f, 0x4f, 0xa8, 0x02, 0x62, 0x27, 0x8a, 0x50, 0x8d, 0x9a, 0x8b, 0x52, 0x0f, 0x1e, 0xcf, 0x41, 0x38, 0x19}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0xf5, 0x6c, 0xd4, 0x2f, 0x0f, 0x69, 0x0f, 0x87, 0x3f, 0x61, 0x65, 0x1e, 0x35, 0x34, 0x85, 0xba, 0x02, 0x30, 0xac, 0x25, 0x3d, 0xe2, 0x62, 0xf1, 0xcc, 0xe9, 0x1b, 0xc2, 0xef, 0x6a, 0x42, 0x57}} , - {{0x34, 0x1f, 0x2e, 0xac, 0xd1, 0xc7, 0x04, 0x52, 0x32, 0x66, 0xb2, 0x33, 0x73, 0x21, 0x34, 0x54, 0xf7, 0x71, 0xed, 0x06, 0xb0, 0xff, 0xa6, 0x59, 0x6f, 0x8a, 0x4e, 0xfb, 0x02, 0xb0, 0x45, 0x6b}}}, -{{{0xf5, 0x48, 0x0b, 0x03, 0xc5, 0x22, 0x7d, 0x80, 0x08, 0x53, 0xfe, 0x32, 0xb1, 0xa1, 0x8a, 0x74, 0x6f, 0xbd, 0x3f, 0x85, 0xf4, 0xcf, 0xf5, 0x60, 0xaf, 0x41, 0x7e, 0x3e, 0x46, 0xa3, 0x5a, 0x20}} , - {{0xaa, 0x35, 0x87, 0x44, 0x63, 0x66, 0x97, 0xf8, 0x6e, 0x55, 0x0c, 0x04, 0x3e, 0x35, 0x50, 0xbf, 0x93, 0x69, 0xd2, 0x8b, 0x05, 0x55, 0x99, 0xbe, 0xe2, 0x53, 0x61, 0xec, 0xe8, 0x08, 0x0b, 0x32}}}, -{{{0xb3, 0x10, 0x45, 0x02, 0x69, 0x59, 0x2e, 0x97, 0xd9, 0x64, 0xf8, 0xdb, 0x25, 0x80, 0xdc, 0xc4, 0xd5, 0x62, 0x3c, 0xed, 0x65, 0x91, 0xad, 0xd1, 0x57, 0x81, 0x94, 0xaa, 0xa1, 0x29, 0xfc, 0x68}} , - {{0xdd, 0xb5, 0x7d, 0xab, 0x5a, 0x21, 0x41, 0x53, 0xbb, 0x17, 0x79, 0x0d, 0xd1, 0xa8, 0x0c, 0x0c, 0x20, 0x88, 0x09, 0xe9, 0x84, 0xe8, 0x25, 0x11, 0x67, 0x7a, 0x8b, 0x1a, 0xe4, 0x5d, 0xe1, 0x5d}}}, -{{{0x37, 0xea, 0xfe, 0x65, 0x3b, 0x25, 0xe8, 0xe1, 0xc2, 0xc5, 0x02, 0xa4, 0xbe, 0x98, 0x0a, 0x2b, 0x61, 0xc1, 0x9b, 0xe2, 0xd5, 0x92, 0xe6, 0x9e, 0x7d, 0x1f, 0xca, 0x43, 0x88, 0x8b, 0x2c, 0x59}} , - {{0xe0, 0xb5, 0x00, 0x1d, 0x2a, 0x6f, 0xaf, 0x79, 0x86, 0x2f, 0xa6, 0x5a, 0x93, 0xd1, 0xfe, 0xae, 0x3a, 0xee, 0xdb, 0x7c, 0x61, 0xbe, 0x7c, 0x01, 0xf9, 0xfe, 0x52, 0xdc, 0xd8, 0x52, 0xa3, 0x42}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0x22, 0xaf, 0x13, 0x37, 0xbd, 0x37, 0x71, 0xac, 0x04, 0x46, 0x63, 0xac, 0xa4, 0x77, 0xed, 0x25, 0x38, 0xe0, 0x15, 0xa8, 0x64, 0x00, 0x0d, 0xce, 0x51, 0x01, 0xa9, 0xbc, 0x0f, 0x03, 0x1c, 0x04}} , - {{0x89, 0xf9, 0x80, 0x07, 0xcf, 0x3f, 0xb3, 0xe9, 0xe7, 0x45, 0x44, 0x3d, 0x2a, 0x7c, 0xe9, 0xe4, 0x16, 0x5c, 0x5e, 0x65, 0x1c, 0xc7, 0x7d, 0xc6, 0x7a, 0xfb, 0x43, 0xee, 0x25, 0x76, 0x46, 0x72}}}, -{{{0x02, 0xa2, 0xed, 0xf4, 0x8f, 0x6b, 0x0b, 0x3e, 0xeb, 0x35, 0x1a, 0xd5, 0x7e, 0xdb, 0x78, 0x00, 0x96, 0x8a, 0xa0, 0xb4, 0xcf, 0x60, 0x4b, 0xd4, 0xd5, 0xf9, 0x2d, 0xbf, 0x88, 0xbd, 0x22, 0x62}} , - {{0x13, 0x53, 0xe4, 0x82, 0x57, 0xfa, 0x1e, 0x8f, 0x06, 0x2b, 0x90, 0xba, 0x08, 0xb6, 0x10, 0x54, 0x4f, 0x7c, 0x1b, 0x26, 0xed, 0xda, 0x6b, 0xdd, 0x25, 0xd0, 0x4e, 0xea, 0x42, 0xbb, 0x25, 0x03}}}, -{{{0x51, 0x16, 0x50, 0x7c, 0xd5, 0x5d, 0xf6, 0x99, 0xe8, 0x77, 0x72, 0x4e, 0xfa, 0x62, 0xcb, 0x76, 0x75, 0x0c, 0xe2, 0x71, 0x98, 0x92, 0xd5, 0xfa, 0x45, 0xdf, 0x5c, 0x6f, 0x1e, 0x9e, 0x28, 0x69}} , - {{0x0d, 0xac, 0x66, 0x6d, 0xc3, 0x8b, 0xba, 0x16, 0xb5, 0xe2, 0xa0, 0x0d, 0x0c, 0xbd, 0xa4, 0x8e, 0x18, 0x6c, 0xf2, 0xdc, 0xf9, 0xdc, 0x4a, 0x86, 0x25, 0x95, 0x14, 0xcb, 0xd8, 0x1a, 0x04, 0x0f}}}, -{{{0x97, 0xa5, 0xdb, 0x8b, 0x2d, 0xaa, 0x42, 0x11, 0x09, 0xf2, 0x93, 0xbb, 0xd9, 0x06, 0x84, 0x4e, 0x11, 0xa8, 0xa0, 0x25, 0x2b, 0xa6, 0x5f, 0xae, 0xc4, 0xb4, 0x4c, 0xc8, 0xab, 0xc7, 0x3b, 0x02}} , - {{0xee, 0xc9, 0x29, 0x0f, 0xdf, 0x11, 0x85, 0xed, 0xce, 0x0d, 0x62, 0x2c, 0x8f, 0x4b, 0xf9, 0x04, 0xe9, 0x06, 0x72, 0x1d, 0x37, 0x20, 0x50, 0xc9, 0x14, 0xeb, 0xec, 0x39, 0xa7, 0x97, 0x2b, 0x4d}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0x69, 0xd1, 0x39, 0xbd, 0xfb, 0x33, 0xbe, 0xc4, 0xf0, 0x5c, 0xef, 0xf0, 0x56, 0x68, 0xfc, 0x97, 0x47, 0xc8, 0x72, 0xb6, 0x53, 0xa4, 0x0a, 0x98, 0xa5, 0xb4, 0x37, 0x71, 0xcf, 0x66, 0x50, 0x6d}} , - {{0x17, 0xa4, 0x19, 0x52, 0x11, 0x47, 0xb3, 0x5c, 0x5b, 0xa9, 0x2e, 0x22, 0xb4, 0x00, 0x52, 0xf9, 0x57, 0x18, 0xb8, 0xbe, 0x5a, 0xe3, 0xab, 0x83, 0xc8, 0x87, 0x0a, 0x2a, 0xd8, 0x8c, 0xbb, 0x54}}}, -{{{0xa9, 0x62, 0x93, 0x85, 0xbe, 0xe8, 0x73, 0x4a, 0x0e, 0xb0, 0xb5, 0x2d, 0x94, 0x50, 0xaa, 0xd3, 0xb2, 0xea, 0x9d, 0x62, 0x76, 0x3b, 0x07, 0x34, 0x4e, 0x2d, 0x70, 0xc8, 0x9a, 0x15, 0x66, 0x6b}} , - {{0xc5, 0x96, 0xca, 0xc8, 0x22, 0x1a, 0xee, 0x5f, 0xe7, 0x31, 0x60, 0x22, 0x83, 0x08, 0x63, 0xce, 0xb9, 0x32, 0x44, 0x58, 0x5d, 0x3a, 0x9b, 0xe4, 0x04, 0xd5, 0xef, 0x38, 0xef, 0x4b, 0xdd, 0x19}}}, -{{{0x4d, 0xc2, 0x17, 0x75, 0xa1, 0x68, 0xcd, 0xc3, 0xc6, 0x03, 0x44, 0xe3, 0x78, 0x09, 0x91, 0x47, 0x3f, 0x0f, 0xe4, 0x92, 0x58, 0xfa, 0x7d, 0x1f, 0x20, 0x94, 0x58, 0x5e, 0xbc, 0x19, 0x02, 0x6f}} , - {{0x20, 0xd6, 0xd8, 0x91, 0x54, 0xa7, 0xf3, 0x20, 0x4b, 0x34, 0x06, 0xfa, 0x30, 0xc8, 0x6f, 0x14, 0x10, 0x65, 0x74, 0x13, 0x4e, 0xf0, 0x69, 0x26, 0xce, 0xcf, 0x90, 0xf4, 0xd0, 0xc5, 0xc8, 0x64}}}, -{{{0x26, 0xa2, 0x50, 0x02, 0x24, 0x72, 0xf1, 0xf0, 0x4e, 0x2d, 0x93, 0xd5, 0x08, 0xe7, 0xae, 0x38, 0xf7, 0x18, 0xa5, 0x32, 0x34, 0xc2, 0xf0, 0xa6, 0xec, 0xb9, 0x61, 0x7b, 0x64, 0x99, 0xac, 0x71}} , - {{0x25, 0xcf, 0x74, 0x55, 0x1b, 0xaa, 0xa9, 0x38, 0x41, 0x40, 0xd5, 0x95, 0x95, 0xab, 0x1c, 0x5e, 0xbc, 0x41, 0x7e, 0x14, 0x30, 0xbe, 0x13, 0x89, 0xf4, 0xe5, 0xeb, 0x28, 0xc0, 0xc2, 0x96, 0x3a}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0x2b, 0x77, 0x45, 0xec, 0x67, 0x76, 0x32, 0x4c, 0xb9, 0xdf, 0x25, 0x32, 0x6b, 0xcb, 0xe7, 0x14, 0x61, 0x43, 0xee, 0xba, 0x9b, 0x71, 0xef, 0xd2, 0x48, 0x65, 0xbb, 0x1b, 0x8a, 0x13, 0x1b, 0x22}} , - {{0x84, 0xad, 0x0c, 0x18, 0x38, 0x5a, 0xba, 0xd0, 0x98, 0x59, 0xbf, 0x37, 0xb0, 0x4f, 0x97, 0x60, 0x20, 0xb3, 0x9b, 0x97, 0xf6, 0x08, 0x6c, 0xa4, 0xff, 0xfb, 0xb7, 0xfa, 0x95, 0xb2, 0x51, 0x79}}}, -{{{0x28, 0x5c, 0x3f, 0xdb, 0x6b, 0x18, 0x3b, 0x5c, 0xd1, 0x04, 0x28, 0xde, 0x85, 0x52, 0x31, 0xb5, 0xbb, 0xf6, 0xa9, 0xed, 0xbe, 0x28, 0x4f, 0xb3, 0x7e, 0x05, 0x6a, 0xdb, 0x95, 0x0d, 0x1b, 0x1c}} , - {{0xd5, 0xc5, 0xc3, 0x9a, 0x0a, 0xd0, 0x31, 0x3e, 0x07, 0x36, 0x8e, 0xc0, 0x8a, 0x62, 0xb1, 0xca, 0xd6, 0x0e, 0x1e, 0x9d, 0xef, 0xab, 0x98, 0x4d, 0xbb, 0x6c, 0x05, 0xe0, 0xe4, 0x5d, 0xbd, 0x57}}}, -{{{0xcc, 0x21, 0x27, 0xce, 0xfd, 0xa9, 0x94, 0x8e, 0xe1, 0xab, 0x49, 0xe0, 0x46, 0x26, 0xa1, 0xa8, 0x8c, 0xa1, 0x99, 0x1d, 0xb4, 0x27, 0x6d, 0x2d, 0xc8, 0x39, 0x30, 0x5e, 0x37, 0x52, 0xc4, 0x6e}} , - {{0xa9, 0x85, 0xf4, 0xe7, 0xb0, 0x15, 0x33, 0x84, 0x1b, 0x14, 0x1a, 0x02, 0xd9, 0x3b, 0xad, 0x0f, 0x43, 0x6c, 0xea, 0x3e, 0x0f, 0x7e, 0xda, 0xdd, 0x6b, 0x4c, 0x7f, 0x6e, 0xd4, 0x6b, 0xbf, 0x0f}}}, -{{{0x47, 0x9f, 0x7c, 0x56, 0x7c, 0x43, 0x91, 0x1c, 0xbb, 0x4e, 0x72, 0x3e, 0x64, 0xab, 0xa0, 0xa0, 0xdf, 0xb4, 0xd8, 0x87, 0x3a, 0xbd, 0xa8, 0x48, 0xc9, 0xb8, 0xef, 0x2e, 0xad, 0x6f, 0x84, 0x4f}} , - {{0x2d, 0x2d, 0xf0, 0x1b, 0x7e, 0x2a, 0x6c, 0xf8, 0xa9, 0x6a, 0xe1, 0xf0, 0x99, 0xa1, 0x67, 0x9a, 0xd4, 0x13, 0xca, 0xca, 0xba, 0x27, 0x92, 0xaa, 0xa1, 0x5d, 0x50, 0xde, 0xcc, 0x40, 0x26, 0x0a}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0x9f, 0x3e, 0xf2, 0xb2, 0x90, 0xce, 0xdb, 0x64, 0x3e, 0x03, 0xdd, 0x37, 0x36, 0x54, 0x70, 0x76, 0x24, 0xb5, 0x69, 0x03, 0xfc, 0xa0, 0x2b, 0x74, 0xb2, 0x05, 0x0e, 0xcc, 0xd8, 0x1f, 0x6a, 0x1f}} , - {{0x19, 0x5e, 0x60, 0x69, 0x58, 0x86, 0xa0, 0x31, 0xbd, 0x32, 0xe9, 0x2c, 0x5c, 0xd2, 0x85, 0xba, 0x40, 0x64, 0xa8, 0x74, 0xf8, 0x0e, 0x1c, 0xb3, 0xa9, 0x69, 0xe8, 0x1e, 0x40, 0x64, 0x99, 0x77}}}, -{{{0x6c, 0x32, 0x4f, 0xfd, 0xbb, 0x5c, 0xbb, 0x8d, 0x64, 0x66, 0x4a, 0x71, 0x1f, 0x79, 0xa3, 0xad, 0x8d, 0xf9, 0xd4, 0xec, 0xcf, 0x67, 0x70, 0xfa, 0x05, 0x4a, 0x0f, 0x6e, 0xaf, 0x87, 0x0a, 0x6f}} , - {{0xc6, 0x36, 0x6e, 0x6c, 0x8c, 0x24, 0x09, 0x60, 0xbe, 0x26, 0xd2, 0x4c, 0x5e, 0x17, 0xca, 0x5f, 0x1d, 0xcc, 0x87, 0xe8, 0x42, 0x6a, 0xcb, 0xcb, 0x7d, 0x92, 0x05, 0x35, 0x81, 0x13, 0x60, 0x6b}}}, -{{{0xf4, 0x15, 0xcd, 0x0f, 0x0a, 0xaf, 0x4e, 0x6b, 0x51, 0xfd, 0x14, 0xc4, 0x2e, 0x13, 0x86, 0x74, 0x44, 0xcb, 0x66, 0x6b, 0xb6, 0x9d, 0x74, 0x56, 0x32, 0xac, 0x8d, 0x8e, 0x8c, 0x8c, 0x8c, 0x39}} , - {{0xca, 0x59, 0x74, 0x1a, 0x11, 0xef, 0x6d, 0xf7, 0x39, 0x5c, 0x3b, 0x1f, 0xfa, 0xe3, 0x40, 0x41, 0x23, 0x9e, 0xf6, 0xd1, 0x21, 0xa2, 0xbf, 0xad, 0x65, 0x42, 0x6b, 0x59, 0x8a, 0xe8, 0xc5, 0x7f}}}, -{{{0x64, 0x05, 0x7a, 0x84, 0x4a, 0x13, 0xc3, 0xf6, 0xb0, 0x6e, 0x9a, 0x6b, 0x53, 0x6b, 0x32, 0xda, 0xd9, 0x74, 0x75, 0xc4, 0xba, 0x64, 0x3d, 0x3b, 0x08, 0xdd, 0x10, 0x46, 0xef, 0xc7, 0x90, 0x1f}} , - {{0x7b, 0x2f, 0x3a, 0xce, 0xc8, 0xa1, 0x79, 0x3c, 0x30, 0x12, 0x44, 0x28, 0xf6, 0xbc, 0xff, 0xfd, 0xf4, 0xc0, 0x97, 0xb0, 0xcc, 0xc3, 0x13, 0x7a, 0xb9, 0x9a, 0x16, 0xe4, 0xcb, 0x4c, 0x34, 0x63}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0x07, 0x4e, 0xd3, 0x2d, 0x09, 0x33, 0x0e, 0xd2, 0x0d, 0xbe, 0x3e, 0xe7, 0xe4, 0xaa, 0xb7, 0x00, 0x8b, 0xe8, 0xad, 0xaa, 0x7a, 0x8d, 0x34, 0x28, 0xa9, 0x81, 0x94, 0xc5, 0xe7, 0x42, 0xac, 0x47}} , - {{0x24, 0x89, 0x7a, 0x8f, 0xb5, 0x9b, 0xf0, 0xc2, 0x03, 0x64, 0xd0, 0x1e, 0xf5, 0xa4, 0xb2, 0xf3, 0x74, 0xe9, 0x1a, 0x16, 0xfd, 0xcb, 0x15, 0xea, 0xeb, 0x10, 0x6c, 0x35, 0xd1, 0xc1, 0xa6, 0x28}}}, -{{{0xcc, 0xd5, 0x39, 0xfc, 0xa5, 0xa4, 0xad, 0x32, 0x15, 0xce, 0x19, 0xe8, 0x34, 0x2b, 0x1c, 0x60, 0x91, 0xfc, 0x05, 0xa9, 0xb3, 0xdc, 0x80, 0x29, 0xc4, 0x20, 0x79, 0x06, 0x39, 0xc0, 0xe2, 0x22}} , - {{0xbb, 0xa8, 0xe1, 0x89, 0x70, 0x57, 0x18, 0x54, 0x3c, 0xf6, 0x0d, 0x82, 0x12, 0x05, 0x87, 0x96, 0x06, 0x39, 0xe3, 0xf8, 0xb3, 0x95, 0xe5, 0xd7, 0x26, 0xbf, 0x09, 0x5a, 0x94, 0xf9, 0x1c, 0x63}}}, -{{{0x2b, 0x8c, 0x2d, 0x9a, 0x8b, 0x84, 0xf2, 0x56, 0xfb, 0xad, 0x2e, 0x7f, 0xb7, 0xfc, 0x30, 0xe1, 0x35, 0x89, 0xba, 0x4d, 0xa8, 0x6d, 0xce, 0x8c, 0x8b, 0x30, 0xe0, 0xda, 0x29, 0x18, 0x11, 0x17}} , - {{0x19, 0xa6, 0x5a, 0x65, 0x93, 0xc3, 0xb5, 0x31, 0x22, 0x4f, 0xf3, 0xf6, 0x0f, 0xeb, 0x28, 0xc3, 0x7c, 0xeb, 0xce, 0x86, 0xec, 0x67, 0x76, 0x6e, 0x35, 0x45, 0x7b, 0xd8, 0x6b, 0x92, 0x01, 0x65}}}, -{{{0x3d, 0xd5, 0x9a, 0x64, 0x73, 0x36, 0xb1, 0xd6, 0x86, 0x98, 0x42, 0x3f, 0x8a, 0xf1, 0xc7, 0xf5, 0x42, 0xa8, 0x9c, 0x52, 0xa8, 0xdc, 0xf9, 0x24, 0x3f, 0x4a, 0xa1, 0xa4, 0x5b, 0xe8, 0x62, 0x1a}} , - {{0xc5, 0xbd, 0xc8, 0x14, 0xd5, 0x0d, 0xeb, 0xe1, 0xa5, 0xe6, 0x83, 0x11, 0x09, 0x00, 0x1d, 0x55, 0x83, 0x51, 0x7e, 0x75, 0x00, 0x81, 0xb9, 0xcb, 0xd8, 0xc5, 0xe5, 0xa1, 0xd9, 0x17, 0x6d, 0x1f}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0xea, 0xf9, 0xe4, 0xe9, 0xe1, 0x52, 0x3f, 0x51, 0x19, 0x0d, 0xdd, 0xd9, 0x9d, 0x93, 0x31, 0x87, 0x23, 0x09, 0xd5, 0x83, 0xeb, 0x92, 0x09, 0x76, 0x6e, 0xe3, 0xf8, 0xc0, 0xa2, 0x66, 0xb5, 0x36}} , - {{0x3a, 0xbb, 0x39, 0xed, 0x32, 0x02, 0xe7, 0x43, 0x7a, 0x38, 0x14, 0x84, 0xe3, 0x44, 0xd2, 0x5e, 0x94, 0xdd, 0x78, 0x89, 0x55, 0x4c, 0x73, 0x9e, 0xe1, 0xe4, 0x3e, 0x43, 0xd0, 0x4a, 0xde, 0x1b}}}, -{{{0xb2, 0xe7, 0x8f, 0xe3, 0xa3, 0xc5, 0xcb, 0x72, 0xee, 0x79, 0x41, 0xf8, 0xdf, 0xee, 0x65, 0xc5, 0x45, 0x77, 0x27, 0x3c, 0xbd, 0x58, 0xd3, 0x75, 0xe2, 0x04, 0x4b, 0xbb, 0x65, 0xf3, 0xc8, 0x0f}} , - {{0x24, 0x7b, 0x93, 0x34, 0xb5, 0xe2, 0x74, 0x48, 0xcd, 0xa0, 0x0b, 0x92, 0x97, 0x66, 0x39, 0xf4, 0xb0, 0xe2, 0x5d, 0x39, 0x6a, 0x5b, 0x45, 0x17, 0x78, 0x1e, 0xdb, 0x91, 0x81, 0x1c, 0xf9, 0x16}}}, -{{{0x16, 0xdf, 0xd1, 0x5a, 0xd5, 0xe9, 0x4e, 0x58, 0x95, 0x93, 0x5f, 0x51, 0x09, 0xc3, 0x2a, 0xc9, 0xd4, 0x55, 0x48, 0x79, 0xa4, 0xa3, 0xb2, 0xc3, 0x62, 0xaa, 0x8c, 0xe8, 0xad, 0x47, 0x39, 0x1b}} , - {{0x46, 0xda, 0x9e, 0x51, 0x3a, 0xe6, 0xd1, 0xa6, 0xbb, 0x4d, 0x7b, 0x08, 0xbe, 0x8c, 0xd5, 0xf3, 0x3f, 0xfd, 0xf7, 0x44, 0x80, 0x2d, 0x53, 0x4b, 0xd0, 0x87, 0x68, 0xc1, 0xb5, 0xd8, 0xf7, 0x07}}}, -{{{0xf4, 0x10, 0x46, 0xbe, 0xb7, 0xd2, 0xd1, 0xce, 0x5e, 0x76, 0xa2, 0xd7, 0x03, 0xdc, 0xe4, 0x81, 0x5a, 0xf6, 0x3c, 0xde, 0xae, 0x7a, 0x9d, 0x21, 0x34, 0xa5, 0xf6, 0xa9, 0x73, 0xe2, 0x8d, 0x60}} , - {{0xfa, 0x44, 0x71, 0xf6, 0x41, 0xd8, 0xc6, 0x58, 0x13, 0x37, 0xeb, 0x84, 0x0f, 0x96, 0xc7, 0xdc, 0xc8, 0xa9, 0x7a, 0x83, 0xb2, 0x2f, 0x31, 0xb1, 0x1a, 0xd8, 0x98, 0x3f, 0x11, 0xd0, 0x31, 0x3b}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0x81, 0xd5, 0x34, 0x16, 0x01, 0xa3, 0x93, 0xea, 0x52, 0x94, 0xec, 0x93, 0xb7, 0x81, 0x11, 0x2d, 0x58, 0xf9, 0xb5, 0x0a, 0xaa, 0x4f, 0xf6, 0x2e, 0x3f, 0x36, 0xbf, 0x33, 0x5a, 0xe7, 0xd1, 0x08}} , - {{0x1a, 0xcf, 0x42, 0xae, 0xcc, 0xb5, 0x77, 0x39, 0xc4, 0x5b, 0x5b, 0xd0, 0x26, 0x59, 0x27, 0xd0, 0x55, 0x71, 0x12, 0x9d, 0x88, 0x3d, 0x9c, 0xea, 0x41, 0x6a, 0xf0, 0x50, 0x93, 0x93, 0xdd, 0x47}}}, -{{{0x6f, 0xc9, 0x51, 0x6d, 0x1c, 0xaa, 0xf5, 0xa5, 0x90, 0x3f, 0x14, 0xe2, 0x6e, 0x8e, 0x64, 0xfd, 0xac, 0xe0, 0x4e, 0x22, 0xe5, 0xc1, 0xbc, 0x29, 0x0a, 0x6a, 0x9e, 0xa1, 0x60, 0xcb, 0x2f, 0x0b}} , - {{0xdc, 0x39, 0x32, 0xf3, 0xa1, 0x44, 0xe9, 0xc5, 0xc3, 0x78, 0xfb, 0x95, 0x47, 0x34, 0x35, 0x34, 0xe8, 0x25, 0xde, 0x93, 0xc6, 0xb4, 0x76, 0x6d, 0x86, 0x13, 0xc6, 0xe9, 0x68, 0xb5, 0x01, 0x63}}}, -{{{0x1f, 0x9a, 0x52, 0x64, 0x97, 0xd9, 0x1c, 0x08, 0x51, 0x6f, 0x26, 0x9d, 0xaa, 0x93, 0x33, 0x43, 0xfa, 0x77, 0xe9, 0x62, 0x9b, 0x5d, 0x18, 0x75, 0xeb, 0x78, 0xf7, 0x87, 0x8f, 0x41, 0xb4, 0x4d}} , - {{0x13, 0xa8, 0x82, 0x3e, 0xe9, 0x13, 0xad, 0xeb, 0x01, 0xca, 0xcf, 0xda, 0xcd, 0xf7, 0x6c, 0xc7, 0x7a, 0xdc, 0x1e, 0x6e, 0xc8, 0x4e, 0x55, 0x62, 0x80, 0xea, 0x78, 0x0c, 0x86, 0xb9, 0x40, 0x51}}}, -{{{0x27, 0xae, 0xd3, 0x0d, 0x4c, 0x8f, 0x34, 0xea, 0x7d, 0x3c, 0xe5, 0x8a, 0xcf, 0x5b, 0x92, 0xd8, 0x30, 0x16, 0xb4, 0xa3, 0x75, 0xff, 0xeb, 0x27, 0xc8, 0x5c, 0x6c, 0xc2, 0xee, 0x6c, 0x21, 0x0b}} , - {{0xc3, 0xba, 0x12, 0x53, 0x2a, 0xaa, 0x77, 0xad, 0x19, 0x78, 0x55, 0x8a, 0x2e, 0x60, 0x87, 0xc2, 0x6e, 0x91, 0x38, 0x91, 0x3f, 0x7a, 0xc5, 0x24, 0x8f, 0x51, 0xc5, 0xde, 0xb0, 0x53, 0x30, 0x56}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0x02, 0xfe, 0x54, 0x12, 0x18, 0xca, 0x7d, 0xa5, 0x68, 0x43, 0xa3, 0x6d, 0x14, 0x2a, 0x6a, 0xa5, 0x8e, 0x32, 0xe7, 0x63, 0x4f, 0xe3, 0xc6, 0x44, 0x3e, 0xab, 0x63, 0xca, 0x17, 0x86, 0x74, 0x3f}} , - {{0x1e, 0x64, 0xc1, 0x7d, 0x52, 0xdc, 0x13, 0x5a, 0xa1, 0x9c, 0x4e, 0xee, 0x99, 0x28, 0xbb, 0x4c, 0xee, 0xac, 0xa9, 0x1b, 0x89, 0xa2, 0x38, 0x39, 0x7b, 0xc4, 0x0f, 0x42, 0xe6, 0x89, 0xed, 0x0f}}}, -{{{0xf3, 0x3c, 0x8c, 0x80, 0x83, 0x10, 0x8a, 0x37, 0x50, 0x9c, 0xb4, 0xdf, 0x3f, 0x8c, 0xf7, 0x23, 0x07, 0xd6, 0xff, 0xa0, 0x82, 0x6c, 0x75, 0x3b, 0xe4, 0xb5, 0xbb, 0xe4, 0xe6, 0x50, 0xf0, 0x08}} , - {{0x62, 0xee, 0x75, 0x48, 0x92, 0x33, 0xf2, 0xf4, 0xad, 0x15, 0x7a, 0xa1, 0x01, 0x46, 0xa9, 0x32, 0x06, 0x88, 0xb6, 0x36, 0x47, 0x35, 0xb9, 0xb4, 0x42, 0x85, 0x76, 0xf0, 0x48, 0x00, 0x90, 0x38}}}, -{{{0x51, 0x15, 0x9d, 0xc3, 0x95, 0xd1, 0x39, 0xbb, 0x64, 0x9d, 0x15, 0x81, 0xc1, 0x68, 0xd0, 0xb6, 0xa4, 0x2c, 0x7d, 0x5e, 0x02, 0x39, 0x00, 0xe0, 0x3b, 0xa4, 0xcc, 0xca, 0x1d, 0x81, 0x24, 0x10}} , - {{0xe7, 0x29, 0xf9, 0x37, 0xd9, 0x46, 0x5a, 0xcd, 0x70, 0xfe, 0x4d, 0x5b, 0xbf, 0xa5, 0xcf, 0x91, 0xf4, 0xef, 0xee, 0x8a, 0x29, 0xd0, 0xe7, 0xc4, 0x25, 0x92, 0x8a, 0xff, 0x36, 0xfc, 0xe4, 0x49}}}, -{{{0xbd, 0x00, 0xb9, 0x04, 0x7d, 0x35, 0xfc, 0xeb, 0xd0, 0x0b, 0x05, 0x32, 0x52, 0x7a, 0x89, 0x24, 0x75, 0x50, 0xe1, 0x63, 0x02, 0x82, 0x8e, 0xe7, 0x85, 0x0c, 0xf2, 0x56, 0x44, 0x37, 0x83, 0x25}} , - {{0x8f, 0xa1, 0xce, 0xcb, 0x60, 0xda, 0x12, 0x02, 0x1e, 0x29, 0x39, 0x2a, 0x03, 0xb7, 0xeb, 0x77, 0x40, 0xea, 0xc9, 0x2b, 0x2c, 0xd5, 0x7d, 0x7e, 0x2c, 0xc7, 0x5a, 0xfd, 0xff, 0xc4, 0xd1, 0x62}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0x1d, 0x88, 0x98, 0x5b, 0x4e, 0xfc, 0x41, 0x24, 0x05, 0xe6, 0x50, 0x2b, 0xae, 0x96, 0x51, 0xd9, 0x6b, 0x72, 0xb2, 0x33, 0x42, 0x98, 0x68, 0xbb, 0x10, 0x5a, 0x7a, 0x8c, 0x9d, 0x07, 0xb4, 0x05}} , - {{0x2f, 0x61, 0x9f, 0xd7, 0xa8, 0x3f, 0x83, 0x8c, 0x10, 0x69, 0x90, 0xe6, 0xcf, 0xd2, 0x63, 0xa3, 0xe4, 0x54, 0x7e, 0xe5, 0x69, 0x13, 0x1c, 0x90, 0x57, 0xaa, 0xe9, 0x53, 0x22, 0x43, 0x29, 0x23}}}, -{{{0xe5, 0x1c, 0xf8, 0x0a, 0xfd, 0x2d, 0x7e, 0xf5, 0xf5, 0x70, 0x7d, 0x41, 0x6b, 0x11, 0xfe, 0xbe, 0x99, 0xd1, 0x55, 0x29, 0x31, 0xbf, 0xc0, 0x97, 0x6c, 0xd5, 0x35, 0xcc, 0x5e, 0x8b, 0xd9, 0x69}} , - {{0x8e, 0x4e, 0x9f, 0x25, 0xf8, 0x81, 0x54, 0x2d, 0x0e, 0xd5, 0x54, 0x81, 0x9b, 0xa6, 0x92, 0xce, 0x4b, 0xe9, 0x8f, 0x24, 0x3b, 0xca, 0xe0, 0x44, 0xab, 0x36, 0xfe, 0xfb, 0x87, 0xd4, 0x26, 0x3e}}}, -{{{0x0f, 0x93, 0x9c, 0x11, 0xe7, 0xdb, 0xf1, 0xf0, 0x85, 0x43, 0x28, 0x15, 0x37, 0xdd, 0xde, 0x27, 0xdf, 0xad, 0x3e, 0x49, 0x4f, 0xe0, 0x5b, 0xf6, 0x80, 0x59, 0x15, 0x3c, 0x85, 0xb7, 0x3e, 0x12}} , - {{0xf5, 0xff, 0xcc, 0xf0, 0xb4, 0x12, 0x03, 0x5f, 0xc9, 0x84, 0xcb, 0x1d, 0x17, 0xe0, 0xbc, 0xcc, 0x03, 0x62, 0xa9, 0x8b, 0x94, 0xa6, 0xaa, 0x18, 0xcb, 0x27, 0x8d, 0x49, 0xa6, 0x17, 0x15, 0x07}}}, -{{{0xd9, 0xb6, 0xd4, 0x9d, 0xd4, 0x6a, 0xaf, 0x70, 0x07, 0x2c, 0x10, 0x9e, 0xbd, 0x11, 0xad, 0xe4, 0x26, 0x33, 0x70, 0x92, 0x78, 0x1c, 0x74, 0x9f, 0x75, 0x60, 0x56, 0xf4, 0x39, 0xa8, 0xa8, 0x62}} , - {{0x3b, 0xbf, 0x55, 0x35, 0x61, 0x8b, 0x44, 0x97, 0xe8, 0x3a, 0x55, 0xc1, 0xc8, 0x3b, 0xfd, 0x95, 0x29, 0x11, 0x60, 0x96, 0x1e, 0xcb, 0x11, 0x9d, 0xc2, 0x03, 0x8a, 0x1b, 0xc6, 0xd6, 0x45, 0x3d}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0x7e, 0x0e, 0x50, 0xb2, 0xcc, 0x0d, 0x6b, 0xa6, 0x71, 0x5b, 0x42, 0xed, 0xbd, 0xaf, 0xac, 0xf0, 0xfc, 0x12, 0xa2, 0x3f, 0x4e, 0xda, 0xe8, 0x11, 0xf3, 0x23, 0xe1, 0x04, 0x62, 0x03, 0x1c, 0x4e}} , - {{0xc8, 0xb1, 0x1b, 0x6f, 0x73, 0x61, 0x3d, 0x27, 0x0d, 0x7d, 0x7a, 0x25, 0x5f, 0x73, 0x0e, 0x2f, 0x93, 0xf6, 0x24, 0xd8, 0x4f, 0x90, 0xac, 0xa2, 0x62, 0x0a, 0xf0, 0x61, 0xd9, 0x08, 0x59, 0x6a}}}, -{{{0x6f, 0x2d, 0x55, 0xf8, 0x2f, 0x8e, 0xf0, 0x18, 0x3b, 0xea, 0xdd, 0x26, 0x72, 0xd1, 0xf5, 0xfe, 0xe5, 0xb8, 0xe6, 0xd3, 0x10, 0x48, 0x46, 0x49, 0x3a, 0x9f, 0x5e, 0x45, 0x6b, 0x90, 0xe8, 0x7f}} , - {{0xd3, 0x76, 0x69, 0x33, 0x7b, 0xb9, 0x40, 0x70, 0xee, 0xa6, 0x29, 0x6b, 0xdd, 0xd0, 0x5d, 0x8d, 0xc1, 0x3e, 0x4a, 0xea, 0x37, 0xb1, 0x03, 0x02, 0x03, 0x35, 0xf1, 0x28, 0x9d, 0xff, 0x00, 0x13}}}, -{{{0x7a, 0xdb, 0x12, 0xd2, 0x8a, 0x82, 0x03, 0x1b, 0x1e, 0xaf, 0xf9, 0x4b, 0x9c, 0xbe, 0xae, 0x7c, 0xe4, 0x94, 0x2a, 0x23, 0xb3, 0x62, 0x86, 0xe7, 0xfd, 0x23, 0xaa, 0x99, 0xbd, 0x2b, 0x11, 0x6c}} , - {{0x8d, 0xa6, 0xd5, 0xac, 0x9d, 0xcc, 0x68, 0x75, 0x7f, 0xc3, 0x4d, 0x4b, 0xdd, 0x6c, 0xbb, 0x11, 0x5a, 0x60, 0xe5, 0xbd, 0x7d, 0x27, 0x8b, 0xda, 0xb4, 0x95, 0xf6, 0x03, 0x27, 0xa4, 0x92, 0x3f}}}, -{{{0x22, 0xd6, 0xb5, 0x17, 0x84, 0xbf, 0x12, 0xcc, 0x23, 0x14, 0x4a, 0xdf, 0x14, 0x31, 0xbc, 0xa1, 0xac, 0x6e, 0xab, 0xfa, 0x57, 0x11, 0x53, 0xb3, 0x27, 0xe6, 0xf9, 0x47, 0x33, 0x44, 0x34, 0x1e}} , - {{0x79, 0xfc, 0xa6, 0xb4, 0x0b, 0x35, 0x20, 0xc9, 0x4d, 0x22, 0x84, 0xc4, 0xa9, 0x20, 0xec, 0x89, 0x94, 0xba, 0x66, 0x56, 0x48, 0xb9, 0x87, 0x7f, 0xca, 0x1e, 0x06, 0xed, 0xa5, 0x55, 0x59, 0x29}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0x56, 0xe1, 0xf5, 0xf1, 0xd5, 0xab, 0xa8, 0x2b, 0xae, 0x89, 0xf3, 0xcf, 0x56, 0x9f, 0xf2, 0x4b, 0x31, 0xbc, 0x18, 0xa9, 0x06, 0x5b, 0xbe, 0xb4, 0x61, 0xf8, 0xb2, 0x06, 0x9c, 0x81, 0xab, 0x4c}} , - {{0x1f, 0x68, 0x76, 0x01, 0x16, 0x38, 0x2b, 0x0f, 0x77, 0x97, 0x92, 0x67, 0x4e, 0x86, 0x6a, 0x8b, 0xe5, 0xe8, 0x0c, 0xf7, 0x36, 0x39, 0xb5, 0x33, 0xe6, 0xcf, 0x5e, 0xbd, 0x18, 0xfb, 0x10, 0x1f}}}, -{{{0x83, 0xf0, 0x0d, 0x63, 0xef, 0x53, 0x6b, 0xb5, 0x6b, 0xf9, 0x83, 0xcf, 0xde, 0x04, 0x22, 0x9b, 0x2c, 0x0a, 0xe0, 0xa5, 0xd8, 0xc7, 0x9c, 0xa5, 0xa3, 0xf6, 0x6f, 0xcf, 0x90, 0x6b, 0x68, 0x7c}} , - {{0x33, 0x15, 0xd7, 0x7f, 0x1a, 0xd5, 0x21, 0x58, 0xc4, 0x18, 0xa5, 0xf0, 0xcc, 0x73, 0xa8, 0xfd, 0xfa, 0x18, 0xd1, 0x03, 0x91, 0x8d, 0x52, 0xd2, 0xa3, 0xa4, 0xd3, 0xb1, 0xea, 0x1d, 0x0f, 0x00}}}, -{{{0xcc, 0x48, 0x83, 0x90, 0xe5, 0xfd, 0x3f, 0x84, 0xaa, 0xf9, 0x8b, 0x82, 0x59, 0x24, 0x34, 0x68, 0x4f, 0x1c, 0x23, 0xd9, 0xcc, 0x71, 0xe1, 0x7f, 0x8c, 0xaf, 0xf1, 0xee, 0x00, 0xb6, 0xa0, 0x77}} , - {{0xf5, 0x1a, 0x61, 0xf7, 0x37, 0x9d, 0x00, 0xf4, 0xf2, 0x69, 0x6f, 0x4b, 0x01, 0x85, 0x19, 0x45, 0x4d, 0x7f, 0x02, 0x7c, 0x6a, 0x05, 0x47, 0x6c, 0x1f, 0x81, 0x20, 0xd4, 0xe8, 0x50, 0x27, 0x72}}}, -{{{0x2c, 0x3a, 0xe5, 0xad, 0xf4, 0xdd, 0x2d, 0xf7, 0x5c, 0x44, 0xb5, 0x5b, 0x21, 0xa3, 0x89, 0x5f, 0x96, 0x45, 0xca, 0x4d, 0xa4, 0x21, 0x99, 0x70, 0xda, 0xc4, 0xc4, 0xa0, 0xe5, 0xf4, 0xec, 0x0a}} , - {{0x07, 0x68, 0x21, 0x65, 0xe9, 0x08, 0xa0, 0x0b, 0x6a, 0x4a, 0xba, 0xb5, 0x80, 0xaf, 0xd0, 0x1b, 0xc5, 0xf5, 0x4b, 0x73, 0x50, 0x60, 0x2d, 0x71, 0x69, 0x61, 0x0e, 0xc0, 0x20, 0x40, 0x30, 0x19}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0xd0, 0x75, 0x57, 0x3b, 0xeb, 0x5c, 0x14, 0x56, 0x50, 0xc9, 0x4f, 0xb8, 0xb8, 0x1e, 0xa3, 0xf4, 0xab, 0xf5, 0xa9, 0x20, 0x15, 0x94, 0x82, 0xda, 0x96, 0x1c, 0x9b, 0x59, 0x8c, 0xff, 0xf4, 0x51}} , - {{0xc1, 0x3a, 0x86, 0xd7, 0xb0, 0x06, 0x84, 0x7f, 0x1b, 0xbd, 0xd4, 0x07, 0x78, 0x80, 0x2e, 0xb1, 0xb4, 0xee, 0x52, 0x38, 0xee, 0x9a, 0xf9, 0xf6, 0xf3, 0x41, 0x6e, 0xd4, 0x88, 0x95, 0xac, 0x35}}}, -{{{0x41, 0x97, 0xbf, 0x71, 0x6a, 0x9b, 0x72, 0xec, 0xf3, 0xf8, 0x6b, 0xe6, 0x0e, 0x6c, 0x69, 0xa5, 0x2f, 0x68, 0x52, 0xd8, 0x61, 0x81, 0xc0, 0x63, 0x3f, 0xa6, 0x3c, 0x13, 0x90, 0xe6, 0x8d, 0x56}} , - {{0xe8, 0x39, 0x30, 0x77, 0x23, 0xb1, 0xfd, 0x1b, 0x3d, 0x3e, 0x74, 0x4d, 0x7f, 0xae, 0x5b, 0x3a, 0xb4, 0x65, 0x0e, 0x3a, 0x43, 0xdc, 0xdc, 0x41, 0x47, 0xe6, 0xe8, 0x92, 0x09, 0x22, 0x48, 0x4c}}}, -{{{0x85, 0x57, 0x9f, 0xb5, 0xc8, 0x06, 0xb2, 0x9f, 0x47, 0x3f, 0xf0, 0xfa, 0xe6, 0xa9, 0xb1, 0x9b, 0x6f, 0x96, 0x7d, 0xf9, 0xa4, 0x65, 0x09, 0x75, 0x32, 0xa6, 0x6c, 0x7f, 0x47, 0x4b, 0x2f, 0x4f}} , - {{0x34, 0xe9, 0x59, 0x93, 0x9d, 0x26, 0x80, 0x54, 0xf2, 0xcc, 0x3c, 0xc2, 0x25, 0x85, 0xe3, 0x6a, 0xc1, 0x62, 0x04, 0xa7, 0x08, 0x32, 0x6d, 0xa1, 0x39, 0x84, 0x8a, 0x3b, 0x87, 0x5f, 0x11, 0x13}}}, -{{{0xda, 0x03, 0x34, 0x66, 0xc4, 0x0c, 0x73, 0x6e, 0xbc, 0x24, 0xb5, 0xf9, 0x70, 0x81, 0x52, 0xe9, 0xf4, 0x7c, 0x23, 0xdd, 0x9f, 0xb8, 0x46, 0xef, 0x1d, 0x22, 0x55, 0x7d, 0x71, 0xc4, 0x42, 0x33}} , - {{0xc5, 0x37, 0x69, 0x5b, 0xa8, 0xc6, 0x9d, 0xa4, 0xfc, 0x61, 0x6e, 0x68, 0x46, 0xea, 0xd7, 0x1c, 0x67, 0xd2, 0x7d, 0xfa, 0xf1, 0xcc, 0x54, 0x8d, 0x36, 0x35, 0xc9, 0x00, 0xdf, 0x6c, 0x67, 0x50}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0x9a, 0x4d, 0x42, 0x29, 0x5d, 0xa4, 0x6b, 0x6f, 0xa8, 0x8a, 0x4d, 0x91, 0x7b, 0xd2, 0xdf, 0x36, 0xef, 0x01, 0x22, 0xc5, 0xcc, 0x8d, 0xeb, 0x58, 0x3d, 0xb3, 0x50, 0xfc, 0x8b, 0x97, 0x96, 0x33}} , - {{0x93, 0x33, 0x07, 0xc8, 0x4a, 0xca, 0xd0, 0xb1, 0xab, 0xbd, 0xdd, 0xa7, 0x7c, 0xac, 0x3e, 0x45, 0xcb, 0xcc, 0x07, 0x91, 0xbf, 0x35, 0x9d, 0xcb, 0x7d, 0x12, 0x3c, 0x11, 0x59, 0x13, 0xcf, 0x5c}}}, -{{{0x45, 0xb8, 0x41, 0xd7, 0xab, 0x07, 0x15, 0x00, 0x8e, 0xce, 0xdf, 0xb2, 0x43, 0x5c, 0x01, 0xdc, 0xf4, 0x01, 0x51, 0x95, 0x10, 0x5a, 0xf6, 0x24, 0x24, 0xa0, 0x19, 0x3a, 0x09, 0x2a, 0xaa, 0x3f}} , - {{0xdc, 0x8e, 0xeb, 0xc6, 0xbf, 0xdd, 0x11, 0x7b, 0xe7, 0x47, 0xe6, 0xce, 0xe7, 0xb6, 0xc5, 0xe8, 0x8a, 0xdc, 0x4b, 0x57, 0x15, 0x3b, 0x66, 0xca, 0x89, 0xa3, 0xfd, 0xac, 0x0d, 0xe1, 0x1d, 0x7a}}}, -{{{0x89, 0xef, 0xbf, 0x03, 0x75, 0xd0, 0x29, 0x50, 0xcb, 0x7d, 0xd6, 0xbe, 0xad, 0x5f, 0x7b, 0x00, 0x32, 0xaa, 0x98, 0xed, 0x3f, 0x8f, 0x92, 0xcb, 0x81, 0x56, 0x01, 0x63, 0x64, 0xa3, 0x38, 0x39}} , - {{0x8b, 0xa4, 0xd6, 0x50, 0xb4, 0xaa, 0x5d, 0x64, 0x64, 0x76, 0x2e, 0xa1, 0xa6, 0xb3, 0xb8, 0x7c, 0x7a, 0x56, 0xf5, 0x5c, 0x4e, 0x84, 0x5c, 0xfb, 0xdd, 0xca, 0x48, 0x8b, 0x48, 0xb9, 0xba, 0x34}}}, -{{{0xc5, 0xe3, 0xe8, 0xae, 0x17, 0x27, 0xe3, 0x64, 0x60, 0x71, 0x47, 0x29, 0x02, 0x0f, 0x92, 0x5d, 0x10, 0x93, 0xc8, 0x0e, 0xa1, 0xed, 0xba, 0xa9, 0x96, 0x1c, 0xc5, 0x76, 0x30, 0xcd, 0xf9, 0x30}} , - {{0x95, 0xb0, 0xbd, 0x8c, 0xbc, 0xa7, 0x4f, 0x7e, 0xfd, 0x4e, 0x3a, 0xbf, 0x5f, 0x04, 0x79, 0x80, 0x2b, 0x5a, 0x9f, 0x4f, 0x68, 0x21, 0x19, 0x71, 0xc6, 0x20, 0x01, 0x42, 0xaa, 0xdf, 0xae, 0x2c}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0x90, 0x6e, 0x7e, 0x4b, 0x71, 0x93, 0xc0, 0x72, 0xed, 0xeb, 0x71, 0x24, 0x97, 0x26, 0x9c, 0xfe, 0xcb, 0x3e, 0x59, 0x19, 0xa8, 0x0f, 0x75, 0x7d, 0xbe, 0x18, 0xe6, 0x96, 0x1e, 0x95, 0x70, 0x60}} , - {{0x89, 0x66, 0x3e, 0x1d, 0x4c, 0x5f, 0xfe, 0xc0, 0x04, 0x43, 0xd6, 0x44, 0x19, 0xb5, 0xad, 0xc7, 0x22, 0xdc, 0x71, 0x28, 0x64, 0xde, 0x41, 0x38, 0x27, 0x8f, 0x2c, 0x6b, 0x08, 0xb8, 0xb8, 0x7b}}}, -{{{0x3d, 0x70, 0x27, 0x9d, 0xd9, 0xaf, 0xb1, 0x27, 0xaf, 0xe3, 0x5d, 0x1e, 0x3a, 0x30, 0x54, 0x61, 0x60, 0xe8, 0xc3, 0x26, 0x3a, 0xbc, 0x7e, 0xf5, 0x81, 0xdd, 0x64, 0x01, 0x04, 0xeb, 0xc0, 0x1e}} , - {{0xda, 0x2c, 0xa4, 0xd1, 0xa1, 0xc3, 0x5c, 0x6e, 0x32, 0x07, 0x1f, 0xb8, 0x0e, 0x19, 0x9e, 0x99, 0x29, 0x33, 0x9a, 0xae, 0x7a, 0xed, 0x68, 0x42, 0x69, 0x7c, 0x07, 0xb3, 0x38, 0x2c, 0xf6, 0x3d}}}, -{{{0x64, 0xaa, 0xb5, 0x88, 0x79, 0x65, 0x38, 0x8c, 0x94, 0xd6, 0x62, 0x37, 0x7d, 0x64, 0xcd, 0x3a, 0xeb, 0xff, 0xe8, 0x81, 0x09, 0xc7, 0x6a, 0x50, 0x09, 0x0d, 0x28, 0x03, 0x0d, 0x9a, 0x93, 0x0a}} , - {{0x42, 0xa3, 0xf1, 0xc5, 0xb4, 0x0f, 0xd8, 0xc8, 0x8d, 0x15, 0x31, 0xbd, 0xf8, 0x07, 0x8b, 0xcd, 0x08, 0x8a, 0xfb, 0x18, 0x07, 0xfe, 0x8e, 0x52, 0x86, 0xef, 0xbe, 0xec, 0x49, 0x52, 0x99, 0x08}}}, -{{{0x0f, 0xa9, 0xd5, 0x01, 0xaa, 0x48, 0x4f, 0x28, 0x66, 0x32, 0x1a, 0xba, 0x7c, 0xea, 0x11, 0x80, 0x17, 0x18, 0x9b, 0x56, 0x88, 0x25, 0x06, 0x69, 0x12, 0x2c, 0xea, 0x56, 0x69, 0x41, 0x24, 0x19}} , - {{0xde, 0x21, 0xf0, 0xda, 0x8a, 0xfb, 0xb1, 0xb8, 0xcd, 0xc8, 0x6a, 0x82, 0x19, 0x73, 0xdb, 0xc7, 0xcf, 0x88, 0xeb, 0x96, 0xee, 0x6f, 0xfb, 0x06, 0xd2, 0xcd, 0x7d, 0x7b, 0x12, 0x28, 0x8e, 0x0c}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0x93, 0x44, 0x97, 0xce, 0x28, 0xff, 0x3a, 0x40, 0xc4, 0xf5, 0xf6, 0x9b, 0xf4, 0x6b, 0x07, 0x84, 0xfb, 0x98, 0xd8, 0xec, 0x8c, 0x03, 0x57, 0xec, 0x49, 0xed, 0x63, 0xb6, 0xaa, 0xff, 0x98, 0x28}} , - {{0x3d, 0x16, 0x35, 0xf3, 0x46, 0xbc, 0xb3, 0xf4, 0xc6, 0xb6, 0x4f, 0xfa, 0xf4, 0xa0, 0x13, 0xe6, 0x57, 0x45, 0x93, 0xb9, 0xbc, 0xd6, 0x59, 0xe7, 0x77, 0x94, 0x6c, 0xab, 0x96, 0x3b, 0x4f, 0x09}}}, -{{{0x5a, 0xf7, 0x6b, 0x01, 0x12, 0x4f, 0x51, 0xc1, 0x70, 0x84, 0x94, 0x47, 0xb2, 0x01, 0x6c, 0x71, 0xd7, 0xcc, 0x17, 0x66, 0x0f, 0x59, 0x5d, 0x5d, 0x10, 0x01, 0x57, 0x11, 0xf5, 0xdd, 0xe2, 0x34}} , - {{0x26, 0xd9, 0x1f, 0x5c, 0x58, 0xac, 0x8b, 0x03, 0xd2, 0xc3, 0x85, 0x0f, 0x3a, 0xc3, 0x7f, 0x6d, 0x8e, 0x86, 0xcd, 0x52, 0x74, 0x8f, 0x55, 0x77, 0x17, 0xb7, 0x8e, 0xb7, 0x88, 0xea, 0xda, 0x1b}}}, -{{{0xb6, 0xea, 0x0e, 0x40, 0x93, 0x20, 0x79, 0x35, 0x6a, 0x61, 0x84, 0x5a, 0x07, 0x6d, 0xf9, 0x77, 0x6f, 0xed, 0x69, 0x1c, 0x0d, 0x25, 0x76, 0xcc, 0xf0, 0xdb, 0xbb, 0xc5, 0xad, 0xe2, 0x26, 0x57}} , - {{0xcf, 0xe8, 0x0e, 0x6b, 0x96, 0x7d, 0xed, 0x27, 0xd1, 0x3c, 0xa9, 0xd9, 0x50, 0xa9, 0x98, 0x84, 0x5e, 0x86, 0xef, 0xd6, 0xf0, 0xf8, 0x0e, 0x89, 0x05, 0x2f, 0xd9, 0x5f, 0x15, 0x5f, 0x73, 0x79}}}, -{{{0xc8, 0x5c, 0x16, 0xfe, 0xed, 0x9f, 0x26, 0x56, 0xf6, 0x4b, 0x9f, 0xa7, 0x0a, 0x85, 0xfe, 0xa5, 0x8c, 0x87, 0xdd, 0x98, 0xce, 0x4e, 0xc3, 0x58, 0x55, 0xb2, 0x7b, 0x3d, 0xd8, 0x6b, 0xb5, 0x4c}} , - {{0x65, 0x38, 0xa0, 0x15, 0xfa, 0xa7, 0xb4, 0x8f, 0xeb, 0xc4, 0x86, 0x9b, 0x30, 0xa5, 0x5e, 0x4d, 0xea, 0x8a, 0x9a, 0x9f, 0x1a, 0xd8, 0x5b, 0x53, 0x14, 0x19, 0x25, 0x63, 0xb4, 0x6f, 0x1f, 0x5d}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0xac, 0x8f, 0xbc, 0x1e, 0x7d, 0x8b, 0x5a, 0x0b, 0x8d, 0xaf, 0x76, 0x2e, 0x71, 0xe3, 0x3b, 0x6f, 0x53, 0x2f, 0x3e, 0x90, 0x95, 0xd4, 0x35, 0x14, 0x4f, 0x8c, 0x3c, 0xce, 0x57, 0x1c, 0x76, 0x49}} , - {{0xa8, 0x50, 0xe1, 0x61, 0x6b, 0x57, 0x35, 0xeb, 0x44, 0x0b, 0x0c, 0x6e, 0xf9, 0x25, 0x80, 0x74, 0xf2, 0x8f, 0x6f, 0x7a, 0x3e, 0x7f, 0x2d, 0xf3, 0x4e, 0x09, 0x65, 0x10, 0x5e, 0x03, 0x25, 0x32}}}, -{{{0xa9, 0x60, 0xdc, 0x0f, 0x64, 0xe5, 0x1d, 0xe2, 0x8d, 0x4f, 0x79, 0x2f, 0x0e, 0x24, 0x02, 0x00, 0x05, 0x77, 0x43, 0x25, 0x3d, 0x6a, 0xc7, 0xb7, 0xbf, 0x04, 0x08, 0x65, 0xf4, 0x39, 0x4b, 0x65}} , - {{0x96, 0x19, 0x12, 0x6b, 0x6a, 0xb7, 0xe3, 0xdc, 0x45, 0x9b, 0xdb, 0xb4, 0xa8, 0xae, 0xdc, 0xa8, 0x14, 0x44, 0x65, 0x62, 0xce, 0x34, 0x9a, 0x84, 0x18, 0x12, 0x01, 0xf1, 0xe2, 0x7b, 0xce, 0x50}}}, -{{{0x41, 0x21, 0x30, 0x53, 0x1b, 0x47, 0x01, 0xb7, 0x18, 0xd8, 0x82, 0x57, 0xbd, 0xa3, 0x60, 0xf0, 0x32, 0xf6, 0x5b, 0xf0, 0x30, 0x88, 0x91, 0x59, 0xfd, 0x90, 0xa2, 0xb9, 0x55, 0x93, 0x21, 0x34}} , - {{0x97, 0x67, 0x9e, 0xeb, 0x6a, 0xf9, 0x6e, 0xd6, 0x73, 0xe8, 0x6b, 0x29, 0xec, 0x63, 0x82, 0x00, 0xa8, 0x99, 0x1c, 0x1d, 0x30, 0xc8, 0x90, 0x52, 0x90, 0xb6, 0x6a, 0x80, 0x4e, 0xff, 0x4b, 0x51}}}, -{{{0x0f, 0x7d, 0x63, 0x8c, 0x6e, 0x5c, 0xde, 0x30, 0xdf, 0x65, 0xfa, 0x2e, 0xb0, 0xa3, 0x25, 0x05, 0x54, 0xbd, 0x25, 0xba, 0x06, 0xae, 0xdf, 0x8b, 0xd9, 0x1b, 0xea, 0x38, 0xb3, 0x05, 0x16, 0x09}} , - {{0xc7, 0x8c, 0xbf, 0x64, 0x28, 0xad, 0xf8, 0xa5, 0x5a, 0x6f, 0xc9, 0xba, 0xd5, 0x7f, 0xd5, 0xd6, 0xbd, 0x66, 0x2f, 0x3d, 0xaa, 0x54, 0xf6, 0xba, 0x32, 0x22, 0x9a, 0x1e, 0x52, 0x05, 0xf4, 0x1d}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0xaa, 0x1f, 0xbb, 0xeb, 0xfe, 0xe4, 0x87, 0xfc, 0xb1, 0x2c, 0xb7, 0x88, 0xf4, 0xc6, 0xb9, 0xf5, 0x24, 0x46, 0xf2, 0xa5, 0x9f, 0x8f, 0x8a, 0x93, 0x70, 0x69, 0xd4, 0x56, 0xec, 0xfd, 0x06, 0x46}} , - {{0x4e, 0x66, 0xcf, 0x4e, 0x34, 0xce, 0x0c, 0xd9, 0xa6, 0x50, 0xd6, 0x5e, 0x95, 0xaf, 0xe9, 0x58, 0xfa, 0xee, 0x9b, 0xb8, 0xa5, 0x0f, 0x35, 0xe0, 0x43, 0x82, 0x6d, 0x65, 0xe6, 0xd9, 0x00, 0x0f}}}, -{{{0x7b, 0x75, 0x3a, 0xfc, 0x64, 0xd3, 0x29, 0x7e, 0xdd, 0x49, 0x9a, 0x59, 0x53, 0xbf, 0xb4, 0xa7, 0x52, 0xb3, 0x05, 0xab, 0xc3, 0xaf, 0x16, 0x1a, 0x85, 0x42, 0x32, 0xa2, 0x86, 0xfa, 0x39, 0x43}} , - {{0x0e, 0x4b, 0xa3, 0x63, 0x8a, 0xfe, 0xa5, 0x58, 0xf1, 0x13, 0xbd, 0x9d, 0xaa, 0x7f, 0x76, 0x40, 0x70, 0x81, 0x10, 0x75, 0x99, 0xbb, 0xbe, 0x0b, 0x16, 0xe9, 0xba, 0x62, 0x34, 0xcc, 0x07, 0x6d}}}, -{{{0xc3, 0xf1, 0xc6, 0x93, 0x65, 0xee, 0x0b, 0xbc, 0xea, 0x14, 0xf0, 0xc1, 0xf8, 0x84, 0x89, 0xc2, 0xc9, 0xd7, 0xea, 0x34, 0xca, 0xa7, 0xc4, 0x99, 0xd5, 0x50, 0x69, 0xcb, 0xd6, 0x21, 0x63, 0x7c}} , - {{0x99, 0xeb, 0x7c, 0x31, 0x73, 0x64, 0x67, 0x7f, 0x0c, 0x66, 0xaa, 0x8c, 0x69, 0x91, 0xe2, 0x26, 0xd3, 0x23, 0xe2, 0x76, 0x5d, 0x32, 0x52, 0xdf, 0x5d, 0xc5, 0x8f, 0xb7, 0x7c, 0x84, 0xb3, 0x70}}}, -{{{0xeb, 0x01, 0xc7, 0x36, 0x97, 0x4e, 0xb6, 0xab, 0x5f, 0x0d, 0x2c, 0xba, 0x67, 0x64, 0x55, 0xde, 0xbc, 0xff, 0xa6, 0xec, 0x04, 0xd3, 0x8d, 0x39, 0x56, 0x5e, 0xee, 0xf8, 0xe4, 0x2e, 0x33, 0x62}} , - {{0x65, 0xef, 0xb8, 0x9f, 0xc8, 0x4b, 0xa7, 0xfd, 0x21, 0x49, 0x9b, 0x92, 0x35, 0x82, 0xd6, 0x0a, 0x9b, 0xf2, 0x79, 0xf1, 0x47, 0x2f, 0x6a, 0x7e, 0x9f, 0xcf, 0x18, 0x02, 0x3c, 0xfb, 0x1b, 0x3e}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0x2f, 0x8b, 0xc8, 0x40, 0x51, 0xd1, 0xac, 0x1a, 0x0b, 0xe4, 0xa9, 0xa2, 0x42, 0x21, 0x19, 0x2f, 0x7b, 0x97, 0xbf, 0xf7, 0x57, 0x6d, 0x3f, 0x3d, 0x4f, 0x0f, 0xe2, 0xb2, 0x81, 0x00, 0x9e, 0x7b}} , - {{0x8c, 0x85, 0x2b, 0xc4, 0xfc, 0xf1, 0xab, 0xe8, 0x79, 0x22, 0xc4, 0x84, 0x17, 0x3a, 0xfa, 0x86, 0xa6, 0x7d, 0xf9, 0xf3, 0x6f, 0x03, 0x57, 0x20, 0x4d, 0x79, 0xf9, 0x6e, 0x71, 0x54, 0x38, 0x09}}}, -{{{0x40, 0x29, 0x74, 0xa8, 0x2f, 0x5e, 0xf9, 0x79, 0xa4, 0xf3, 0x3e, 0xb9, 0xfd, 0x33, 0x31, 0xac, 0x9a, 0x69, 0x88, 0x1e, 0x77, 0x21, 0x2d, 0xf3, 0x91, 0x52, 0x26, 0x15, 0xb2, 0xa6, 0xcf, 0x7e}} , - {{0xc6, 0x20, 0x47, 0x6c, 0xa4, 0x7d, 0xcb, 0x63, 0xea, 0x5b, 0x03, 0xdf, 0x3e, 0x88, 0x81, 0x6d, 0xce, 0x07, 0x42, 0x18, 0x60, 0x7e, 0x7b, 0x55, 0xfe, 0x6a, 0xf3, 0xda, 0x5c, 0x8b, 0x95, 0x10}}}, -{{{0x62, 0xe4, 0x0d, 0x03, 0xb4, 0xd7, 0xcd, 0xfa, 0xbd, 0x46, 0xdf, 0x93, 0x71, 0x10, 0x2c, 0xa8, 0x3b, 0xb6, 0x09, 0x05, 0x70, 0x84, 0x43, 0x29, 0xa8, 0x59, 0xf5, 0x8e, 0x10, 0xe4, 0xd7, 0x20}} , - {{0x57, 0x82, 0x1c, 0xab, 0xbf, 0x62, 0x70, 0xe8, 0xc4, 0xcf, 0xf0, 0x28, 0x6e, 0x16, 0x3c, 0x08, 0x78, 0x89, 0x85, 0x46, 0x0f, 0xf6, 0x7f, 0xcf, 0xcb, 0x7e, 0xb8, 0x25, 0xe9, 0x5a, 0xfa, 0x03}}}, -{{{0xfb, 0x95, 0x92, 0x63, 0x50, 0xfc, 0x62, 0xf0, 0xa4, 0x5e, 0x8c, 0x18, 0xc2, 0x17, 0x24, 0xb7, 0x78, 0xc2, 0xa9, 0xe7, 0x6a, 0x32, 0xd6, 0x29, 0x85, 0xaf, 0xcb, 0x8d, 0x91, 0x13, 0xda, 0x6b}} , - {{0x36, 0x0a, 0xc2, 0xb6, 0x4b, 0xa5, 0x5d, 0x07, 0x17, 0x41, 0x31, 0x5f, 0x62, 0x46, 0xf8, 0x92, 0xf9, 0x66, 0x48, 0x73, 0xa6, 0x97, 0x0d, 0x7d, 0x88, 0xee, 0x62, 0xb1, 0x03, 0xa8, 0x3f, 0x2c}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0x4a, 0xb1, 0x70, 0x8a, 0xa9, 0xe8, 0x63, 0x79, 0x00, 0xe2, 0x25, 0x16, 0xca, 0x4b, 0x0f, 0xa4, 0x66, 0xad, 0x19, 0x9f, 0x88, 0x67, 0x0c, 0x8b, 0xc2, 0x4a, 0x5b, 0x2b, 0x6d, 0x95, 0xaf, 0x19}} , - {{0x8b, 0x9d, 0xb6, 0xcc, 0x60, 0xb4, 0x72, 0x4f, 0x17, 0x69, 0x5a, 0x4a, 0x68, 0x34, 0xab, 0xa1, 0x45, 0x32, 0x3c, 0x83, 0x87, 0x72, 0x30, 0x54, 0x77, 0x68, 0xae, 0xfb, 0xb5, 0x8b, 0x22, 0x5e}}}, -{{{0xf1, 0xb9, 0x87, 0x35, 0xc5, 0xbb, 0xb9, 0xcf, 0xf5, 0xd6, 0xcd, 0xd5, 0x0c, 0x7c, 0x0e, 0xe6, 0x90, 0x34, 0xfb, 0x51, 0x42, 0x1e, 0x6d, 0xac, 0x9a, 0x46, 0xc4, 0x97, 0x29, 0x32, 0xbf, 0x45}} , - {{0x66, 0x9e, 0xc6, 0x24, 0xc0, 0xed, 0xa5, 0x5d, 0x88, 0xd4, 0xf0, 0x73, 0x97, 0x7b, 0xea, 0x7f, 0x42, 0xff, 0x21, 0xa0, 0x9b, 0x2f, 0x9a, 0xfd, 0x53, 0x57, 0x07, 0x84, 0x48, 0x88, 0x9d, 0x52}}}, -{{{0xc6, 0x96, 0x48, 0x34, 0x2a, 0x06, 0xaf, 0x94, 0x3d, 0xf4, 0x1a, 0xcf, 0xf2, 0xc0, 0x21, 0xc2, 0x42, 0x5e, 0xc8, 0x2f, 0x35, 0xa2, 0x3e, 0x29, 0xfa, 0x0c, 0x84, 0xe5, 0x89, 0x72, 0x7c, 0x06}} , - {{0x32, 0x65, 0x03, 0xe5, 0x89, 0xa6, 0x6e, 0xb3, 0x5b, 0x8e, 0xca, 0xeb, 0xfe, 0x22, 0x56, 0x8b, 0x5d, 0x14, 0x4b, 0x4d, 0xf9, 0xbe, 0xb5, 0xf5, 0xe6, 0x5c, 0x7b, 0x8b, 0xf4, 0x13, 0x11, 0x34}}}, -{{{0x07, 0xc6, 0x22, 0x15, 0xe2, 0x9c, 0x60, 0xa2, 0x19, 0xd9, 0x27, 0xae, 0x37, 0x4e, 0xa6, 0xc9, 0x80, 0xa6, 0x91, 0x8f, 0x12, 0x49, 0xe5, 0x00, 0x18, 0x47, 0xd1, 0xd7, 0x28, 0x22, 0x63, 0x39}} , - {{0xe8, 0xe2, 0x00, 0x7e, 0xf2, 0x9e, 0x1e, 0x99, 0x39, 0x95, 0x04, 0xbd, 0x1e, 0x67, 0x7b, 0xb2, 0x26, 0xac, 0xe6, 0xaa, 0xe2, 0x46, 0xd5, 0xe4, 0xe8, 0x86, 0xbd, 0xab, 0x7c, 0x55, 0x59, 0x6f}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0x24, 0x64, 0x6e, 0x9b, 0x35, 0x71, 0x78, 0xce, 0x33, 0x03, 0x21, 0x33, 0x36, 0xf1, 0x73, 0x9b, 0xb9, 0x15, 0x8b, 0x2c, 0x69, 0xcf, 0x4d, 0xed, 0x4f, 0x4d, 0x57, 0x14, 0x13, 0x82, 0xa4, 0x4d}} , - {{0x65, 0x6e, 0x0a, 0xa4, 0x59, 0x07, 0x17, 0xf2, 0x6b, 0x4a, 0x1f, 0x6e, 0xf6, 0xb5, 0xbc, 0x62, 0xe4, 0xb6, 0xda, 0xa2, 0x93, 0xbc, 0x29, 0x05, 0xd2, 0xd2, 0x73, 0x46, 0x03, 0x16, 0x40, 0x31}}}, -{{{0x4c, 0x73, 0x6d, 0x15, 0xbd, 0xa1, 0x4d, 0x5c, 0x13, 0x0b, 0x24, 0x06, 0x98, 0x78, 0x1c, 0x5b, 0xeb, 0x1f, 0x18, 0x54, 0x43, 0xd9, 0x55, 0x66, 0xda, 0x29, 0x21, 0xe8, 0xb8, 0x3c, 0x42, 0x22}} , - {{0xb4, 0xcd, 0x08, 0x6f, 0x15, 0x23, 0x1a, 0x0b, 0x22, 0xed, 0xd1, 0xf1, 0xa7, 0xc7, 0x73, 0x45, 0xf3, 0x9e, 0xce, 0x76, 0xb7, 0xf6, 0x39, 0xb6, 0x8e, 0x79, 0xbe, 0xe9, 0x9b, 0xcf, 0x7d, 0x62}}}, -{{{0x92, 0x5b, 0xfc, 0x72, 0xfd, 0xba, 0xf1, 0xfd, 0xa6, 0x7c, 0x95, 0xe3, 0x61, 0x3f, 0xe9, 0x03, 0xd4, 0x2b, 0xd4, 0x20, 0xd9, 0xdb, 0x4d, 0x32, 0x3e, 0xf5, 0x11, 0x64, 0xe3, 0xb4, 0xbe, 0x32}} , - {{0x86, 0x17, 0x90, 0xe7, 0xc9, 0x1f, 0x10, 0xa5, 0x6a, 0x2d, 0x39, 0xd0, 0x3b, 0xc4, 0xa6, 0xe9, 0x59, 0x13, 0xda, 0x1a, 0xe6, 0xa0, 0xb9, 0x3c, 0x50, 0xb8, 0x40, 0x7c, 0x15, 0x36, 0x5a, 0x42}}}, -{{{0xb4, 0x0b, 0x32, 0xab, 0xdc, 0x04, 0x51, 0x55, 0x21, 0x1e, 0x0b, 0x75, 0x99, 0x89, 0x73, 0x35, 0x3a, 0x91, 0x2b, 0xfe, 0xe7, 0x49, 0xea, 0x76, 0xc1, 0xf9, 0x46, 0xb9, 0x53, 0x02, 0x23, 0x04}} , - {{0xfc, 0x5a, 0x1e, 0x1d, 0x74, 0x58, 0x95, 0xa6, 0x8f, 0x7b, 0x97, 0x3e, 0x17, 0x3b, 0x79, 0x2d, 0xa6, 0x57, 0xef, 0x45, 0x02, 0x0b, 0x4d, 0x6e, 0x9e, 0x93, 0x8d, 0x2f, 0xd9, 0x9d, 0xdb, 0x04}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0xc0, 0xd7, 0x56, 0x97, 0x58, 0x91, 0xde, 0x09, 0x4f, 0x9f, 0xbe, 0x63, 0xb0, 0x83, 0x86, 0x43, 0x5d, 0xbc, 0xe0, 0xf3, 0xc0, 0x75, 0xbf, 0x8b, 0x8e, 0xaa, 0xf7, 0x8b, 0x64, 0x6e, 0xb0, 0x63}} , - {{0x16, 0xae, 0x8b, 0xe0, 0x9b, 0x24, 0x68, 0x5c, 0x44, 0xc2, 0xd0, 0x08, 0xb7, 0x7b, 0x62, 0xfd, 0x7f, 0xd8, 0xd4, 0xb7, 0x50, 0xfd, 0x2c, 0x1b, 0xbf, 0x41, 0x95, 0xd9, 0x8e, 0xd8, 0x17, 0x1b}}}, -{{{0x86, 0x55, 0x37, 0x8e, 0xc3, 0x38, 0x48, 0x14, 0xb5, 0x97, 0xd2, 0xa7, 0x54, 0x45, 0xf1, 0x35, 0x44, 0x38, 0x9e, 0xf1, 0x1b, 0xb6, 0x34, 0x00, 0x3c, 0x96, 0xee, 0x29, 0x00, 0xea, 0x2c, 0x0b}} , - {{0xea, 0xda, 0x99, 0x9e, 0x19, 0x83, 0x66, 0x6d, 0xe9, 0x76, 0x87, 0x50, 0xd1, 0xfd, 0x3c, 0x60, 0x87, 0xc6, 0x41, 0xd9, 0x8e, 0xdb, 0x5e, 0xde, 0xaa, 0x9a, 0xd3, 0x28, 0xda, 0x95, 0xea, 0x47}}}, -{{{0xd0, 0x80, 0xba, 0x19, 0xae, 0x1d, 0xa9, 0x79, 0xf6, 0x3f, 0xac, 0x5d, 0x6f, 0x96, 0x1f, 0x2a, 0xce, 0x29, 0xb2, 0xff, 0x37, 0xf1, 0x94, 0x8f, 0x0c, 0xb5, 0x28, 0xba, 0x9a, 0x21, 0xf6, 0x66}} , - {{0x02, 0xfb, 0x54, 0xb8, 0x05, 0xf3, 0x81, 0x52, 0x69, 0x34, 0x46, 0x9d, 0x86, 0x76, 0x8f, 0xd7, 0xf8, 0x6a, 0x66, 0xff, 0xe6, 0xa7, 0x90, 0xf7, 0x5e, 0xcd, 0x6a, 0x9b, 0x55, 0xfc, 0x9d, 0x48}}}, -{{{0xbd, 0xaa, 0x13, 0xe6, 0xcd, 0x45, 0x4a, 0xa4, 0x59, 0x0a, 0x64, 0xb1, 0x98, 0xd6, 0x34, 0x13, 0x04, 0xe6, 0x97, 0x94, 0x06, 0xcb, 0xd4, 0x4e, 0xbb, 0x96, 0xcd, 0xd1, 0x57, 0xd1, 0xe3, 0x06}} , - {{0x7a, 0x6c, 0x45, 0x27, 0xc4, 0x93, 0x7f, 0x7d, 0x7c, 0x62, 0x50, 0x38, 0x3a, 0x6b, 0xb5, 0x88, 0xc6, 0xd9, 0xf1, 0x78, 0x19, 0xb9, 0x39, 0x93, 0x3d, 0xc9, 0xe0, 0x9c, 0x3c, 0xce, 0xf5, 0x72}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0x24, 0xea, 0x23, 0x7d, 0x56, 0x2c, 0xe2, 0x59, 0x0e, 0x85, 0x60, 0x04, 0x88, 0x5a, 0x74, 0x1e, 0x4b, 0xef, 0x13, 0xda, 0x4c, 0xff, 0x83, 0x45, 0x85, 0x3f, 0x08, 0x95, 0x2c, 0x20, 0x13, 0x1f}} , - {{0x48, 0x5f, 0x27, 0x90, 0x5c, 0x02, 0x42, 0xad, 0x78, 0x47, 0x5c, 0xb5, 0x7e, 0x08, 0x85, 0x00, 0xfa, 0x7f, 0xfd, 0xfd, 0xe7, 0x09, 0x11, 0xf2, 0x7e, 0x1b, 0x38, 0x6c, 0x35, 0x6d, 0x33, 0x66}}}, -{{{0x93, 0x03, 0x36, 0x81, 0xac, 0xe4, 0x20, 0x09, 0x35, 0x4c, 0x45, 0xb2, 0x1e, 0x4c, 0x14, 0x21, 0xe6, 0xe9, 0x8a, 0x7b, 0x8d, 0xfe, 0x1e, 0xc6, 0x3e, 0xc1, 0x35, 0xfa, 0xe7, 0x70, 0x4e, 0x1d}} , - {{0x61, 0x2e, 0xc2, 0xdd, 0x95, 0x57, 0xd1, 0xab, 0x80, 0xe8, 0x63, 0x17, 0xb5, 0x48, 0xe4, 0x8a, 0x11, 0x9e, 0x72, 0xbe, 0x85, 0x8d, 0x51, 0x0a, 0xf2, 0x9f, 0xe0, 0x1c, 0xa9, 0x07, 0x28, 0x7b}}}, -{{{0xbb, 0x71, 0x14, 0x5e, 0x26, 0x8c, 0x3d, 0xc8, 0xe9, 0x7c, 0xd3, 0xd6, 0xd1, 0x2f, 0x07, 0x6d, 0xe6, 0xdf, 0xfb, 0x79, 0xd6, 0x99, 0x59, 0x96, 0x48, 0x40, 0x0f, 0x3a, 0x7b, 0xb2, 0xa0, 0x72}} , - {{0x4e, 0x3b, 0x69, 0xc8, 0x43, 0x75, 0x51, 0x6c, 0x79, 0x56, 0xe4, 0xcb, 0xf7, 0xa6, 0x51, 0xc2, 0x2c, 0x42, 0x0b, 0xd4, 0x82, 0x20, 0x1c, 0x01, 0x08, 0x66, 0xd7, 0xbf, 0x04, 0x56, 0xfc, 0x02}}}, -{{{0x24, 0xe8, 0xb7, 0x60, 0xae, 0x47, 0x80, 0xfc, 0xe5, 0x23, 0xe7, 0xc2, 0xc9, 0x85, 0xe6, 0x98, 0xa0, 0x29, 0x4e, 0xe1, 0x84, 0x39, 0x2d, 0x95, 0x2c, 0xf3, 0x45, 0x3c, 0xff, 0xaf, 0x27, 0x4c}} , - {{0x6b, 0xa6, 0xf5, 0x4b, 0x11, 0xbd, 0xba, 0x5b, 0x9e, 0xc4, 0xa4, 0x51, 0x1e, 0xbe, 0xd0, 0x90, 0x3a, 0x9c, 0xc2, 0x26, 0xb6, 0x1e, 0xf1, 0x95, 0x7d, 0xc8, 0x6d, 0x52, 0xe6, 0x99, 0x2c, 0x5f}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0x85, 0xe0, 0x24, 0x32, 0xb4, 0xd1, 0xef, 0xfc, 0x69, 0xa2, 0xbf, 0x8f, 0x72, 0x2c, 0x95, 0xf6, 0xe4, 0x6e, 0x7d, 0x90, 0xf7, 0x57, 0x81, 0xa0, 0xf7, 0xda, 0xef, 0x33, 0x07, 0xe3, 0x6b, 0x78}} , - {{0x36, 0x27, 0x3e, 0xc6, 0x12, 0x07, 0xab, 0x4e, 0xbe, 0x69, 0x9d, 0xb3, 0xbe, 0x08, 0x7c, 0x2a, 0x47, 0x08, 0xfd, 0xd4, 0xcd, 0x0e, 0x27, 0x34, 0x5b, 0x98, 0x34, 0x2f, 0x77, 0x5f, 0x3a, 0x65}}}, -{{{0x13, 0xaa, 0x2e, 0x4c, 0xf0, 0x22, 0xb8, 0x6c, 0xb3, 0x19, 0x4d, 0xeb, 0x6b, 0xd0, 0xa4, 0xc6, 0x9c, 0xdd, 0xc8, 0x5b, 0x81, 0x57, 0x89, 0xdf, 0x33, 0xa9, 0x68, 0x49, 0x80, 0xe4, 0xfe, 0x21}} , - {{0x00, 0x17, 0x90, 0x30, 0xe9, 0xd3, 0x60, 0x30, 0x31, 0xc2, 0x72, 0x89, 0x7a, 0x36, 0xa5, 0xbd, 0x39, 0x83, 0x85, 0x50, 0xa1, 0x5d, 0x6c, 0x41, 0x1d, 0xb5, 0x2c, 0x07, 0x40, 0x77, 0x0b, 0x50}}}, -{{{0x64, 0x34, 0xec, 0xc0, 0x9e, 0x44, 0x41, 0xaf, 0xa0, 0x36, 0x05, 0x6d, 0xea, 0x30, 0x25, 0x46, 0x35, 0x24, 0x9d, 0x86, 0xbd, 0x95, 0xf1, 0x6a, 0x46, 0xd7, 0x94, 0x54, 0xf9, 0x3b, 0xbd, 0x5d}} , - {{0x77, 0x5b, 0xe2, 0x37, 0xc7, 0xe1, 0x7c, 0x13, 0x8c, 0x9f, 0x7b, 0x7b, 0x2a, 0xce, 0x42, 0xa3, 0xb9, 0x2a, 0x99, 0xa8, 0xc0, 0xd8, 0x3c, 0x86, 0xb0, 0xfb, 0xe9, 0x76, 0x77, 0xf7, 0xf5, 0x56}}}, -{{{0xdf, 0xb3, 0x46, 0x11, 0x6e, 0x13, 0xb7, 0x28, 0x4e, 0x56, 0xdd, 0xf1, 0xac, 0xad, 0x58, 0xc3, 0xf8, 0x88, 0x94, 0x5e, 0x06, 0x98, 0xa1, 0xe4, 0x6a, 0xfb, 0x0a, 0x49, 0x5d, 0x8a, 0xfe, 0x77}} , - {{0x46, 0x02, 0xf5, 0xa5, 0xaf, 0xc5, 0x75, 0x6d, 0xba, 0x45, 0x35, 0x0a, 0xfe, 0xc9, 0xac, 0x22, 0x91, 0x8d, 0x21, 0x95, 0x33, 0x03, 0xc0, 0x8a, 0x16, 0xf3, 0x39, 0xe0, 0x01, 0x0f, 0x53, 0x3c}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0x34, 0x75, 0x37, 0x1f, 0x34, 0x4e, 0xa9, 0x1d, 0x68, 0x67, 0xf8, 0x49, 0x98, 0x96, 0xfc, 0x4c, 0x65, 0x97, 0xf7, 0x02, 0x4a, 0x52, 0x6c, 0x01, 0xbd, 0x48, 0xbb, 0x1b, 0xed, 0xa4, 0xe2, 0x53}} , - {{0x59, 0xd5, 0x9b, 0x5a, 0xa2, 0x90, 0xd3, 0xb8, 0x37, 0x4c, 0x55, 0x82, 0x28, 0x08, 0x0f, 0x7f, 0xaa, 0x81, 0x65, 0xe0, 0x0c, 0x52, 0xc9, 0xa3, 0x32, 0x27, 0x64, 0xda, 0xfd, 0x34, 0x23, 0x5a}}}, -{{{0xb5, 0xb0, 0x0c, 0x4d, 0xb3, 0x7b, 0x23, 0xc8, 0x1f, 0x8a, 0x39, 0x66, 0xe6, 0xba, 0x4c, 0x10, 0x37, 0xca, 0x9c, 0x7c, 0x05, 0x9e, 0xff, 0xc0, 0xf8, 0x8e, 0xb1, 0x8f, 0x6f, 0x67, 0x18, 0x26}} , - {{0x4b, 0x41, 0x13, 0x54, 0x23, 0x1a, 0xa4, 0x4e, 0xa9, 0x8b, 0x1e, 0x4b, 0xfc, 0x15, 0x24, 0xbb, 0x7e, 0xcb, 0xb6, 0x1e, 0x1b, 0xf5, 0xf2, 0xc8, 0x56, 0xec, 0x32, 0xa2, 0x60, 0x5b, 0xa0, 0x2a}}}, -{{{0xa4, 0x29, 0x47, 0x86, 0x2e, 0x92, 0x4f, 0x11, 0x4f, 0xf3, 0xb2, 0x5c, 0xd5, 0x3e, 0xa6, 0xb9, 0xc8, 0xe2, 0x33, 0x11, 0x1f, 0x01, 0x8f, 0xb0, 0x9b, 0xc7, 0xa5, 0xff, 0x83, 0x0f, 0x1e, 0x28}} , - {{0x1d, 0x29, 0x7a, 0xa1, 0xec, 0x8e, 0xb5, 0xad, 0xea, 0x02, 0x68, 0x60, 0x74, 0x29, 0x1c, 0xa5, 0xcf, 0xc8, 0x3b, 0x7d, 0x8b, 0x2b, 0x7c, 0xad, 0xa4, 0x40, 0x17, 0x51, 0x59, 0x7c, 0x2e, 0x5d}}}, -{{{0x0a, 0x6c, 0x4f, 0xbc, 0x3e, 0x32, 0xe7, 0x4a, 0x1a, 0x13, 0xc1, 0x49, 0x38, 0xbf, 0xf7, 0xc2, 0xd3, 0x8f, 0x6b, 0xad, 0x52, 0xf7, 0xcf, 0xbc, 0x27, 0xcb, 0x40, 0x67, 0x76, 0xcd, 0x6d, 0x56}} , - {{0xe5, 0xb0, 0x27, 0xad, 0xbe, 0x9b, 0xf2, 0xb5, 0x63, 0xde, 0x3a, 0x23, 0x95, 0xb7, 0x0a, 0x7e, 0xf3, 0x9e, 0x45, 0x6f, 0x19, 0x39, 0x75, 0x8f, 0x39, 0x3d, 0x0f, 0xc0, 0x9f, 0xf1, 0xe9, 0x51}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0x88, 0xaa, 0x14, 0x24, 0x86, 0x94, 0x11, 0x12, 0x3e, 0x1a, 0xb5, 0xcc, 0xbb, 0xe0, 0x9c, 0xd5, 0x9c, 0x6d, 0xba, 0x58, 0x72, 0x8d, 0xfb, 0x22, 0x7b, 0x9f, 0x7c, 0x94, 0x30, 0xb3, 0x51, 0x21}} , - {{0xf6, 0x74, 0x3d, 0xf2, 0xaf, 0xd0, 0x1e, 0x03, 0x7c, 0x23, 0x6b, 0xc9, 0xfc, 0x25, 0x70, 0x90, 0xdc, 0x9a, 0xa4, 0xfb, 0x49, 0xfc, 0x3d, 0x0a, 0x35, 0x38, 0x6f, 0xe4, 0x7e, 0x50, 0x01, 0x2a}}}, -{{{0xd6, 0xe3, 0x96, 0x61, 0x3a, 0xfd, 0xef, 0x9b, 0x1f, 0x90, 0xa4, 0x24, 0x14, 0x5b, 0xc8, 0xde, 0x50, 0xb1, 0x1d, 0xaf, 0xe8, 0x55, 0x8a, 0x87, 0x0d, 0xfe, 0xaa, 0x3b, 0x82, 0x2c, 0x8d, 0x7b}} , - {{0x85, 0x0c, 0xaf, 0xf8, 0x83, 0x44, 0x49, 0xd9, 0x45, 0xcf, 0xf7, 0x48, 0xd9, 0x53, 0xb4, 0xf1, 0x65, 0xa0, 0xe1, 0xc3, 0xb3, 0x15, 0xed, 0x89, 0x9b, 0x4f, 0x62, 0xb3, 0x57, 0xa5, 0x45, 0x1c}}}, -{{{0x8f, 0x12, 0xea, 0xaf, 0xd1, 0x1f, 0x79, 0x10, 0x0b, 0xf6, 0xa3, 0x7b, 0xea, 0xac, 0x8b, 0x57, 0x32, 0x62, 0xe7, 0x06, 0x12, 0x51, 0xa0, 0x3b, 0x43, 0x5e, 0xa4, 0x20, 0x78, 0x31, 0xce, 0x0d}} , - {{0x84, 0x7c, 0xc2, 0xa6, 0x91, 0x23, 0xce, 0xbd, 0xdc, 0xf9, 0xce, 0xd5, 0x75, 0x30, 0x22, 0xe6, 0xf9, 0x43, 0x62, 0x0d, 0xf7, 0x75, 0x9d, 0x7f, 0x8c, 0xff, 0x7d, 0xe4, 0x72, 0xac, 0x9f, 0x1c}}}, -{{{0x88, 0xc1, 0x99, 0xd0, 0x3c, 0x1c, 0x5d, 0xb4, 0xef, 0x13, 0x0f, 0x90, 0xb9, 0x36, 0x2f, 0x95, 0x95, 0xc6, 0xdc, 0xde, 0x0a, 0x51, 0xe2, 0x8d, 0xf3, 0xbc, 0x51, 0xec, 0xdf, 0xb1, 0xa2, 0x5f}} , - {{0x2e, 0x68, 0xa1, 0x23, 0x7d, 0x9b, 0x40, 0x69, 0x85, 0x7b, 0x42, 0xbf, 0x90, 0x4b, 0xd6, 0x40, 0x2f, 0xd7, 0x52, 0x52, 0xb2, 0x21, 0xde, 0x64, 0xbd, 0x88, 0xc3, 0x6d, 0xa5, 0xfa, 0x81, 0x3f}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0xfb, 0xfd, 0x47, 0x7b, 0x8a, 0x66, 0x9e, 0x79, 0x2e, 0x64, 0x82, 0xef, 0xf7, 0x21, 0xec, 0xf6, 0xd8, 0x86, 0x09, 0x31, 0x7c, 0xdd, 0x03, 0x6a, 0x58, 0xa0, 0x77, 0xb7, 0x9b, 0x8c, 0x87, 0x1f}} , - {{0x55, 0x47, 0xe4, 0xa8, 0x3d, 0x55, 0x21, 0x34, 0xab, 0x1d, 0xae, 0xe0, 0xf4, 0xea, 0xdb, 0xc5, 0xb9, 0x58, 0xbf, 0xc4, 0x2a, 0x89, 0x31, 0x1a, 0xf4, 0x2d, 0xe1, 0xca, 0x37, 0x99, 0x47, 0x59}}}, -{{{0xc7, 0xca, 0x63, 0xc1, 0x49, 0xa9, 0x35, 0x45, 0x55, 0x7e, 0xda, 0x64, 0x32, 0x07, 0x50, 0xf7, 0x32, 0xac, 0xde, 0x75, 0x58, 0x9b, 0x11, 0xb2, 0x3a, 0x1f, 0xf5, 0xf7, 0x79, 0x04, 0xe6, 0x08}} , - {{0x46, 0xfa, 0x22, 0x4b, 0xfa, 0xe1, 0xfe, 0x96, 0xfc, 0x67, 0xba, 0x67, 0x97, 0xc4, 0xe7, 0x1b, 0x86, 0x90, 0x5f, 0xee, 0xf4, 0x5b, 0x11, 0xb2, 0xcd, 0xad, 0xee, 0xc2, 0x48, 0x6c, 0x2b, 0x1b}}}, -{{{0xe3, 0x39, 0x62, 0xb4, 0x4f, 0x31, 0x04, 0xc9, 0xda, 0xd5, 0x73, 0x51, 0x57, 0xc5, 0xb8, 0xf3, 0xa3, 0x43, 0x70, 0xe4, 0x61, 0x81, 0x84, 0xe2, 0xbb, 0xbf, 0x4f, 0x9e, 0xa4, 0x5e, 0x74, 0x06}} , - {{0x29, 0xac, 0xff, 0x27, 0xe0, 0x59, 0xbe, 0x39, 0x9c, 0x0d, 0x83, 0xd7, 0x10, 0x0b, 0x15, 0xb7, 0xe1, 0xc2, 0x2c, 0x30, 0x73, 0x80, 0x3a, 0x7d, 0x5d, 0xab, 0x58, 0x6b, 0xc1, 0xf0, 0xf4, 0x22}}}, -{{{0xfe, 0x7f, 0xfb, 0x35, 0x7d, 0xc6, 0x01, 0x23, 0x28, 0xc4, 0x02, 0xac, 0x1f, 0x42, 0xb4, 0x9d, 0xfc, 0x00, 0x94, 0xa5, 0xee, 0xca, 0xda, 0x97, 0x09, 0x41, 0x77, 0x87, 0x5d, 0x7b, 0x87, 0x78}} , - {{0xf5, 0xfb, 0x90, 0x2d, 0x81, 0x19, 0x9e, 0x2f, 0x6d, 0x85, 0x88, 0x8c, 0x40, 0x5c, 0x77, 0x41, 0x4d, 0x01, 0x19, 0x76, 0x60, 0xe8, 0x4c, 0x48, 0xe4, 0x33, 0x83, 0x32, 0x6c, 0xb4, 0x41, 0x03}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0xff, 0x10, 0xc2, 0x09, 0x4f, 0x6e, 0xf4, 0xd2, 0xdf, 0x7e, 0xca, 0x7b, 0x1c, 0x1d, 0xba, 0xa3, 0xb6, 0xda, 0x67, 0x33, 0xd4, 0x87, 0x36, 0x4b, 0x11, 0x20, 0x05, 0xa6, 0x29, 0xc1, 0x87, 0x17}} , - {{0xf6, 0x96, 0xca, 0x2f, 0xda, 0x38, 0xa7, 0x1b, 0xfc, 0xca, 0x7d, 0xfe, 0x08, 0x89, 0xe2, 0x47, 0x2b, 0x6a, 0x5d, 0x4b, 0xfa, 0xa1, 0xb4, 0xde, 0xb6, 0xc2, 0x31, 0x51, 0xf5, 0xe0, 0xa4, 0x0b}}}, -{{{0x5c, 0xe5, 0xc6, 0x04, 0x8e, 0x2b, 0x57, 0xbe, 0x38, 0x85, 0x23, 0xcb, 0xb7, 0xbe, 0x4f, 0xa9, 0xd3, 0x6e, 0x12, 0xaa, 0xd5, 0xb2, 0x2e, 0x93, 0x29, 0x9a, 0x4a, 0x88, 0x18, 0x43, 0xf5, 0x01}} , - {{0x50, 0xfc, 0xdb, 0xa2, 0x59, 0x21, 0x8d, 0xbd, 0x7e, 0x33, 0xae, 0x2f, 0x87, 0x1a, 0xd0, 0x97, 0xc7, 0x0d, 0x4d, 0x63, 0x01, 0xef, 0x05, 0x84, 0xec, 0x40, 0xdd, 0xa8, 0x0a, 0x4f, 0x70, 0x0b}}}, -{{{0x41, 0x69, 0x01, 0x67, 0x5c, 0xd3, 0x8a, 0xc5, 0xcf, 0x3f, 0xd1, 0x57, 0xd1, 0x67, 0x3e, 0x01, 0x39, 0xb5, 0xcb, 0x81, 0x56, 0x96, 0x26, 0xb6, 0xc2, 0xe7, 0x5c, 0xfb, 0x63, 0x97, 0x58, 0x06}} , - {{0x0c, 0x0e, 0xf3, 0xba, 0xf0, 0xe5, 0xba, 0xb2, 0x57, 0x77, 0xc6, 0x20, 0x9b, 0x89, 0x24, 0xbe, 0xf2, 0x9c, 0x8a, 0xba, 0x69, 0xc1, 0xf1, 0xb0, 0x4f, 0x2a, 0x05, 0x9a, 0xee, 0x10, 0x7e, 0x36}}}, -{{{0x3f, 0x26, 0xe9, 0x40, 0xe9, 0x03, 0xad, 0x06, 0x69, 0x91, 0xe0, 0xd1, 0x89, 0x60, 0x84, 0x79, 0xde, 0x27, 0x6d, 0xe6, 0x76, 0xbd, 0xea, 0xe6, 0xae, 0x48, 0xc3, 0x67, 0xc0, 0x57, 0xcd, 0x2f}} , - {{0x7f, 0xc1, 0xdc, 0xb9, 0xc7, 0xbc, 0x86, 0x3d, 0x55, 0x4b, 0x28, 0x7a, 0xfb, 0x4d, 0xc7, 0xf8, 0xbc, 0x67, 0x2a, 0x60, 0x4d, 0x8f, 0x07, 0x0b, 0x1a, 0x17, 0xbf, 0xfa, 0xac, 0xa7, 0x3d, 0x1a}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0x91, 0x3f, 0xed, 0x5e, 0x18, 0x78, 0x3f, 0x23, 0x2c, 0x0d, 0x8c, 0x44, 0x00, 0xe8, 0xfb, 0xe9, 0x8e, 0xd6, 0xd1, 0x36, 0x58, 0x57, 0x9e, 0xae, 0x4b, 0x5c, 0x0b, 0x07, 0xbc, 0x6b, 0x55, 0x2b}} , - {{0x6f, 0x4d, 0x17, 0xd7, 0xe1, 0x84, 0xd9, 0x78, 0xb1, 0x90, 0xfd, 0x2e, 0xb3, 0xb5, 0x19, 0x3f, 0x1b, 0xfa, 0xc0, 0x68, 0xb3, 0xdd, 0x00, 0x2e, 0x89, 0xbd, 0x7e, 0x80, 0x32, 0x13, 0xa0, 0x7b}}}, -{{{0x1a, 0x6f, 0x40, 0xaf, 0x44, 0x44, 0xb0, 0x43, 0x8f, 0x0d, 0xd0, 0x1e, 0xc4, 0x0b, 0x19, 0x5d, 0x8e, 0xfe, 0xc1, 0xf3, 0xc5, 0x5c, 0x91, 0xf8, 0x04, 0x4e, 0xbe, 0x90, 0xb4, 0x47, 0x5c, 0x3f}} , - {{0xb0, 0x3b, 0x2c, 0xf3, 0xfe, 0x32, 0x71, 0x07, 0x3f, 0xaa, 0xba, 0x45, 0x60, 0xa8, 0x8d, 0xea, 0x54, 0xcb, 0x39, 0x10, 0xb4, 0xf2, 0x8b, 0xd2, 0x14, 0x82, 0x42, 0x07, 0x8e, 0xe9, 0x7c, 0x53}}}, -{{{0xb0, 0xae, 0xc1, 0x8d, 0xc9, 0x8f, 0xb9, 0x7a, 0x77, 0xef, 0xba, 0x79, 0xa0, 0x3c, 0xa8, 0xf5, 0x6a, 0xe2, 0x3f, 0x5d, 0x00, 0xe3, 0x4b, 0x45, 0x24, 0x7b, 0x43, 0x78, 0x55, 0x1d, 0x2b, 0x1e}} , - {{0x01, 0xb8, 0xd6, 0x16, 0x67, 0xa0, 0x15, 0xb9, 0xe1, 0x58, 0xa4, 0xa7, 0x31, 0x37, 0x77, 0x2f, 0x8b, 0x12, 0x9f, 0xf4, 0x3f, 0xc7, 0x36, 0x66, 0xd2, 0xa8, 0x56, 0xf7, 0x7f, 0x74, 0xc6, 0x41}}}, -{{{0x5d, 0xf8, 0xb4, 0xa8, 0x30, 0xdd, 0xcc, 0x38, 0xa5, 0xd3, 0xca, 0xd8, 0xd1, 0xf8, 0xb2, 0x31, 0x91, 0xd4, 0x72, 0x05, 0x57, 0x4a, 0x3b, 0x82, 0x4a, 0xc6, 0x68, 0x20, 0xe2, 0x18, 0x41, 0x61}} , - {{0x19, 0xd4, 0x8d, 0x47, 0x29, 0x12, 0x65, 0xb0, 0x11, 0x78, 0x47, 0xb5, 0xcb, 0xa3, 0xa5, 0xfa, 0x05, 0x85, 0x54, 0xa9, 0x33, 0x97, 0x8d, 0x2b, 0xc2, 0xfe, 0x99, 0x35, 0x28, 0xe5, 0xeb, 0x63}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0xb1, 0x3f, 0x3f, 0xef, 0xd8, 0xf4, 0xfc, 0xb3, 0xa0, 0x60, 0x50, 0x06, 0x2b, 0x29, 0x52, 0x70, 0x15, 0x0b, 0x24, 0x24, 0xf8, 0x5f, 0x79, 0x18, 0xcc, 0xff, 0x89, 0x99, 0x84, 0xa1, 0xae, 0x13}} , - {{0x44, 0x1f, 0xb8, 0xc2, 0x01, 0xc1, 0x30, 0x19, 0x55, 0x05, 0x60, 0x10, 0xa4, 0x6c, 0x2d, 0x67, 0x70, 0xe5, 0x25, 0x1b, 0xf2, 0xbf, 0xdd, 0xfb, 0x70, 0x2b, 0xa1, 0x8c, 0x9c, 0x94, 0x84, 0x08}}}, -{{{0xe7, 0xc4, 0x43, 0x4d, 0xc9, 0x2b, 0x69, 0x5d, 0x1d, 0x3c, 0xaf, 0xbb, 0x43, 0x38, 0x4e, 0x98, 0x3d, 0xed, 0x0d, 0x21, 0x03, 0xfd, 0xf0, 0x99, 0x47, 0x04, 0xb0, 0x98, 0x69, 0x55, 0x72, 0x0f}} , - {{0x5e, 0xdf, 0x15, 0x53, 0x3b, 0x86, 0x80, 0xb0, 0xf1, 0x70, 0x68, 0x8f, 0x66, 0x7c, 0x0e, 0x49, 0x1a, 0xd8, 0x6b, 0xfe, 0x4e, 0xef, 0xca, 0x47, 0xd4, 0x03, 0xc1, 0x37, 0x50, 0x9c, 0xc1, 0x16}}}, -{{{0xcd, 0x24, 0xc6, 0x3e, 0x0c, 0x82, 0x9b, 0x91, 0x2b, 0x61, 0x4a, 0xb2, 0x0f, 0x88, 0x55, 0x5f, 0x5a, 0x57, 0xff, 0xe5, 0x74, 0x0b, 0x13, 0x43, 0x00, 0xd8, 0x6b, 0xcf, 0xd2, 0x15, 0x03, 0x2c}} , - {{0xdc, 0xff, 0x15, 0x61, 0x2f, 0x4a, 0x2f, 0x62, 0xf2, 0x04, 0x2f, 0xb5, 0x0c, 0xb7, 0x1e, 0x3f, 0x74, 0x1a, 0x0f, 0xd7, 0xea, 0xcd, 0xd9, 0x7d, 0xf6, 0x12, 0x0e, 0x2f, 0xdb, 0x5a, 0x3b, 0x16}}}, -{{{0x1b, 0x37, 0x47, 0xe3, 0xf5, 0x9e, 0xea, 0x2c, 0x2a, 0xe7, 0x82, 0x36, 0xf4, 0x1f, 0x81, 0x47, 0x92, 0x4b, 0x69, 0x0e, 0x11, 0x8c, 0x5d, 0x53, 0x5b, 0x81, 0x27, 0x08, 0xbc, 0xa0, 0xae, 0x25}} , - {{0x69, 0x32, 0xa1, 0x05, 0x11, 0x42, 0x00, 0xd2, 0x59, 0xac, 0x4d, 0x62, 0x8b, 0x13, 0xe2, 0x50, 0x5d, 0xa0, 0x9d, 0x9b, 0xfd, 0xbb, 0x12, 0x41, 0x75, 0x41, 0x9e, 0xcc, 0xdc, 0xc7, 0xdc, 0x5d}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0xd9, 0xe3, 0x38, 0x06, 0x46, 0x70, 0x82, 0x5e, 0x28, 0x49, 0x79, 0xff, 0x25, 0xd2, 0x4e, 0x29, 0x8d, 0x06, 0xb0, 0x23, 0xae, 0x9b, 0x66, 0xe4, 0x7d, 0xc0, 0x70, 0x91, 0xa3, 0xfc, 0xec, 0x4e}} , - {{0x62, 0x12, 0x37, 0x6a, 0x30, 0xf6, 0x1e, 0xfb, 0x14, 0x5c, 0x0d, 0x0e, 0xb7, 0x81, 0x6a, 0xe7, 0x08, 0x05, 0xac, 0xaa, 0x38, 0x46, 0xe2, 0x73, 0xea, 0x4b, 0x07, 0x81, 0x43, 0x7c, 0x9e, 0x5e}}}, -{{{0xfc, 0xf9, 0x21, 0x4f, 0x2e, 0x76, 0x9b, 0x1f, 0x28, 0x60, 0x77, 0x43, 0x32, 0x9d, 0xbe, 0x17, 0x30, 0x2a, 0xc6, 0x18, 0x92, 0x66, 0x62, 0x30, 0x98, 0x40, 0x11, 0xa6, 0x7f, 0x18, 0x84, 0x28}} , - {{0x3f, 0xab, 0xd3, 0xf4, 0x8a, 0x76, 0xa1, 0x3c, 0xca, 0x2d, 0x49, 0xc3, 0xea, 0x08, 0x0b, 0x85, 0x17, 0x2a, 0xc3, 0x6c, 0x08, 0xfd, 0x57, 0x9f, 0x3d, 0x5f, 0xdf, 0x67, 0x68, 0x42, 0x00, 0x32}}}, -{{{0x51, 0x60, 0x1b, 0x06, 0x4f, 0x8a, 0x21, 0xba, 0x38, 0xa8, 0xba, 0xd6, 0x40, 0xf6, 0xe9, 0x9b, 0x76, 0x4d, 0x56, 0x21, 0x5b, 0x0a, 0x9b, 0x2e, 0x4f, 0x3d, 0x81, 0x32, 0x08, 0x9f, 0x97, 0x5b}} , - {{0xe5, 0x44, 0xec, 0x06, 0x9d, 0x90, 0x79, 0x9f, 0xd3, 0xe0, 0x79, 0xaf, 0x8f, 0x10, 0xfd, 0xdd, 0x04, 0xae, 0x27, 0x97, 0x46, 0x33, 0x79, 0xea, 0xb8, 0x4e, 0xca, 0x5a, 0x59, 0x57, 0xe1, 0x0e}}}, -{{{0x1a, 0xda, 0xf3, 0xa5, 0x41, 0x43, 0x28, 0xfc, 0x7e, 0xe7, 0x71, 0xea, 0xc6, 0x3b, 0x59, 0xcc, 0x2e, 0xd3, 0x40, 0xec, 0xb3, 0x13, 0x6f, 0x44, 0xcd, 0x13, 0xb2, 0x37, 0xf2, 0x6e, 0xd9, 0x1c}} , - {{0xe3, 0xdb, 0x60, 0xcd, 0x5c, 0x4a, 0x18, 0x0f, 0xef, 0x73, 0x36, 0x71, 0x8c, 0xf6, 0x11, 0xb4, 0xd8, 0xce, 0x17, 0x5e, 0x4f, 0x26, 0x77, 0x97, 0x5f, 0xcb, 0xef, 0x91, 0xeb, 0x6a, 0x62, 0x7a}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0x18, 0x4a, 0xa2, 0x97, 0x08, 0x81, 0x2d, 0x83, 0xc4, 0xcc, 0xf0, 0x83, 0x7e, 0xec, 0x0d, 0x95, 0x4c, 0x5b, 0xfb, 0xfa, 0x98, 0x80, 0x4a, 0x66, 0x56, 0x0c, 0x51, 0xb3, 0xf2, 0x04, 0x5d, 0x27}} , - {{0x3b, 0xb9, 0xb8, 0x06, 0x5a, 0x2e, 0xfe, 0xc3, 0x82, 0x37, 0x9c, 0xa3, 0x11, 0x1f, 0x9c, 0xa6, 0xda, 0x63, 0x48, 0x9b, 0xad, 0xde, 0x2d, 0xa6, 0xbc, 0x6e, 0x32, 0xda, 0x27, 0x65, 0xdd, 0x57}}}, -{{{0x84, 0x4f, 0x37, 0x31, 0x7d, 0x2e, 0xbc, 0xad, 0x87, 0x07, 0x2a, 0x6b, 0x37, 0xfc, 0x5f, 0xeb, 0x4e, 0x75, 0x35, 0xa6, 0xde, 0xab, 0x0a, 0x19, 0x3a, 0xb7, 0xb1, 0xef, 0x92, 0x6a, 0x3b, 0x3c}} , - {{0x3b, 0xb2, 0x94, 0x6d, 0x39, 0x60, 0xac, 0xee, 0xe7, 0x81, 0x1a, 0x3b, 0x76, 0x87, 0x5c, 0x05, 0x94, 0x2a, 0x45, 0xb9, 0x80, 0xe9, 0x22, 0xb1, 0x07, 0xcb, 0x40, 0x9e, 0x70, 0x49, 0x6d, 0x12}}}, -{{{0xfd, 0x18, 0x78, 0x84, 0xa8, 0x4c, 0x7d, 0x6e, 0x59, 0xa6, 0xe5, 0x74, 0xf1, 0x19, 0xa6, 0x84, 0x2e, 0x51, 0xc1, 0x29, 0x13, 0xf2, 0x14, 0x6b, 0x5d, 0x53, 0x51, 0xf7, 0xef, 0xbf, 0x01, 0x22}} , - {{0xa4, 0x4b, 0x62, 0x4c, 0xe6, 0xfd, 0x72, 0x07, 0xf2, 0x81, 0xfc, 0xf2, 0xbd, 0x12, 0x7c, 0x68, 0x76, 0x2a, 0xba, 0xf5, 0x65, 0xb1, 0x1f, 0x17, 0x0a, 0x38, 0xb0, 0xbf, 0xc0, 0xf8, 0xf4, 0x2a}}}, -{{{0x55, 0x60, 0x55, 0x5b, 0xe4, 0x1d, 0x71, 0x4c, 0x9d, 0x5b, 0x9f, 0x70, 0xa6, 0x85, 0x9a, 0x2c, 0xa0, 0xe2, 0x32, 0x48, 0xce, 0x9e, 0x2a, 0xa5, 0x07, 0x3b, 0xc7, 0x6c, 0x86, 0x77, 0xde, 0x3c}} , - {{0xf7, 0x18, 0x7a, 0x96, 0x7e, 0x43, 0x57, 0xa9, 0x55, 0xfc, 0x4e, 0xb6, 0x72, 0x00, 0xf2, 0xe4, 0xd7, 0x52, 0xd3, 0xd3, 0xb6, 0x85, 0xf6, 0x71, 0xc7, 0x44, 0x3f, 0x7f, 0xd7, 0xb3, 0xf2, 0x79}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0x46, 0xca, 0xa7, 0x55, 0x7b, 0x79, 0xf3, 0xca, 0x5a, 0x65, 0xf6, 0xed, 0x50, 0x14, 0x7b, 0xe4, 0xc4, 0x2a, 0x65, 0x9e, 0xe2, 0xf9, 0xca, 0xa7, 0x22, 0x26, 0x53, 0xcb, 0x21, 0x5b, 0xa7, 0x31}} , - {{0x90, 0xd7, 0xc5, 0x26, 0x08, 0xbd, 0xb0, 0x53, 0x63, 0x58, 0xc3, 0x31, 0x5e, 0x75, 0x46, 0x15, 0x91, 0xa6, 0xf8, 0x2f, 0x1a, 0x08, 0x65, 0x88, 0x2f, 0x98, 0x04, 0xf1, 0x7c, 0x6e, 0x00, 0x77}}}, -{{{0x81, 0x21, 0x61, 0x09, 0xf6, 0x4e, 0xf1, 0x92, 0xee, 0x63, 0x61, 0x73, 0x87, 0xc7, 0x54, 0x0e, 0x42, 0x4b, 0xc9, 0x47, 0xd1, 0xb8, 0x7e, 0x91, 0x75, 0x37, 0x99, 0x28, 0xb8, 0xdd, 0x7f, 0x50}} , - {{0x89, 0x8f, 0xc0, 0xbe, 0x5d, 0xd6, 0x9f, 0xa0, 0xf0, 0x9d, 0x81, 0xce, 0x3a, 0x7b, 0x98, 0x58, 0xbb, 0xd7, 0x78, 0xc8, 0x3f, 0x13, 0xf1, 0x74, 0x19, 0xdf, 0xf8, 0x98, 0x89, 0x5d, 0xfa, 0x5f}}}, -{{{0x9e, 0x35, 0x85, 0x94, 0x47, 0x1f, 0x90, 0x15, 0x26, 0xd0, 0x84, 0xed, 0x8a, 0x80, 0xf7, 0x63, 0x42, 0x86, 0x27, 0xd7, 0xf4, 0x75, 0x58, 0xdc, 0x9c, 0xc0, 0x22, 0x7e, 0x20, 0x35, 0xfd, 0x1f}} , - {{0x68, 0x0e, 0x6f, 0x97, 0xba, 0x70, 0xbb, 0xa3, 0x0e, 0xe5, 0x0b, 0x12, 0xf4, 0xa2, 0xdc, 0x47, 0xf8, 0xe6, 0xd0, 0x23, 0x6c, 0x33, 0xa8, 0x99, 0x46, 0x6e, 0x0f, 0x44, 0xba, 0x76, 0x48, 0x0f}}}, -{{{0xa3, 0x2a, 0x61, 0x37, 0xe2, 0x59, 0x12, 0x0e, 0x27, 0xba, 0x64, 0x43, 0xae, 0xc0, 0x42, 0x69, 0x79, 0xa4, 0x1e, 0x29, 0x8b, 0x15, 0xeb, 0xf8, 0xaf, 0xd4, 0xa2, 0x68, 0x33, 0xb5, 0x7a, 0x24}} , - {{0x2c, 0x19, 0x33, 0xdd, 0x1b, 0xab, 0xec, 0x01, 0xb0, 0x23, 0xf8, 0x42, 0x2b, 0x06, 0x88, 0xea, 0x3d, 0x2d, 0x00, 0x2a, 0x78, 0x45, 0x4d, 0x38, 0xed, 0x2e, 0x2e, 0x44, 0x49, 0xed, 0xcb, 0x33}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0xa0, 0x68, 0xe8, 0x41, 0x8f, 0x91, 0xf8, 0x11, 0x13, 0x90, 0x2e, 0xa7, 0xab, 0x30, 0xef, 0xad, 0xa0, 0x61, 0x00, 0x88, 0xef, 0xdb, 0xce, 0x5b, 0x5c, 0xbb, 0x62, 0xc8, 0x56, 0xf9, 0x00, 0x73}} , - {{0x3f, 0x60, 0xc1, 0x82, 0x2d, 0xa3, 0x28, 0x58, 0x24, 0x9e, 0x9f, 0xe3, 0x70, 0xcc, 0x09, 0x4e, 0x1a, 0x3f, 0x11, 0x11, 0x15, 0x07, 0x3c, 0xa4, 0x41, 0xe0, 0x65, 0xa3, 0x0a, 0x41, 0x6d, 0x11}}}, -{{{0x31, 0x40, 0x01, 0x52, 0x56, 0x94, 0x5b, 0x28, 0x8a, 0xaa, 0x52, 0xee, 0xd8, 0x0a, 0x05, 0x8d, 0xcd, 0xb5, 0xaa, 0x2e, 0x38, 0xaa, 0xb7, 0x87, 0xf7, 0x2b, 0xfb, 0x04, 0xcb, 0x84, 0x3d, 0x54}} , - {{0x20, 0xef, 0x59, 0xde, 0xa4, 0x2b, 0x93, 0x6e, 0x2e, 0xec, 0x42, 0x9a, 0xd4, 0x2d, 0xf4, 0x46, 0x58, 0x27, 0x2b, 0x18, 0x8f, 0x83, 0x3d, 0x69, 0x9e, 0xd4, 0x3e, 0xb6, 0xc5, 0xfd, 0x58, 0x03}}}, -{{{0x33, 0x89, 0xc9, 0x63, 0x62, 0x1c, 0x17, 0xb4, 0x60, 0xc4, 0x26, 0x68, 0x09, 0xc3, 0x2e, 0x37, 0x0f, 0x7b, 0xb4, 0x9c, 0xb6, 0xf9, 0xfb, 0xd4, 0x51, 0x78, 0xc8, 0x63, 0xea, 0x77, 0x47, 0x07}} , - {{0x32, 0xb4, 0x18, 0x47, 0x79, 0xcb, 0xd4, 0x5a, 0x07, 0x14, 0x0f, 0xa0, 0xd5, 0xac, 0xd0, 0x41, 0x40, 0xab, 0x61, 0x23, 0xe5, 0x2a, 0x2a, 0x6f, 0xf7, 0xa8, 0xd4, 0x76, 0xef, 0xe7, 0x45, 0x6c}}}, -{{{0xa1, 0x5e, 0x60, 0x4f, 0xfb, 0xe1, 0x70, 0x6a, 0x1f, 0x55, 0x4f, 0x09, 0xb4, 0x95, 0x33, 0x36, 0xc6, 0x81, 0x01, 0x18, 0x06, 0x25, 0x27, 0xa4, 0xb4, 0x24, 0xa4, 0x86, 0x03, 0x4c, 0xac, 0x02}} , - {{0x77, 0x38, 0xde, 0xd7, 0x60, 0x48, 0x07, 0xf0, 0x74, 0xa8, 0xff, 0x54, 0xe5, 0x30, 0x43, 0xff, 0x77, 0xfb, 0x21, 0x07, 0xff, 0xb2, 0x07, 0x6b, 0xe4, 0xe5, 0x30, 0xfc, 0x19, 0x6c, 0xa3, 0x01}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0x13, 0xc5, 0x2c, 0xac, 0xd3, 0x83, 0x82, 0x7c, 0x29, 0xf7, 0x05, 0xa5, 0x00, 0xb6, 0x1f, 0x86, 0x55, 0xf4, 0xd6, 0x2f, 0x0c, 0x99, 0xd0, 0x65, 0x9b, 0x6b, 0x46, 0x0d, 0x43, 0xf8, 0x16, 0x28}} , - {{0x1e, 0x7f, 0xb4, 0x74, 0x7e, 0xb1, 0x89, 0x4f, 0x18, 0x5a, 0xab, 0x64, 0x06, 0xdf, 0x45, 0x87, 0xe0, 0x6a, 0xc6, 0xf0, 0x0e, 0xc9, 0x24, 0x35, 0x38, 0xea, 0x30, 0x54, 0xb4, 0xc4, 0x52, 0x54}}}, -{{{0xe9, 0x9f, 0xdc, 0x3f, 0xc1, 0x89, 0x44, 0x74, 0x27, 0xe4, 0xc1, 0x90, 0xff, 0x4a, 0xa7, 0x3c, 0xee, 0xcd, 0xf4, 0x1d, 0x25, 0x94, 0x7f, 0x63, 0x16, 0x48, 0xbc, 0x64, 0xfe, 0x95, 0xc4, 0x0c}} , - {{0x8b, 0x19, 0x75, 0x6e, 0x03, 0x06, 0x5e, 0x6a, 0x6f, 0x1a, 0x8c, 0xe3, 0xd3, 0x28, 0xf2, 0xe0, 0xb9, 0x7a, 0x43, 0x69, 0xe6, 0xd3, 0xc0, 0xfe, 0x7e, 0x97, 0xab, 0x6c, 0x7b, 0x8e, 0x13, 0x42}}}, -{{{0xd4, 0xca, 0x70, 0x3d, 0xab, 0xfb, 0x5f, 0x5e, 0x00, 0x0c, 0xcc, 0x77, 0x22, 0xf8, 0x78, 0x55, 0xae, 0x62, 0x35, 0xfb, 0x9a, 0xc6, 0x03, 0xe4, 0x0c, 0xee, 0xab, 0xc7, 0xc0, 0x89, 0x87, 0x54}} , - {{0x32, 0xad, 0xae, 0x85, 0x58, 0x43, 0xb8, 0xb1, 0xe6, 0x3e, 0x00, 0x9c, 0x78, 0x88, 0x56, 0xdb, 0x9c, 0xfc, 0x79, 0xf6, 0xf9, 0x41, 0x5f, 0xb7, 0xbc, 0x11, 0xf9, 0x20, 0x36, 0x1c, 0x53, 0x2b}}}, -{{{0x5a, 0x20, 0x5b, 0xa1, 0xa5, 0x44, 0x91, 0x24, 0x02, 0x63, 0x12, 0x64, 0xb8, 0x55, 0xf6, 0xde, 0x2c, 0xdb, 0x47, 0xb8, 0xc6, 0x0a, 0xc3, 0x00, 0x78, 0x93, 0xd8, 0xf5, 0xf5, 0x18, 0x28, 0x0a}} , - {{0xd6, 0x1b, 0x9a, 0x6c, 0xe5, 0x46, 0xea, 0x70, 0x96, 0x8d, 0x4e, 0x2a, 0x52, 0x21, 0x26, 0x4b, 0xb1, 0xbb, 0x0f, 0x7c, 0xa9, 0x9b, 0x04, 0xbb, 0x51, 0x08, 0xf1, 0x9a, 0xa4, 0x76, 0x7c, 0x18}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0xfa, 0x94, 0xf7, 0x40, 0xd0, 0xd7, 0xeb, 0xa9, 0x82, 0x36, 0xd5, 0x15, 0xb9, 0x33, 0x7a, 0xbf, 0x8a, 0xf2, 0x63, 0xaa, 0x37, 0xf5, 0x59, 0xac, 0xbd, 0xbb, 0x32, 0x36, 0xbe, 0x73, 0x99, 0x38}} , - {{0x2c, 0xb3, 0xda, 0x7a, 0xd8, 0x3d, 0x99, 0xca, 0xd2, 0xf4, 0xda, 0x99, 0x8e, 0x4f, 0x98, 0xb7, 0xf4, 0xae, 0x3e, 0x9f, 0x8e, 0x35, 0x60, 0xa4, 0x33, 0x75, 0xa4, 0x04, 0x93, 0xb1, 0x6b, 0x4d}}}, -{{{0x97, 0x9d, 0xa8, 0xcd, 0x97, 0x7b, 0x9d, 0xb9, 0xe7, 0xa5, 0xef, 0xfd, 0xa8, 0x42, 0x6b, 0xc3, 0x62, 0x64, 0x7d, 0xa5, 0x1b, 0xc9, 0x9e, 0xd2, 0x45, 0xb9, 0xee, 0x03, 0xb0, 0xbf, 0xc0, 0x68}} , - {{0xed, 0xb7, 0x84, 0x2c, 0xf6, 0xd3, 0xa1, 0x6b, 0x24, 0x6d, 0x87, 0x56, 0x97, 0x59, 0x79, 0x62, 0x9f, 0xac, 0xed, 0xf3, 0xc9, 0x89, 0x21, 0x2e, 0x04, 0xb3, 0xcc, 0x2f, 0xbe, 0xd6, 0x0a, 0x4b}}}, -{{{0x39, 0x61, 0x05, 0xed, 0x25, 0x89, 0x8b, 0x5d, 0x1b, 0xcb, 0x0c, 0x55, 0xf4, 0x6a, 0x00, 0x8a, 0x46, 0xe8, 0x1e, 0xc6, 0x83, 0xc8, 0x5a, 0x76, 0xdb, 0xcc, 0x19, 0x7a, 0xcc, 0x67, 0x46, 0x0b}} , - {{0x53, 0xcf, 0xc2, 0xa1, 0xad, 0x6a, 0xf3, 0xcd, 0x8f, 0xc9, 0xde, 0x1c, 0xf8, 0x6c, 0x8f, 0xf8, 0x76, 0x42, 0xe7, 0xfe, 0xb2, 0x72, 0x21, 0x0a, 0x66, 0x74, 0x8f, 0xb7, 0xeb, 0xe4, 0x6f, 0x01}}}, -{{{0x22, 0x8c, 0x6b, 0xbe, 0xfc, 0x4d, 0x70, 0x62, 0x6e, 0x52, 0x77, 0x99, 0x88, 0x7e, 0x7b, 0x57, 0x7a, 0x0d, 0xfe, 0xdc, 0x72, 0x92, 0xf1, 0x68, 0x1d, 0x97, 0xd7, 0x7c, 0x8d, 0x53, 0x10, 0x37}} , - {{0x53, 0x88, 0x77, 0x02, 0xca, 0x27, 0xa8, 0xe5, 0x45, 0xe2, 0xa8, 0x48, 0x2a, 0xab, 0x18, 0xca, 0xea, 0x2d, 0x2a, 0x54, 0x17, 0x37, 0x32, 0x09, 0xdc, 0xe0, 0x4a, 0xb7, 0x7d, 0x82, 0x10, 0x7d}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0x8a, 0x64, 0x1e, 0x14, 0x0a, 0x57, 0xd4, 0xda, 0x5c, 0x96, 0x9b, 0x01, 0x4c, 0x67, 0xbf, 0x8b, 0x30, 0xfe, 0x08, 0xdb, 0x0d, 0xd5, 0xa8, 0xd7, 0x09, 0x11, 0x85, 0xa2, 0xd3, 0x45, 0xfb, 0x7e}} , - {{0xda, 0x8c, 0xc2, 0xd0, 0xac, 0x18, 0xe8, 0x52, 0x36, 0xd4, 0x21, 0xa3, 0xdd, 0x57, 0x22, 0x79, 0xb7, 0xf8, 0x71, 0x9d, 0xc6, 0x91, 0x70, 0x86, 0x56, 0xbf, 0xa1, 0x11, 0x8b, 0x19, 0xe1, 0x0f}}}, -{{{0x18, 0x32, 0x98, 0x2c, 0x8f, 0x91, 0xae, 0x12, 0xf0, 0x8c, 0xea, 0xf3, 0x3c, 0xb9, 0x5d, 0xe4, 0x69, 0xed, 0xb2, 0x47, 0x18, 0xbd, 0xce, 0x16, 0x52, 0x5c, 0x23, 0xe2, 0xa5, 0x25, 0x52, 0x5d}} , - {{0xb9, 0xb1, 0xe7, 0x5d, 0x4e, 0xbc, 0xee, 0xbb, 0x40, 0x81, 0x77, 0x82, 0x19, 0xab, 0xb5, 0xc6, 0xee, 0xab, 0x5b, 0x6b, 0x63, 0x92, 0x8a, 0x34, 0x8d, 0xcd, 0xee, 0x4f, 0x49, 0xe5, 0xc9, 0x7e}}}, -{{{0x21, 0xac, 0x8b, 0x22, 0xcd, 0xc3, 0x9a, 0xe9, 0x5e, 0x78, 0xbd, 0xde, 0xba, 0xad, 0xab, 0xbf, 0x75, 0x41, 0x09, 0xc5, 0x58, 0xa4, 0x7d, 0x92, 0xb0, 0x7f, 0xf2, 0xa1, 0xd1, 0xc0, 0xb3, 0x6d}} , - {{0x62, 0x4f, 0xd0, 0x75, 0x77, 0xba, 0x76, 0x77, 0xd7, 0xb8, 0xd8, 0x92, 0x6f, 0x98, 0x34, 0x3d, 0xd6, 0x4e, 0x1c, 0x0f, 0xf0, 0x8f, 0x2e, 0xf1, 0xb3, 0xbd, 0xb1, 0xb9, 0xec, 0x99, 0xb4, 0x07}}}, -{{{0x60, 0x57, 0x2e, 0x9a, 0x72, 0x1d, 0x6b, 0x6e, 0x58, 0x33, 0x24, 0x8c, 0x48, 0x39, 0x46, 0x8e, 0x89, 0x6a, 0x88, 0x51, 0x23, 0x62, 0xb5, 0x32, 0x09, 0x36, 0xe3, 0x57, 0xf5, 0x98, 0xde, 0x6f}} , - {{0x8b, 0x2c, 0x00, 0x48, 0x4a, 0xf9, 0x5b, 0x87, 0x69, 0x52, 0xe5, 0x5b, 0xd1, 0xb1, 0xe5, 0x25, 0x25, 0xe0, 0x9c, 0xc2, 0x13, 0x44, 0xe8, 0xb9, 0x0a, 0x70, 0xad, 0xbd, 0x0f, 0x51, 0x94, 0x69}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0xa2, 0xdc, 0xab, 0xa9, 0x25, 0x2d, 0xac, 0x5f, 0x03, 0x33, 0x08, 0xe7, 0x7e, 0xfe, 0x95, 0x36, 0x3c, 0x5b, 0x3a, 0xd3, 0x05, 0x82, 0x1c, 0x95, 0x2d, 0xd8, 0x77, 0x7e, 0x02, 0xd9, 0x5b, 0x70}} , - {{0xc2, 0xfe, 0x1b, 0x0c, 0x67, 0xcd, 0xd6, 0xe0, 0x51, 0x8e, 0x2c, 0xe0, 0x79, 0x88, 0xf0, 0xcf, 0x41, 0x4a, 0xad, 0x23, 0xd4, 0x46, 0xca, 0x94, 0xa1, 0xc3, 0xeb, 0x28, 0x06, 0xfa, 0x17, 0x14}}}, -{{{0x7b, 0xaa, 0x70, 0x0a, 0x4b, 0xfb, 0xf5, 0xbf, 0x80, 0xc5, 0xcf, 0x08, 0x7a, 0xdd, 0xa1, 0xf4, 0x9d, 0x54, 0x50, 0x53, 0x23, 0x77, 0x23, 0xf5, 0x34, 0xa5, 0x22, 0xd1, 0x0d, 0x96, 0x2e, 0x47}} , - {{0xcc, 0xb7, 0x32, 0x89, 0x57, 0xd0, 0x98, 0x75, 0xe4, 0x37, 0x99, 0xa9, 0xe8, 0xba, 0xed, 0xba, 0xeb, 0xc7, 0x4f, 0x15, 0x76, 0x07, 0x0c, 0x4c, 0xef, 0x9f, 0x52, 0xfc, 0x04, 0x5d, 0x58, 0x10}}}, -{{{0xce, 0x82, 0xf0, 0x8f, 0x79, 0x02, 0xa8, 0xd1, 0xda, 0x14, 0x09, 0x48, 0xee, 0x8a, 0x40, 0x98, 0x76, 0x60, 0x54, 0x5a, 0xde, 0x03, 0x24, 0xf5, 0xe6, 0x2f, 0xe1, 0x03, 0xbf, 0x68, 0x82, 0x7f}} , - {{0x64, 0xe9, 0x28, 0xc7, 0xa4, 0xcf, 0x2a, 0xf9, 0x90, 0x64, 0x72, 0x2c, 0x8b, 0xeb, 0xec, 0xa0, 0xf2, 0x7d, 0x35, 0xb5, 0x90, 0x4d, 0x7f, 0x5b, 0x4a, 0x49, 0xe4, 0xb8, 0x3b, 0xc8, 0xa1, 0x2f}}}, -{{{0x8b, 0xc5, 0xcc, 0x3d, 0x69, 0xa6, 0xa1, 0x18, 0x44, 0xbc, 0x4d, 0x77, 0x37, 0xc7, 0x86, 0xec, 0x0c, 0xc9, 0xd6, 0x44, 0xa9, 0x23, 0x27, 0xb9, 0x03, 0x34, 0xa7, 0x0a, 0xd5, 0xc7, 0x34, 0x37}} , - {{0xf9, 0x7e, 0x3e, 0x66, 0xee, 0xf9, 0x99, 0x28, 0xff, 0xad, 0x11, 0xd8, 0xe2, 0x66, 0xc5, 0xcd, 0x0f, 0x0d, 0x0b, 0x6a, 0xfc, 0x7c, 0x24, 0xa8, 0x4f, 0xa8, 0x5e, 0x80, 0x45, 0x8b, 0x6c, 0x41}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0xef, 0x1e, 0xec, 0xf7, 0x8d, 0x77, 0xf2, 0xea, 0xdb, 0x60, 0x03, 0x21, 0xc0, 0xff, 0x5e, 0x67, 0xc3, 0x71, 0x0b, 0x21, 0xb4, 0x41, 0xa0, 0x68, 0x38, 0xc6, 0x01, 0xa3, 0xd3, 0x51, 0x3c, 0x3c}} , - {{0x92, 0xf8, 0xd6, 0x4b, 0xef, 0x42, 0x13, 0xb2, 0x4a, 0xc4, 0x2e, 0x72, 0x3f, 0xc9, 0x11, 0xbd, 0x74, 0x02, 0x0e, 0xf5, 0x13, 0x9d, 0x83, 0x1a, 0x1b, 0xd5, 0x54, 0xde, 0xc4, 0x1e, 0x16, 0x6c}}}, -{{{0x27, 0x52, 0xe4, 0x63, 0xaa, 0x94, 0xe6, 0xc3, 0x28, 0x9c, 0xc6, 0x56, 0xac, 0xfa, 0xb6, 0xbd, 0xe2, 0xcc, 0x76, 0xc6, 0x27, 0x27, 0xa2, 0x8e, 0x78, 0x2b, 0x84, 0x72, 0x10, 0xbd, 0x4e, 0x2a}} , - {{0xea, 0xa7, 0x23, 0xef, 0x04, 0x61, 0x80, 0x50, 0xc9, 0x6e, 0xa5, 0x96, 0xd1, 0xd1, 0xc8, 0xc3, 0x18, 0xd7, 0x2d, 0xfd, 0x26, 0xbd, 0xcb, 0x7b, 0x92, 0x51, 0x0e, 0x4a, 0x65, 0x57, 0xb8, 0x49}}}, -{{{0xab, 0x55, 0x36, 0xc3, 0xec, 0x63, 0x55, 0x11, 0x55, 0xf6, 0xa5, 0xc7, 0x01, 0x5f, 0xfe, 0x79, 0xd8, 0x0a, 0xf7, 0x03, 0xd8, 0x98, 0x99, 0xf5, 0xd0, 0x00, 0x54, 0x6b, 0x66, 0x28, 0xf5, 0x25}} , - {{0x7a, 0x8d, 0xa1, 0x5d, 0x70, 0x5d, 0x51, 0x27, 0xee, 0x30, 0x65, 0x56, 0x95, 0x46, 0xde, 0xbd, 0x03, 0x75, 0xb4, 0x57, 0x59, 0x89, 0xeb, 0x02, 0x9e, 0xcc, 0x89, 0x19, 0xa7, 0xcb, 0x17, 0x67}}}, -{{{0x6a, 0xeb, 0xfc, 0x9a, 0x9a, 0x10, 0xce, 0xdb, 0x3a, 0x1c, 0x3c, 0x6a, 0x9d, 0xea, 0x46, 0xbc, 0x45, 0x49, 0xac, 0xe3, 0x41, 0x12, 0x7c, 0xf0, 0xf7, 0x4f, 0xf9, 0xf7, 0xff, 0x2c, 0x89, 0x04}} , - {{0x30, 0x31, 0x54, 0x1a, 0x46, 0xca, 0xe6, 0xc6, 0xcb, 0xe2, 0xc3, 0xc1, 0x8b, 0x75, 0x81, 0xbe, 0xee, 0xf8, 0xa3, 0x11, 0x1c, 0x25, 0xa3, 0xa7, 0x35, 0x51, 0x55, 0xe2, 0x25, 0xaa, 0xe2, 0x3a}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0xb4, 0x48, 0x10, 0x9f, 0x8a, 0x09, 0x76, 0xfa, 0xf0, 0x7a, 0xb0, 0x70, 0xf7, 0x83, 0x80, 0x52, 0x84, 0x2b, 0x26, 0xa2, 0xc4, 0x5d, 0x4f, 0xba, 0xb1, 0xc8, 0x40, 0x0d, 0x78, 0x97, 0xc4, 0x60}} , - {{0xd4, 0xb1, 0x6c, 0x08, 0xc7, 0x40, 0x38, 0x73, 0x5f, 0x0b, 0xf3, 0x76, 0x5d, 0xb2, 0xa5, 0x2f, 0x57, 0x57, 0x07, 0xed, 0x08, 0xa2, 0x6c, 0x4f, 0x08, 0x02, 0xb5, 0x0e, 0xee, 0x44, 0xfa, 0x22}}}, -{{{0x0f, 0x00, 0x3f, 0xa6, 0x04, 0x19, 0x56, 0x65, 0x31, 0x7f, 0x8b, 0xeb, 0x0d, 0xe1, 0x47, 0x89, 0x97, 0x16, 0x53, 0xfa, 0x81, 0xa7, 0xaa, 0xb2, 0xbf, 0x67, 0xeb, 0x72, 0x60, 0x81, 0x0d, 0x48}} , - {{0x7e, 0x13, 0x33, 0xcd, 0xa8, 0x84, 0x56, 0x1e, 0x67, 0xaf, 0x6b, 0x43, 0xac, 0x17, 0xaf, 0x16, 0xc0, 0x52, 0x99, 0x49, 0x5b, 0x87, 0x73, 0x7e, 0xb5, 0x43, 0xda, 0x6b, 0x1d, 0x0f, 0x2d, 0x55}}}, -{{{0xe9, 0x58, 0x1f, 0xff, 0x84, 0x3f, 0x93, 0x1c, 0xcb, 0xe1, 0x30, 0x69, 0xa5, 0x75, 0x19, 0x7e, 0x14, 0x5f, 0xf8, 0xfc, 0x09, 0xdd, 0xa8, 0x78, 0x9d, 0xca, 0x59, 0x8b, 0xd1, 0x30, 0x01, 0x13}} , - {{0xff, 0x76, 0x03, 0xc5, 0x4b, 0x89, 0x99, 0x70, 0x00, 0x59, 0x70, 0x9c, 0xd5, 0xd9, 0x11, 0x89, 0x5a, 0x46, 0xfe, 0xef, 0xdc, 0xd9, 0x55, 0x2b, 0x45, 0xa7, 0xb0, 0x2d, 0xfb, 0x24, 0xc2, 0x29}}}, -{{{0x38, 0x06, 0xf8, 0x0b, 0xac, 0x82, 0xc4, 0x97, 0x2b, 0x90, 0xe0, 0xf7, 0xa8, 0xab, 0x6c, 0x08, 0x80, 0x66, 0x90, 0x46, 0xf7, 0x26, 0x2d, 0xf8, 0xf1, 0xc4, 0x6b, 0x4a, 0x82, 0x98, 0x8e, 0x37}} , - {{0x8e, 0xb4, 0xee, 0xb8, 0xd4, 0x3f, 0xb2, 0x1b, 0xe0, 0x0a, 0x3d, 0x75, 0x34, 0x28, 0xa2, 0x8e, 0xc4, 0x92, 0x7b, 0xfe, 0x60, 0x6e, 0x6d, 0xb8, 0x31, 0x1d, 0x62, 0x0d, 0x78, 0x14, 0x42, 0x11}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0x5e, 0xa8, 0xd8, 0x04, 0x9b, 0x73, 0xc9, 0xc9, 0xdc, 0x0d, 0x73, 0xbf, 0x0a, 0x0a, 0x73, 0xff, 0x18, 0x1f, 0x9c, 0x51, 0xaa, 0xc6, 0xf1, 0x83, 0x25, 0xfd, 0xab, 0xa3, 0x11, 0xd3, 0x01, 0x24}} , - {{0x4d, 0xe3, 0x7e, 0x38, 0x62, 0x5e, 0x64, 0xbb, 0x2b, 0x53, 0xb5, 0x03, 0x68, 0xc4, 0xf2, 0x2b, 0x5a, 0x03, 0x32, 0x99, 0x4a, 0x41, 0x9a, 0xe1, 0x1a, 0xae, 0x8c, 0x48, 0xf3, 0x24, 0x32, 0x65}}}, -{{{0xe8, 0xdd, 0xad, 0x3a, 0x8c, 0xea, 0xf4, 0xb3, 0xb2, 0xe5, 0x73, 0xf2, 0xed, 0x8b, 0xbf, 0xed, 0xb1, 0x0c, 0x0c, 0xfb, 0x2b, 0xf1, 0x01, 0x48, 0xe8, 0x26, 0x03, 0x8e, 0x27, 0x4d, 0x96, 0x72}} , - {{0xc8, 0x09, 0x3b, 0x60, 0xc9, 0x26, 0x4d, 0x7c, 0xf2, 0x9c, 0xd4, 0xa1, 0x3b, 0x26, 0xc2, 0x04, 0x33, 0x44, 0x76, 0x3c, 0x02, 0xbb, 0x11, 0x42, 0x0c, 0x22, 0xb7, 0xc6, 0xe1, 0xac, 0xb4, 0x0e}}}, -{{{0x6f, 0x85, 0xe7, 0xef, 0xde, 0x67, 0x30, 0xfc, 0xbf, 0x5a, 0xe0, 0x7b, 0x7a, 0x2a, 0x54, 0x6b, 0x5d, 0x62, 0x85, 0xa1, 0xf8, 0x16, 0x88, 0xec, 0x61, 0xb9, 0x96, 0xb5, 0xef, 0x2d, 0x43, 0x4d}} , - {{0x7c, 0x31, 0x33, 0xcc, 0xe4, 0xcf, 0x6c, 0xff, 0x80, 0x47, 0x77, 0xd1, 0xd8, 0xe9, 0x69, 0x97, 0x98, 0x7f, 0x20, 0x57, 0x1d, 0x1d, 0x4f, 0x08, 0x27, 0xc8, 0x35, 0x57, 0x40, 0xc6, 0x21, 0x0c}}}, -{{{0xd2, 0x8e, 0x9b, 0xfa, 0x42, 0x8e, 0xdf, 0x8f, 0xc7, 0x86, 0xf9, 0xa4, 0xca, 0x70, 0x00, 0x9d, 0x21, 0xbf, 0xec, 0x57, 0x62, 0x30, 0x58, 0x8c, 0x0d, 0x35, 0xdb, 0x5d, 0x8b, 0x6a, 0xa0, 0x5a}} , - {{0xc1, 0x58, 0x7c, 0x0d, 0x20, 0xdd, 0x11, 0x26, 0x5f, 0x89, 0x3b, 0x97, 0x58, 0xf8, 0x8b, 0xe3, 0xdf, 0x32, 0xe2, 0xfc, 0xd8, 0x67, 0xf2, 0xa5, 0x37, 0x1e, 0x6d, 0xec, 0x7c, 0x27, 0x20, 0x79}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0xd0, 0xe9, 0xc0, 0xfa, 0x95, 0x45, 0x23, 0x96, 0xf1, 0x2c, 0x79, 0x25, 0x14, 0xce, 0x40, 0x14, 0x44, 0x2c, 0x36, 0x50, 0xd9, 0x63, 0x56, 0xb7, 0x56, 0x3b, 0x9e, 0xa7, 0xef, 0x89, 0xbb, 0x0e}} , - {{0xce, 0x7f, 0xdc, 0x0a, 0xcc, 0x82, 0x1c, 0x0a, 0x78, 0x71, 0xe8, 0x74, 0x8d, 0x01, 0x30, 0x0f, 0xa7, 0x11, 0x4c, 0xdf, 0x38, 0xd7, 0xa7, 0x0d, 0xf8, 0x48, 0x52, 0x00, 0x80, 0x7b, 0x5f, 0x0e}}}, -{{{0x25, 0x83, 0xe6, 0x94, 0x7b, 0x81, 0xb2, 0x91, 0xae, 0x0e, 0x05, 0xc9, 0xa3, 0x68, 0x2d, 0xd9, 0x88, 0x25, 0x19, 0x2a, 0x61, 0x61, 0x21, 0x97, 0x15, 0xa1, 0x35, 0xa5, 0x46, 0xc8, 0xa2, 0x0e}} , - {{0x1b, 0x03, 0x0d, 0x8b, 0x5a, 0x1b, 0x97, 0x4b, 0xf2, 0x16, 0x31, 0x3d, 0x1f, 0x33, 0xa0, 0x50, 0x3a, 0x18, 0xbe, 0x13, 0xa1, 0x76, 0xc1, 0xba, 0x1b, 0xf1, 0x05, 0x7b, 0x33, 0xa8, 0x82, 0x3b}}}, -{{{0xba, 0x36, 0x7b, 0x6d, 0xa9, 0xea, 0x14, 0x12, 0xc5, 0xfa, 0x91, 0x00, 0xba, 0x9b, 0x99, 0xcc, 0x56, 0x02, 0xe9, 0xa0, 0x26, 0x40, 0x66, 0x8c, 0xc4, 0xf8, 0x85, 0x33, 0x68, 0xe7, 0x03, 0x20}} , - {{0x50, 0x5b, 0xff, 0xa9, 0xb2, 0xf1, 0xf1, 0x78, 0xcf, 0x14, 0xa4, 0xa9, 0xfc, 0x09, 0x46, 0x94, 0x54, 0x65, 0x0d, 0x9c, 0x5f, 0x72, 0x21, 0xe2, 0x97, 0xa5, 0x2d, 0x81, 0xce, 0x4a, 0x5f, 0x79}}}, -{{{0x3d, 0x5f, 0x5c, 0xd2, 0xbc, 0x7d, 0x77, 0x0e, 0x2a, 0x6d, 0x22, 0x45, 0x84, 0x06, 0xc4, 0xdd, 0xc6, 0xa6, 0xc6, 0xd7, 0x49, 0xad, 0x6d, 0x87, 0x91, 0x0e, 0x3a, 0x67, 0x1d, 0x2c, 0x1d, 0x56}} , - {{0xfe, 0x7a, 0x74, 0xcf, 0xd4, 0xd2, 0xe5, 0x19, 0xde, 0xd0, 0xdb, 0x70, 0x23, 0x69, 0xe6, 0x6d, 0xec, 0xec, 0xcc, 0x09, 0x33, 0x6a, 0x77, 0xdc, 0x6b, 0x22, 0x76, 0x5d, 0x92, 0x09, 0xac, 0x2d}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0x23, 0x15, 0x17, 0xeb, 0xd3, 0xdb, 0x12, 0x5e, 0x01, 0xf0, 0x91, 0xab, 0x2c, 0x41, 0xce, 0xac, 0xed, 0x1b, 0x4b, 0x2d, 0xbc, 0xdb, 0x17, 0x66, 0x89, 0x46, 0xad, 0x4b, 0x1e, 0x6f, 0x0b, 0x14}} , - {{0x11, 0xce, 0xbf, 0xb6, 0x77, 0x2d, 0x48, 0x22, 0x18, 0x4f, 0xa3, 0x5d, 0x4a, 0xb0, 0x70, 0x12, 0x3e, 0x54, 0xd7, 0xd8, 0x0e, 0x2b, 0x27, 0xdc, 0x53, 0xff, 0xca, 0x8c, 0x59, 0xb3, 0x4e, 0x44}}}, -{{{0x07, 0x76, 0x61, 0x0f, 0x66, 0xb2, 0x21, 0x39, 0x7e, 0xc0, 0xec, 0x45, 0x28, 0x82, 0xa1, 0x29, 0x32, 0x44, 0x35, 0x13, 0x5e, 0x61, 0x5e, 0x54, 0xcb, 0x7c, 0xef, 0xf6, 0x41, 0xcf, 0x9f, 0x0a}} , - {{0xdd, 0xf9, 0xda, 0x84, 0xc3, 0xe6, 0x8a, 0x9f, 0x24, 0xd2, 0x96, 0x5d, 0x39, 0x6f, 0x58, 0x8c, 0xc1, 0x56, 0x93, 0xab, 0xb5, 0x79, 0x3b, 0xd2, 0xa8, 0x73, 0x16, 0xed, 0xfa, 0xb4, 0x2f, 0x73}}}, -{{{0x8b, 0xb1, 0x95, 0xe5, 0x92, 0x50, 0x35, 0x11, 0x76, 0xac, 0xf4, 0x4d, 0x24, 0xc3, 0x32, 0xe6, 0xeb, 0xfe, 0x2c, 0x87, 0xc4, 0xf1, 0x56, 0xc4, 0x75, 0x24, 0x7a, 0x56, 0x85, 0x5a, 0x3a, 0x13}} , - {{0x0d, 0x16, 0xac, 0x3c, 0x4a, 0x58, 0x86, 0x3a, 0x46, 0x7f, 0x6c, 0xa3, 0x52, 0x6e, 0x37, 0xe4, 0x96, 0x9c, 0xe9, 0x5c, 0x66, 0x41, 0x67, 0xe4, 0xfb, 0x79, 0x0c, 0x05, 0xf6, 0x64, 0xd5, 0x7c}}}, -{{{0x28, 0xc1, 0xe1, 0x54, 0x73, 0xf2, 0xbf, 0x76, 0x74, 0x19, 0x19, 0x1b, 0xe4, 0xb9, 0xa8, 0x46, 0x65, 0x73, 0xf3, 0x77, 0x9b, 0x29, 0x74, 0x5b, 0xc6, 0x89, 0x6c, 0x2c, 0x7c, 0xf8, 0xb3, 0x0f}} , - {{0xf7, 0xd5, 0xe9, 0x74, 0x5d, 0xb8, 0x25, 0x16, 0xb5, 0x30, 0xbc, 0x84, 0xc5, 0xf0, 0xad, 0xca, 0x12, 0x28, 0xbc, 0x9d, 0xd4, 0xfa, 0x82, 0xe6, 0xe3, 0xbf, 0xa2, 0x15, 0x2c, 0xd4, 0x34, 0x10}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0x61, 0xb1, 0x46, 0xba, 0x0e, 0x31, 0xa5, 0x67, 0x6c, 0x7f, 0xd6, 0xd9, 0x27, 0x85, 0x0f, 0x79, 0x14, 0xc8, 0x6c, 0x2f, 0x5f, 0x5b, 0x9c, 0x35, 0x3d, 0x38, 0x86, 0x77, 0x65, 0x55, 0x6a, 0x7b}} , - {{0xd3, 0xb0, 0x3a, 0x66, 0x60, 0x1b, 0x43, 0xf1, 0x26, 0x58, 0x99, 0x09, 0x8f, 0x2d, 0xa3, 0x14, 0x71, 0x85, 0xdb, 0xed, 0xf6, 0x26, 0xd5, 0x61, 0x9a, 0x73, 0xac, 0x0e, 0xea, 0xac, 0xb7, 0x0c}}}, -{{{0x5e, 0xf4, 0xe5, 0x17, 0x0e, 0x10, 0x9f, 0xe7, 0x43, 0x5f, 0x67, 0x5c, 0xac, 0x4b, 0xe5, 0x14, 0x41, 0xd2, 0xbf, 0x48, 0xf5, 0x14, 0xb0, 0x71, 0xc6, 0x61, 0xc1, 0xb2, 0x70, 0x58, 0xd2, 0x5a}} , - {{0x2d, 0xba, 0x16, 0x07, 0x92, 0x94, 0xdc, 0xbd, 0x50, 0x2b, 0xc9, 0x7f, 0x42, 0x00, 0xba, 0x61, 0xed, 0xf8, 0x43, 0xed, 0xf5, 0xf9, 0x40, 0x60, 0xb2, 0xb0, 0x82, 0xcb, 0xed, 0x75, 0xc7, 0x65}}}, -{{{0x80, 0xba, 0x0d, 0x09, 0x40, 0xa7, 0x39, 0xa6, 0x67, 0x34, 0x7e, 0x66, 0xbe, 0x56, 0xfb, 0x53, 0x78, 0xc4, 0x46, 0xe8, 0xed, 0x68, 0x6c, 0x7f, 0xce, 0xe8, 0x9f, 0xce, 0xa2, 0x64, 0x58, 0x53}} , - {{0xe8, 0xc1, 0xa9, 0xc2, 0x7b, 0x59, 0x21, 0x33, 0xe2, 0x43, 0x73, 0x2b, 0xac, 0x2d, 0xc1, 0x89, 0x3b, 0x15, 0xe2, 0xd5, 0xc0, 0x97, 0x8a, 0xfd, 0x6f, 0x36, 0x33, 0xb7, 0xb9, 0xc3, 0x88, 0x09}}}, -{{{0xd0, 0xb6, 0x56, 0x30, 0x5c, 0xae, 0xb3, 0x75, 0x44, 0xa4, 0x83, 0x51, 0x6e, 0x01, 0x65, 0xef, 0x45, 0x76, 0xe6, 0xf5, 0xa2, 0x0d, 0xd4, 0x16, 0x3b, 0x58, 0x2f, 0xf2, 0x2f, 0x36, 0x18, 0x3f}} , - {{0xfd, 0x2f, 0xe0, 0x9b, 0x1e, 0x8c, 0xc5, 0x18, 0xa9, 0xca, 0xd4, 0x2b, 0x35, 0xb6, 0x95, 0x0a, 0x9f, 0x7e, 0xfb, 0xc4, 0xef, 0x88, 0x7b, 0x23, 0x43, 0xec, 0x2f, 0x0d, 0x0f, 0x7a, 0xfc, 0x5c}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0x8d, 0xd2, 0xda, 0xc7, 0x44, 0xd6, 0x7a, 0xdb, 0x26, 0x7d, 0x1d, 0xb8, 0xe1, 0xde, 0x9d, 0x7a, 0x7d, 0x17, 0x7e, 0x1c, 0x37, 0x04, 0x8d, 0x2d, 0x7c, 0x5e, 0x18, 0x38, 0x1e, 0xaf, 0xc7, 0x1b}} , - {{0x33, 0x48, 0x31, 0x00, 0x59, 0xf6, 0xf2, 0xca, 0x0f, 0x27, 0x1b, 0x63, 0x12, 0x7e, 0x02, 0x1d, 0x49, 0xc0, 0x5d, 0x79, 0x87, 0xef, 0x5e, 0x7a, 0x2f, 0x1f, 0x66, 0x55, 0xd8, 0x09, 0xd9, 0x61}}}, -{{{0x54, 0x83, 0x02, 0x18, 0x82, 0x93, 0x99, 0x07, 0xd0, 0xa7, 0xda, 0xd8, 0x75, 0x89, 0xfa, 0xf2, 0xd9, 0xa3, 0xb8, 0x6b, 0x5a, 0x35, 0x28, 0xd2, 0x6b, 0x59, 0xc2, 0xf8, 0x45, 0xe2, 0xbc, 0x06}} , - {{0x65, 0xc0, 0xa3, 0x88, 0x51, 0x95, 0xfc, 0x96, 0x94, 0x78, 0xe8, 0x0d, 0x8b, 0x41, 0xc9, 0xc2, 0x58, 0x48, 0x75, 0x10, 0x2f, 0xcd, 0x2a, 0xc9, 0xa0, 0x6d, 0x0f, 0xdd, 0x9c, 0x98, 0x26, 0x3d}}}, -{{{0x2f, 0x66, 0x29, 0x1b, 0x04, 0x89, 0xbd, 0x7e, 0xee, 0x6e, 0xdd, 0xb7, 0x0e, 0xef, 0xb0, 0x0c, 0xb4, 0xfc, 0x7f, 0xc2, 0xc9, 0x3a, 0x3c, 0x64, 0xef, 0x45, 0x44, 0xaf, 0x8a, 0x90, 0x65, 0x76}} , - {{0xa1, 0x4c, 0x70, 0x4b, 0x0e, 0xa0, 0x83, 0x70, 0x13, 0xa4, 0xaf, 0xb8, 0x38, 0x19, 0x22, 0x65, 0x09, 0xb4, 0x02, 0x4f, 0x06, 0xf8, 0x17, 0xce, 0x46, 0x45, 0xda, 0x50, 0x7c, 0x8a, 0xd1, 0x4e}}}, -{{{0xf7, 0xd4, 0x16, 0x6c, 0x4e, 0x95, 0x9d, 0x5d, 0x0f, 0x91, 0x2b, 0x52, 0xfe, 0x5c, 0x34, 0xe5, 0x30, 0xe6, 0xa4, 0x3b, 0xf3, 0xf3, 0x34, 0x08, 0xa9, 0x4a, 0xa0, 0xb5, 0x6e, 0xb3, 0x09, 0x0a}} , - {{0x26, 0xd9, 0x5e, 0xa3, 0x0f, 0xeb, 0xa2, 0xf3, 0x20, 0x3b, 0x37, 0xd4, 0xe4, 0x9e, 0xce, 0x06, 0x3d, 0x53, 0xed, 0xae, 0x2b, 0xeb, 0xb6, 0x24, 0x0a, 0x11, 0xa3, 0x0f, 0xd6, 0x7f, 0xa4, 0x3a}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0xdb, 0x9f, 0x2c, 0xfc, 0xd6, 0xb2, 0x1e, 0x2e, 0x52, 0x7a, 0x06, 0x87, 0x2d, 0x86, 0x72, 0x2b, 0x6d, 0x90, 0x77, 0x46, 0x43, 0xb5, 0x7a, 0xf8, 0x60, 0x7d, 0x91, 0x60, 0x5b, 0x9d, 0x9e, 0x07}} , - {{0x97, 0x87, 0xc7, 0x04, 0x1c, 0x38, 0x01, 0x39, 0x58, 0xc7, 0x85, 0xa3, 0xfc, 0x64, 0x00, 0x64, 0x25, 0xa2, 0xbf, 0x50, 0x94, 0xca, 0x26, 0x31, 0x45, 0x0a, 0x24, 0xd2, 0x51, 0x29, 0x51, 0x16}}}, -{{{0x4d, 0x4a, 0xd7, 0x98, 0x71, 0x57, 0xac, 0x7d, 0x8b, 0x37, 0xbd, 0x63, 0xff, 0x87, 0xb1, 0x49, 0x95, 0x20, 0x7c, 0xcf, 0x7c, 0x59, 0xc4, 0x91, 0x9c, 0xef, 0xd0, 0xdb, 0x60, 0x09, 0x9d, 0x46}} , - {{0xcb, 0x78, 0x94, 0x90, 0xe4, 0x45, 0xb3, 0xf6, 0xd9, 0xf6, 0x57, 0x74, 0xd5, 0xf8, 0x83, 0x4f, 0x39, 0xc9, 0xbd, 0x88, 0xc2, 0x57, 0x21, 0x1f, 0x24, 0x32, 0x68, 0xf8, 0xc7, 0x21, 0x5f, 0x0b}}}, -{{{0x2a, 0x36, 0x68, 0xfc, 0x5f, 0xb6, 0x4f, 0xa5, 0xe3, 0x9d, 0x24, 0x2f, 0xc0, 0x93, 0x61, 0xcf, 0xf8, 0x0a, 0xed, 0xe1, 0xdb, 0x27, 0xec, 0x0e, 0x14, 0x32, 0x5f, 0x8e, 0xa1, 0x62, 0x41, 0x16}} , - {{0x95, 0x21, 0x01, 0xce, 0x95, 0x5b, 0x0e, 0x57, 0xc7, 0xb9, 0x62, 0xb5, 0x28, 0xca, 0x11, 0xec, 0xb4, 0x46, 0x06, 0x73, 0x26, 0xff, 0xfb, 0x66, 0x7d, 0xee, 0x5f, 0xb2, 0x56, 0xfd, 0x2a, 0x08}}}, -{{{0x92, 0x67, 0x77, 0x56, 0xa1, 0xff, 0xc4, 0xc5, 0x95, 0xf0, 0xe3, 0x3a, 0x0a, 0xca, 0x94, 0x4d, 0x9e, 0x7e, 0x3d, 0xb9, 0x6e, 0xb6, 0xb0, 0xce, 0xa4, 0x30, 0x89, 0x99, 0xe9, 0xad, 0x11, 0x59}} , - {{0xf6, 0x48, 0x95, 0xa1, 0x6f, 0x5f, 0xb7, 0xa5, 0xbb, 0x30, 0x00, 0x1c, 0xd2, 0x8a, 0xd6, 0x25, 0x26, 0x1b, 0xb2, 0x0d, 0x37, 0x6a, 0x05, 0xf4, 0x9d, 0x3e, 0x17, 0x2a, 0x43, 0xd2, 0x3a, 0x06}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0x32, 0x99, 0x93, 0xd1, 0x9a, 0x72, 0xf3, 0xa9, 0x16, 0xbd, 0xb4, 0x4c, 0xdd, 0xf9, 0xd4, 0xb2, 0x64, 0x9a, 0xd3, 0x05, 0xe4, 0xa3, 0x73, 0x1c, 0xcb, 0x7e, 0x57, 0x67, 0xff, 0x04, 0xb3, 0x10}} , - {{0xb9, 0x4b, 0xa4, 0xad, 0xd0, 0x6d, 0x61, 0x23, 0xb4, 0xaf, 0x34, 0xa9, 0xaa, 0x65, 0xec, 0xd9, 0x69, 0xe3, 0x85, 0xcd, 0xcc, 0xe7, 0xb0, 0x9b, 0x41, 0xc1, 0x1c, 0xf9, 0xa0, 0xfa, 0xb7, 0x13}}}, -{{{0x04, 0xfd, 0x88, 0x3c, 0x0c, 0xd0, 0x09, 0x52, 0x51, 0x4f, 0x06, 0x19, 0xcc, 0xc3, 0xbb, 0xde, 0x80, 0xc5, 0x33, 0xbc, 0xf9, 0xf3, 0x17, 0x36, 0xdd, 0xc6, 0xde, 0xe8, 0x9b, 0x5d, 0x79, 0x1b}} , - {{0x65, 0x0a, 0xbe, 0x51, 0x57, 0xad, 0x50, 0x79, 0x08, 0x71, 0x9b, 0x07, 0x95, 0x8f, 0xfb, 0xae, 0x4b, 0x38, 0xba, 0xcf, 0x53, 0x2a, 0x86, 0x1e, 0xc0, 0x50, 0x5c, 0x67, 0x1b, 0xf6, 0x87, 0x6c}}}, -{{{0x4f, 0x00, 0xb2, 0x66, 0x55, 0xed, 0x4a, 0xed, 0x8d, 0xe1, 0x66, 0x18, 0xb2, 0x14, 0x74, 0x8d, 0xfd, 0x1a, 0x36, 0x0f, 0x26, 0x5c, 0x8b, 0x89, 0xf3, 0xab, 0xf2, 0xf3, 0x24, 0x67, 0xfd, 0x70}} , - {{0xfd, 0x4e, 0x2a, 0xc1, 0x3a, 0xca, 0x8f, 0x00, 0xd8, 0xec, 0x74, 0x67, 0xef, 0x61, 0xe0, 0x28, 0xd0, 0x96, 0xf4, 0x48, 0xde, 0x81, 0xe3, 0xef, 0xdc, 0xaa, 0x7d, 0xf3, 0xb6, 0x55, 0xa6, 0x65}}}, -{{{0xeb, 0xcb, 0xc5, 0x70, 0x91, 0x31, 0x10, 0x93, 0x0d, 0xc8, 0xd0, 0xef, 0x62, 0xe8, 0x6f, 0x82, 0xe3, 0x69, 0x3d, 0x91, 0x7f, 0x31, 0xe1, 0x26, 0x35, 0x3c, 0x4a, 0x2f, 0xab, 0xc4, 0x9a, 0x5e}} , - {{0xab, 0x1b, 0xb5, 0xe5, 0x2b, 0xc3, 0x0e, 0x29, 0xb0, 0xd0, 0x73, 0xe6, 0x4f, 0x64, 0xf2, 0xbc, 0xe4, 0xe4, 0xe1, 0x9a, 0x52, 0x33, 0x2f, 0xbd, 0xcc, 0x03, 0xee, 0x8a, 0xfa, 0x00, 0x5f, 0x50}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0xf6, 0xdb, 0x0d, 0x22, 0x3d, 0xb5, 0x14, 0x75, 0x31, 0xf0, 0x81, 0xe2, 0xb9, 0x37, 0xa2, 0xa9, 0x84, 0x11, 0x9a, 0x07, 0xb5, 0x53, 0x89, 0x78, 0xa9, 0x30, 0x27, 0xa1, 0xf1, 0x4e, 0x5c, 0x2e}} , - {{0x8b, 0x00, 0x54, 0xfb, 0x4d, 0xdc, 0xcb, 0x17, 0x35, 0x40, 0xff, 0xb7, 0x8c, 0xfe, 0x4a, 0xe4, 0x4e, 0x99, 0x4e, 0xa8, 0x74, 0x54, 0x5d, 0x5c, 0x96, 0xa3, 0x12, 0x55, 0x36, 0x31, 0x17, 0x5c}}}, -{{{0xce, 0x24, 0xef, 0x7b, 0x86, 0xf2, 0x0f, 0x77, 0xe8, 0x5c, 0x7d, 0x87, 0x38, 0x2d, 0xef, 0xaf, 0xf2, 0x8c, 0x72, 0x2e, 0xeb, 0xb6, 0x55, 0x4b, 0x6e, 0xf1, 0x4e, 0x8a, 0x0e, 0x9a, 0x6c, 0x4c}} , - {{0x25, 0xea, 0x86, 0xc2, 0xd1, 0x4f, 0xb7, 0x3e, 0xa8, 0x5c, 0x8d, 0x66, 0x81, 0x25, 0xed, 0xc5, 0x4c, 0x05, 0xb9, 0xd8, 0xd6, 0x70, 0xbe, 0x73, 0x82, 0xe8, 0xa1, 0xe5, 0x1e, 0x71, 0xd5, 0x26}}}, -{{{0x4e, 0x6d, 0xc3, 0xa7, 0x4f, 0x22, 0x45, 0x26, 0xa2, 0x7e, 0x16, 0xf7, 0xf7, 0x63, 0xdc, 0x86, 0x01, 0x2a, 0x71, 0x38, 0x5c, 0x33, 0xc3, 0xce, 0x30, 0xff, 0xf9, 0x2c, 0x91, 0x71, 0x8a, 0x72}} , - {{0x8c, 0x44, 0x09, 0x28, 0xd5, 0x23, 0xc9, 0x8f, 0xf3, 0x84, 0x45, 0xc6, 0x9a, 0x5e, 0xff, 0xd2, 0xc7, 0x57, 0x93, 0xa3, 0xc1, 0x69, 0xdd, 0x62, 0x0f, 0xda, 0x5c, 0x30, 0x59, 0x5d, 0xe9, 0x4c}}}, -{{{0x92, 0x7e, 0x50, 0x27, 0x72, 0xd7, 0x0c, 0xd6, 0x69, 0x96, 0x81, 0x35, 0x84, 0x94, 0x35, 0x8b, 0x6c, 0xaa, 0x62, 0x86, 0x6e, 0x1c, 0x15, 0xf3, 0x6c, 0xb3, 0xff, 0x65, 0x1b, 0xa2, 0x9b, 0x59}} , - {{0xe2, 0xa9, 0x65, 0x88, 0xc4, 0x50, 0xfa, 0xbb, 0x3b, 0x6e, 0x5f, 0x44, 0x01, 0xca, 0x97, 0xd4, 0xdd, 0xf6, 0xcd, 0x3f, 0x3f, 0xe5, 0x97, 0x67, 0x2b, 0x8c, 0x66, 0x0f, 0x35, 0x9b, 0xf5, 0x07}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0xf1, 0x59, 0x27, 0xd8, 0xdb, 0x5a, 0x11, 0x5e, 0x82, 0xf3, 0x38, 0xff, 0x1c, 0xed, 0xfe, 0x3f, 0x64, 0x54, 0x3f, 0x7f, 0xd1, 0x81, 0xed, 0xef, 0x65, 0xc5, 0xcb, 0xfd, 0xe1, 0x80, 0xcd, 0x11}} , - {{0xe0, 0xdb, 0x22, 0x28, 0xe6, 0xff, 0x61, 0x9d, 0x41, 0x14, 0x2d, 0x3b, 0x26, 0x22, 0xdf, 0xf1, 0x34, 0x81, 0xe9, 0x45, 0xee, 0x0f, 0x98, 0x8b, 0xa6, 0x3f, 0xef, 0xf7, 0x43, 0x19, 0xf1, 0x43}}}, -{{{0xee, 0xf3, 0x00, 0xa1, 0x50, 0xde, 0xc0, 0xb6, 0x01, 0xe3, 0x8c, 0x3c, 0x4d, 0x31, 0xd2, 0xb0, 0x58, 0xcd, 0xed, 0x10, 0x4a, 0x7a, 0xef, 0x80, 0xa9, 0x19, 0x32, 0xf3, 0xd8, 0x33, 0x8c, 0x06}} , - {{0xcb, 0x7d, 0x4f, 0xff, 0x30, 0xd8, 0x12, 0x3b, 0x39, 0x1c, 0x06, 0xf9, 0x4c, 0x34, 0x35, 0x71, 0xb5, 0x16, 0x94, 0x67, 0xdf, 0xee, 0x11, 0xde, 0xa4, 0x1d, 0x88, 0x93, 0x35, 0xa9, 0x32, 0x10}}}, -{{{0xe9, 0xc3, 0xbc, 0x7b, 0x5c, 0xfc, 0xb2, 0xf9, 0xc9, 0x2f, 0xe5, 0xba, 0x3a, 0x0b, 0xab, 0x64, 0x38, 0x6f, 0x5b, 0x4b, 0x93, 0xda, 0x64, 0xec, 0x4d, 0x3d, 0xa0, 0xf5, 0xbb, 0xba, 0x47, 0x48}} , - {{0x60, 0xbc, 0x45, 0x1f, 0x23, 0xa2, 0x3b, 0x70, 0x76, 0xe6, 0x97, 0x99, 0x4f, 0x77, 0x54, 0x67, 0x30, 0x9a, 0xe7, 0x66, 0xd6, 0xcd, 0x2e, 0x51, 0x24, 0x2c, 0x42, 0x4a, 0x11, 0xfe, 0x6f, 0x7e}}}, -{{{0x87, 0xc0, 0xb1, 0xf0, 0xa3, 0x6f, 0x0c, 0x93, 0xa9, 0x0a, 0x72, 0xef, 0x5c, 0xbe, 0x65, 0x35, 0xa7, 0x6a, 0x4e, 0x2c, 0xbf, 0x21, 0x23, 0xe8, 0x2f, 0x97, 0xc7, 0x3e, 0xc8, 0x17, 0xac, 0x1e}} , - {{0x7b, 0xef, 0x21, 0xe5, 0x40, 0xcc, 0x1e, 0xdc, 0xd6, 0xbd, 0x97, 0x7a, 0x7c, 0x75, 0x86, 0x7a, 0x25, 0x5a, 0x6e, 0x7c, 0xe5, 0x51, 0x3c, 0x1b, 0x5b, 0x82, 0x9a, 0x07, 0x60, 0xa1, 0x19, 0x04}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0x96, 0x88, 0xa6, 0xab, 0x8f, 0xe3, 0x3a, 0x49, 0xf8, 0xfe, 0x34, 0xe7, 0x6a, 0xb2, 0xfe, 0x40, 0x26, 0x74, 0x57, 0x4c, 0xf6, 0xd4, 0x99, 0xce, 0x5d, 0x7b, 0x2f, 0x67, 0xd6, 0x5a, 0xe4, 0x4e}} , - {{0x5c, 0x82, 0xb3, 0xbd, 0x55, 0x25, 0xf6, 0x6a, 0x93, 0xa4, 0x02, 0xc6, 0x7d, 0x5c, 0xb1, 0x2b, 0x5b, 0xff, 0xfb, 0x56, 0xf8, 0x01, 0x41, 0x90, 0xc6, 0xb6, 0xac, 0x4f, 0xfe, 0xa7, 0x41, 0x70}}}, -{{{0xdb, 0xfa, 0x9b, 0x2c, 0xd4, 0x23, 0x67, 0x2c, 0x8a, 0x63, 0x6c, 0x07, 0x26, 0x48, 0x4f, 0xc2, 0x03, 0xd2, 0x53, 0x20, 0x28, 0xed, 0x65, 0x71, 0x47, 0xa9, 0x16, 0x16, 0x12, 0xbc, 0x28, 0x33}} , - {{0x39, 0xc0, 0xfa, 0xfa, 0xcd, 0x33, 0x43, 0xc7, 0x97, 0x76, 0x9b, 0x93, 0x91, 0x72, 0xeb, 0xc5, 0x18, 0x67, 0x4c, 0x11, 0xf0, 0xf4, 0xe5, 0x73, 0xb2, 0x5c, 0x1b, 0xc2, 0x26, 0x3f, 0xbf, 0x2b}}}, -{{{0x86, 0xe6, 0x8c, 0x1d, 0xdf, 0xca, 0xfc, 0xd5, 0xf8, 0x3a, 0xc3, 0x44, 0x72, 0xe6, 0x78, 0x9d, 0x2b, 0x97, 0xf8, 0x28, 0x45, 0xb4, 0x20, 0xc9, 0x2a, 0x8c, 0x67, 0xaa, 0x11, 0xc5, 0x5b, 0x2f}} , - {{0x17, 0x0f, 0x86, 0x52, 0xd7, 0x9d, 0xc3, 0x44, 0x51, 0x76, 0x32, 0x65, 0xb4, 0x37, 0x81, 0x99, 0x46, 0x37, 0x62, 0xed, 0xcf, 0x64, 0x9d, 0x72, 0x40, 0x7a, 0x4c, 0x0b, 0x76, 0x2a, 0xfb, 0x56}}}, -{{{0x33, 0xa7, 0x90, 0x7c, 0xc3, 0x6f, 0x17, 0xa5, 0xa0, 0x67, 0x72, 0x17, 0xea, 0x7e, 0x63, 0x14, 0x83, 0xde, 0xc1, 0x71, 0x2d, 0x41, 0x32, 0x7a, 0xf3, 0xd1, 0x2b, 0xd8, 0x2a, 0xa6, 0x46, 0x36}} , - {{0xac, 0xcc, 0x6b, 0x7c, 0xf9, 0xb8, 0x8b, 0x08, 0x5c, 0xd0, 0x7d, 0x8f, 0x73, 0xea, 0x20, 0xda, 0x86, 0xca, 0x00, 0xc7, 0xad, 0x73, 0x4d, 0xe9, 0xe8, 0xa9, 0xda, 0x1f, 0x03, 0x06, 0xdd, 0x24}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0x9c, 0xb2, 0x61, 0x0a, 0x98, 0x2a, 0xa5, 0xd7, 0xee, 0xa9, 0xac, 0x65, 0xcb, 0x0a, 0x1e, 0xe2, 0xbe, 0xdc, 0x85, 0x59, 0x0f, 0x9c, 0xa6, 0x57, 0x34, 0xa5, 0x87, 0xeb, 0x7b, 0x1e, 0x0c, 0x3c}} , - {{0x2f, 0xbd, 0x84, 0x63, 0x0d, 0xb5, 0xa0, 0xf0, 0x4b, 0x9e, 0x93, 0xc6, 0x34, 0x9a, 0x34, 0xff, 0x73, 0x19, 0x2f, 0x6e, 0x54, 0x45, 0x2c, 0x92, 0x31, 0x76, 0x34, 0xf1, 0xb2, 0x26, 0xe8, 0x74}}}, -{{{0x0a, 0x67, 0x90, 0x6d, 0x0c, 0x4c, 0xcc, 0xc0, 0xe6, 0xbd, 0xa7, 0x5e, 0x55, 0x8c, 0xcd, 0x58, 0x9b, 0x11, 0xa2, 0xbb, 0x4b, 0xb1, 0x43, 0x04, 0x3c, 0x55, 0xed, 0x23, 0xfe, 0xcd, 0xb1, 0x53}} , - {{0x05, 0xfb, 0x75, 0xf5, 0x01, 0xaf, 0x38, 0x72, 0x58, 0xfc, 0x04, 0x29, 0x34, 0x7a, 0x67, 0xa2, 0x08, 0x50, 0x6e, 0xd0, 0x2b, 0x73, 0xd5, 0xb8, 0xe4, 0x30, 0x96, 0xad, 0x45, 0xdf, 0xa6, 0x5c}}}, -{{{0x0d, 0x88, 0x1a, 0x90, 0x7e, 0xdc, 0xd8, 0xfe, 0xc1, 0x2f, 0x5d, 0x67, 0xee, 0x67, 0x2f, 0xed, 0x6f, 0x55, 0x43, 0x5f, 0x87, 0x14, 0x35, 0x42, 0xd3, 0x75, 0xae, 0xd5, 0xd3, 0x85, 0x1a, 0x76}} , - {{0x87, 0xc8, 0xa0, 0x6e, 0xe1, 0xb0, 0xad, 0x6a, 0x4a, 0x34, 0x71, 0xed, 0x7c, 0xd6, 0x44, 0x03, 0x65, 0x4a, 0x5c, 0x5c, 0x04, 0xf5, 0x24, 0x3f, 0xb0, 0x16, 0x5e, 0x8c, 0xb2, 0xd2, 0xc5, 0x20}}}, -{{{0x98, 0x83, 0xc2, 0x37, 0xa0, 0x41, 0xa8, 0x48, 0x5c, 0x5f, 0xbf, 0xc8, 0xfa, 0x24, 0xe0, 0x59, 0x2c, 0xbd, 0xf6, 0x81, 0x7e, 0x88, 0xe6, 0xca, 0x04, 0xd8, 0x5d, 0x60, 0xbb, 0x74, 0xa7, 0x0b}} , - {{0x21, 0x13, 0x91, 0xbf, 0x77, 0x7a, 0x33, 0xbc, 0xe9, 0x07, 0x39, 0x0a, 0xdd, 0x7d, 0x06, 0x10, 0x9a, 0xee, 0x47, 0x73, 0x1b, 0x15, 0x5a, 0xfb, 0xcd, 0x4d, 0xd0, 0xd2, 0x3a, 0x01, 0xba, 0x54}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0x48, 0xd5, 0x39, 0x4a, 0x0b, 0x20, 0x6a, 0x43, 0xa0, 0x07, 0x82, 0x5e, 0x49, 0x7c, 0xc9, 0x47, 0xf1, 0x7c, 0x37, 0xb9, 0x23, 0xef, 0x6b, 0x46, 0x45, 0x8c, 0x45, 0x76, 0xdf, 0x14, 0x6b, 0x6e}} , - {{0x42, 0xc9, 0xca, 0x29, 0x4c, 0x76, 0x37, 0xda, 0x8a, 0x2d, 0x7c, 0x3a, 0x58, 0xf2, 0x03, 0xb4, 0xb5, 0xb9, 0x1a, 0x13, 0x2d, 0xde, 0x5f, 0x6b, 0x9d, 0xba, 0x52, 0xc9, 0x5d, 0xb3, 0xf3, 0x30}}}, -{{{0x4c, 0x6f, 0xfe, 0x6b, 0x0c, 0x62, 0xd7, 0x48, 0x71, 0xef, 0xb1, 0x85, 0x79, 0xc0, 0xed, 0x24, 0xb1, 0x08, 0x93, 0x76, 0x8e, 0xf7, 0x38, 0x8e, 0xeb, 0xfe, 0x80, 0x40, 0xaf, 0x90, 0x64, 0x49}} , - {{0x4a, 0x88, 0xda, 0xc1, 0x98, 0x44, 0x3c, 0x53, 0x4e, 0xdb, 0x4b, 0xb9, 0x12, 0x5f, 0xcd, 0x08, 0x04, 0xef, 0x75, 0xe7, 0xb1, 0x3a, 0xe5, 0x07, 0xfa, 0xca, 0x65, 0x7b, 0x72, 0x10, 0x64, 0x7f}}}, -{{{0x3d, 0x81, 0xf0, 0xeb, 0x16, 0xfd, 0x58, 0x33, 0x8d, 0x7c, 0x1a, 0xfb, 0x20, 0x2c, 0x8a, 0xee, 0x90, 0xbb, 0x33, 0x6d, 0x45, 0xe9, 0x8e, 0x99, 0x85, 0xe1, 0x08, 0x1f, 0xc5, 0xf1, 0xb5, 0x46}} , - {{0xe4, 0xe7, 0x43, 0x4b, 0xa0, 0x3f, 0x2b, 0x06, 0xba, 0x17, 0xae, 0x3d, 0xe6, 0xce, 0xbd, 0xb8, 0xed, 0x74, 0x11, 0x35, 0xec, 0x96, 0xfe, 0x31, 0xe3, 0x0e, 0x7a, 0x4e, 0xc9, 0x1d, 0xcb, 0x20}}}, -{{{0xe0, 0x67, 0xe9, 0x7b, 0xdb, 0x96, 0x5c, 0xb0, 0x32, 0xd0, 0x59, 0x31, 0x90, 0xdc, 0x92, 0x97, 0xac, 0x09, 0x38, 0x31, 0x0f, 0x7e, 0xd6, 0x5d, 0xd0, 0x06, 0xb6, 0x1f, 0xea, 0xf0, 0x5b, 0x07}} , - {{0x81, 0x9f, 0xc7, 0xde, 0x6b, 0x41, 0x22, 0x35, 0x14, 0x67, 0x77, 0x3e, 0x90, 0x81, 0xb0, 0xd9, 0x85, 0x4c, 0xca, 0x9b, 0x3f, 0x04, 0x59, 0xd6, 0xaa, 0x17, 0xc3, 0x88, 0x34, 0x37, 0xba, 0x43}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0x4c, 0xb6, 0x69, 0xc8, 0x81, 0x95, 0x94, 0x33, 0x92, 0x34, 0xe9, 0x3c, 0x84, 0x0d, 0x3d, 0x5a, 0x37, 0x9c, 0x22, 0xa0, 0xaa, 0x65, 0xce, 0xb4, 0xc2, 0x2d, 0x66, 0x67, 0x02, 0xff, 0x74, 0x10}} , - {{0x22, 0xb0, 0xd5, 0xe6, 0xc7, 0xef, 0xb1, 0xa7, 0x13, 0xda, 0x60, 0xb4, 0x80, 0xc1, 0x42, 0x7d, 0x10, 0x70, 0x97, 0x04, 0x4d, 0xda, 0x23, 0x89, 0xc2, 0x0e, 0x68, 0xcb, 0xde, 0xe0, 0x9b, 0x29}}}, -{{{0x33, 0xfe, 0x42, 0x2a, 0x36, 0x2b, 0x2e, 0x36, 0x64, 0x5c, 0x8b, 0xcc, 0x81, 0x6a, 0x15, 0x08, 0xa1, 0x27, 0xe8, 0x57, 0xe5, 0x78, 0x8e, 0xf2, 0x58, 0x19, 0x12, 0x42, 0xae, 0xc4, 0x63, 0x3e}} , - {{0x78, 0x96, 0x9c, 0xa7, 0xca, 0x80, 0xae, 0x02, 0x85, 0xb1, 0x7c, 0x04, 0x5c, 0xc1, 0x5b, 0x26, 0xc1, 0xba, 0xed, 0xa5, 0x59, 0x70, 0x85, 0x8c, 0x8c, 0xe8, 0x87, 0xac, 0x6a, 0x28, 0x99, 0x35}}}, -{{{0x9f, 0x04, 0x08, 0x28, 0xbe, 0x87, 0xda, 0x80, 0x28, 0x38, 0xde, 0x9f, 0xcd, 0xe4, 0xe3, 0x62, 0xfb, 0x2e, 0x46, 0x8d, 0x01, 0xb3, 0x06, 0x51, 0xd4, 0x19, 0x3b, 0x11, 0xfa, 0xe2, 0xad, 0x1e}} , - {{0xa0, 0x20, 0x99, 0x69, 0x0a, 0xae, 0xa3, 0x70, 0x4e, 0x64, 0x80, 0xb7, 0x85, 0x9c, 0x87, 0x54, 0x43, 0x43, 0x55, 0x80, 0x6d, 0x8d, 0x7c, 0xa9, 0x64, 0xca, 0x6c, 0x2e, 0x21, 0xd8, 0xc8, 0x6c}}}, -{{{0x91, 0x4a, 0x07, 0xad, 0x08, 0x75, 0xc1, 0x4f, 0xa4, 0xb2, 0xc3, 0x6f, 0x46, 0x3e, 0xb1, 0xce, 0x52, 0xab, 0x67, 0x09, 0x54, 0x48, 0x6b, 0x6c, 0xd7, 0x1d, 0x71, 0x76, 0xcb, 0xff, 0xdd, 0x31}} , - {{0x36, 0x88, 0xfa, 0xfd, 0xf0, 0x36, 0x6f, 0x07, 0x74, 0x88, 0x50, 0xd0, 0x95, 0x38, 0x4a, 0x48, 0x2e, 0x07, 0x64, 0x97, 0x11, 0x76, 0x01, 0x1a, 0x27, 0x4d, 0x8e, 0x25, 0x9a, 0x9b, 0x1c, 0x22}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0xbe, 0x57, 0xbd, 0x0e, 0x0f, 0xac, 0x5e, 0x76, 0xa3, 0x71, 0xad, 0x2b, 0x10, 0x45, 0x02, 0xec, 0x59, 0xd5, 0x5d, 0xa9, 0x44, 0xcc, 0x25, 0x4c, 0xb3, 0x3c, 0x5b, 0x69, 0x07, 0x55, 0x26, 0x6b}} , - {{0x30, 0x6b, 0xd4, 0xa7, 0x51, 0x29, 0xe3, 0xf9, 0x7a, 0x75, 0x2a, 0x82, 0x2f, 0xd6, 0x1d, 0x99, 0x2b, 0x80, 0xd5, 0x67, 0x1e, 0x15, 0x9d, 0xca, 0xfd, 0xeb, 0xac, 0x97, 0x35, 0x09, 0x7f, 0x3f}}}, -{{{0x35, 0x0d, 0x34, 0x0a, 0xb8, 0x67, 0x56, 0x29, 0x20, 0xf3, 0x19, 0x5f, 0xe2, 0x83, 0x42, 0x73, 0x53, 0xa8, 0xc5, 0x02, 0x19, 0x33, 0xb4, 0x64, 0xbd, 0xc3, 0x87, 0x8c, 0xd7, 0x76, 0xed, 0x25}} , - {{0x47, 0x39, 0x37, 0x76, 0x0d, 0x1d, 0x0c, 0xf5, 0x5a, 0x6d, 0x43, 0x88, 0x99, 0x15, 0xb4, 0x52, 0x0f, 0x2a, 0xb3, 0xb0, 0x3f, 0xa6, 0xb3, 0x26, 0xb3, 0xc7, 0x45, 0xf5, 0x92, 0x5f, 0x9b, 0x17}}}, -{{{0x9d, 0x23, 0xbd, 0x15, 0xfe, 0x52, 0x52, 0x15, 0x26, 0x79, 0x86, 0xba, 0x06, 0x56, 0x66, 0xbb, 0x8c, 0x2e, 0x10, 0x11, 0xd5, 0x4a, 0x18, 0x52, 0xda, 0x84, 0x44, 0xf0, 0x3e, 0xe9, 0x8c, 0x35}} , - {{0xad, 0xa0, 0x41, 0xec, 0xc8, 0x4d, 0xb9, 0xd2, 0x6e, 0x96, 0x4e, 0x5b, 0xc5, 0xc2, 0xa0, 0x1b, 0xcf, 0x0c, 0xbf, 0x17, 0x66, 0x57, 0xc1, 0x17, 0x90, 0x45, 0x71, 0xc2, 0xe1, 0x24, 0xeb, 0x27}}}, -{{{0x2c, 0xb9, 0x42, 0xa4, 0xaf, 0x3b, 0x42, 0x0e, 0xc2, 0x0f, 0xf2, 0xea, 0x83, 0xaf, 0x9a, 0x13, 0x17, 0xb0, 0xbd, 0x89, 0x17, 0xe3, 0x72, 0xcb, 0x0e, 0x76, 0x7e, 0x41, 0x63, 0x04, 0x88, 0x71}} , - {{0x75, 0x78, 0x38, 0x86, 0x57, 0xdd, 0x9f, 0xee, 0x54, 0x70, 0x65, 0xbf, 0xf1, 0x2c, 0xe0, 0x39, 0x0d, 0xe3, 0x89, 0xfd, 0x8e, 0x93, 0x4f, 0x43, 0xdc, 0xd5, 0x5b, 0xde, 0xf9, 0x98, 0xe5, 0x7b}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0xe7, 0x3b, 0x65, 0x11, 0xdf, 0xb2, 0xf2, 0x63, 0x94, 0x12, 0x6f, 0x5c, 0x9e, 0x77, 0xc1, 0xb6, 0xd8, 0xab, 0x58, 0x7a, 0x1d, 0x95, 0x73, 0xdd, 0xe7, 0xe3, 0x6f, 0xf2, 0x03, 0x1d, 0xdb, 0x76}} , - {{0xae, 0x06, 0x4e, 0x2c, 0x52, 0x1b, 0xbc, 0x5a, 0x5a, 0xa5, 0xbe, 0x27, 0xbd, 0xeb, 0xe1, 0x14, 0x17, 0x68, 0x26, 0x07, 0x03, 0xd1, 0x18, 0x0b, 0xdf, 0xf1, 0x06, 0x5c, 0xa6, 0x1b, 0xb9, 0x24}}}, -{{{0xc5, 0x66, 0x80, 0x13, 0x0e, 0x48, 0x8c, 0x87, 0x31, 0x84, 0xb4, 0x60, 0xed, 0xc5, 0xec, 0xb6, 0xc5, 0x05, 0x33, 0x5f, 0x2f, 0x7d, 0x40, 0xb6, 0x32, 0x1d, 0x38, 0x74, 0x1b, 0xf1, 0x09, 0x3d}} , - {{0xd4, 0x69, 0x82, 0xbc, 0x8d, 0xf8, 0x34, 0x36, 0x75, 0x55, 0x18, 0x55, 0x58, 0x3c, 0x79, 0xaf, 0x26, 0x80, 0xab, 0x9b, 0x95, 0x00, 0xf1, 0xcb, 0xda, 0xc1, 0x9f, 0xf6, 0x2f, 0xa2, 0xf4, 0x45}}}, -{{{0x17, 0xbe, 0xeb, 0x85, 0xed, 0x9e, 0xcd, 0x56, 0xf5, 0x17, 0x45, 0x42, 0xb4, 0x1f, 0x44, 0x4c, 0x05, 0x74, 0x15, 0x47, 0x00, 0xc6, 0x6a, 0x3d, 0x24, 0x09, 0x0d, 0x58, 0xb1, 0x42, 0xd7, 0x04}} , - {{0x8d, 0xbd, 0xa3, 0xc4, 0x06, 0x9b, 0x1f, 0x90, 0x58, 0x60, 0x74, 0xb2, 0x00, 0x3b, 0x3c, 0xd2, 0xda, 0x82, 0xbb, 0x10, 0x90, 0x69, 0x92, 0xa9, 0xb4, 0x30, 0x81, 0xe3, 0x7c, 0xa8, 0x89, 0x45}}}, -{{{0x3f, 0xdc, 0x05, 0xcb, 0x41, 0x3c, 0xc8, 0x23, 0x04, 0x2c, 0x38, 0x99, 0xe3, 0x68, 0x55, 0xf9, 0xd3, 0x32, 0xc7, 0xbf, 0xfa, 0xd4, 0x1b, 0x5d, 0xde, 0xdc, 0x10, 0x42, 0xc0, 0x42, 0xd9, 0x75}} , - {{0x2d, 0xab, 0x35, 0x4e, 0x87, 0xc4, 0x65, 0x97, 0x67, 0x24, 0xa4, 0x47, 0xad, 0x3f, 0x8e, 0xf3, 0xcb, 0x31, 0x17, 0x77, 0xc5, 0xe2, 0xd7, 0x8f, 0x3c, 0xc1, 0xcd, 0x56, 0x48, 0xc1, 0x6c, 0x69}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0x14, 0xae, 0x5f, 0x88, 0x7b, 0xa5, 0x90, 0xdf, 0x10, 0xb2, 0x8b, 0x5e, 0x24, 0x17, 0xc3, 0xa3, 0xd4, 0x0f, 0x92, 0x61, 0x1a, 0x19, 0x5a, 0xad, 0x76, 0xbd, 0xd8, 0x1c, 0xdd, 0xe0, 0x12, 0x6d}} , - {{0x8e, 0xbd, 0x70, 0x8f, 0x02, 0xa3, 0x24, 0x4d, 0x5a, 0x67, 0xc4, 0xda, 0xf7, 0x20, 0x0f, 0x81, 0x5b, 0x7a, 0x05, 0x24, 0x67, 0x83, 0x0b, 0x2a, 0x80, 0xe7, 0xfd, 0x74, 0x4b, 0x9e, 0x5c, 0x0d}}}, -{{{0x94, 0xd5, 0x5f, 0x1f, 0xa2, 0xfb, 0xeb, 0xe1, 0x07, 0x34, 0xf8, 0x20, 0xad, 0x81, 0x30, 0x06, 0x2d, 0xa1, 0x81, 0x95, 0x36, 0xcf, 0x11, 0x0b, 0xaf, 0xc1, 0x2b, 0x9a, 0x6c, 0x55, 0xc1, 0x16}} , - {{0x36, 0x4f, 0xf1, 0x5e, 0x74, 0x35, 0x13, 0x28, 0xd7, 0x11, 0xcf, 0xb8, 0xde, 0x93, 0xb3, 0x05, 0xb8, 0xb5, 0x73, 0xe9, 0xeb, 0xad, 0x19, 0x1e, 0x89, 0x0f, 0x8b, 0x15, 0xd5, 0x8c, 0xe3, 0x23}}}, -{{{0x33, 0x79, 0xe7, 0x18, 0xe6, 0x0f, 0x57, 0x93, 0x15, 0xa0, 0xa7, 0xaa, 0xc4, 0xbf, 0x4f, 0x30, 0x74, 0x95, 0x5e, 0x69, 0x4a, 0x5b, 0x45, 0xe4, 0x00, 0xeb, 0x23, 0x74, 0x4c, 0xdf, 0x6b, 0x45}} , - {{0x97, 0x29, 0x6c, 0xc4, 0x42, 0x0b, 0xdd, 0xc0, 0x29, 0x5c, 0x9b, 0x34, 0x97, 0xd0, 0xc7, 0x79, 0x80, 0x63, 0x74, 0xe4, 0x8e, 0x37, 0xb0, 0x2b, 0x7c, 0xe8, 0x68, 0x6c, 0xc3, 0x82, 0x97, 0x57}}}, -{{{0x22, 0xbe, 0x83, 0xb6, 0x4b, 0x80, 0x6b, 0x43, 0x24, 0x5e, 0xef, 0x99, 0x9b, 0xa8, 0xfc, 0x25, 0x8d, 0x3b, 0x03, 0x94, 0x2b, 0x3e, 0xe7, 0x95, 0x76, 0x9b, 0xcc, 0x15, 0xdb, 0x32, 0xe6, 0x66}} , - {{0x84, 0xf0, 0x4a, 0x13, 0xa6, 0xd6, 0xfa, 0x93, 0x46, 0x07, 0xf6, 0x7e, 0x5c, 0x6d, 0x5e, 0xf6, 0xa6, 0xe7, 0x48, 0xf0, 0x06, 0xea, 0xff, 0x90, 0xc1, 0xcc, 0x4c, 0x19, 0x9c, 0x3c, 0x4e, 0x53}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0x2a, 0x50, 0xe3, 0x07, 0x15, 0x59, 0xf2, 0x8b, 0x81, 0xf2, 0xf3, 0xd3, 0x6c, 0x99, 0x8c, 0x70, 0x67, 0xec, 0xcc, 0xee, 0x9e, 0x59, 0x45, 0x59, 0x7d, 0x47, 0x75, 0x69, 0xf5, 0x24, 0x93, 0x5d}} , - {{0x6a, 0x4f, 0x1b, 0xbe, 0x6b, 0x30, 0xcf, 0x75, 0x46, 0xe3, 0x7b, 0x9d, 0xfc, 0xcd, 0xd8, 0x5c, 0x1f, 0xb4, 0xc8, 0xe2, 0x24, 0xec, 0x1a, 0x28, 0x05, 0x32, 0x57, 0xfd, 0x3c, 0x5a, 0x98, 0x10}}}, -{{{0xa3, 0xdb, 0xf7, 0x30, 0xd8, 0xc2, 0x9a, 0xe1, 0xd3, 0xce, 0x22, 0xe5, 0x80, 0x1e, 0xd9, 0xe4, 0x1f, 0xab, 0xc0, 0x71, 0x1a, 0x86, 0x0e, 0x27, 0x99, 0x5b, 0xfa, 0x76, 0x99, 0xb0, 0x08, 0x3c}} , - {{0x2a, 0x93, 0xd2, 0x85, 0x1b, 0x6a, 0x5d, 0xa6, 0xee, 0xd1, 0xd1, 0x33, 0xbd, 0x6a, 0x36, 0x73, 0x37, 0x3a, 0x44, 0xb4, 0xec, 0xa9, 0x7a, 0xde, 0x83, 0x40, 0xd7, 0xdf, 0x28, 0xba, 0xa2, 0x30}}}, -{{{0xd3, 0xb5, 0x6d, 0x05, 0x3f, 0x9f, 0xf3, 0x15, 0x8d, 0x7c, 0xca, 0xc9, 0xfc, 0x8a, 0x7c, 0x94, 0xb0, 0x63, 0x36, 0x9b, 0x78, 0xd1, 0x91, 0x1f, 0x93, 0xd8, 0x57, 0x43, 0xde, 0x76, 0xa3, 0x43}} , - {{0x9b, 0x35, 0xe2, 0xa9, 0x3d, 0x32, 0x1e, 0xbb, 0x16, 0x28, 0x70, 0xe9, 0x45, 0x2f, 0x8f, 0x70, 0x7f, 0x08, 0x7e, 0x53, 0xc4, 0x7a, 0xbf, 0xf7, 0xe1, 0xa4, 0x6a, 0xd8, 0xac, 0x64, 0x1b, 0x11}}}, -{{{0xb2, 0xeb, 0x47, 0x46, 0x18, 0x3e, 0x1f, 0x99, 0x0c, 0xcc, 0xf1, 0x2c, 0xe0, 0xe7, 0x8f, 0xe0, 0x01, 0x7e, 0x65, 0xb8, 0x0c, 0xd0, 0xfb, 0xc8, 0xb9, 0x90, 0x98, 0x33, 0x61, 0x3b, 0xd8, 0x27}} , - {{0xa0, 0xbe, 0x72, 0x3a, 0x50, 0x4b, 0x74, 0xab, 0x01, 0xc8, 0x93, 0xc5, 0xe4, 0xc7, 0x08, 0x6c, 0xb4, 0xca, 0xee, 0xeb, 0x8e, 0xd7, 0x4e, 0x26, 0xc6, 0x1d, 0xe2, 0x71, 0xaf, 0x89, 0xa0, 0x2a}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0x98, 0x0b, 0xe4, 0xde, 0xdb, 0xa8, 0xfa, 0x82, 0x74, 0x06, 0x52, 0x6d, 0x08, 0x52, 0x8a, 0xff, 0x62, 0xc5, 0x6a, 0x44, 0x0f, 0x51, 0x8c, 0x1f, 0x6e, 0xb6, 0xc6, 0x2c, 0x81, 0xd3, 0x76, 0x46}} , - {{0xf4, 0x29, 0x74, 0x2e, 0x80, 0xa7, 0x1a, 0x8f, 0xf6, 0xbd, 0xd6, 0x8e, 0xbf, 0xc1, 0x95, 0x2a, 0xeb, 0xa0, 0x7f, 0x45, 0xa0, 0x50, 0x14, 0x05, 0xb1, 0x57, 0x4c, 0x74, 0xb7, 0xe2, 0x89, 0x7d}}}, -{{{0x07, 0xee, 0xa7, 0xad, 0xb7, 0x09, 0x0b, 0x49, 0x4e, 0xbf, 0xca, 0xe5, 0x21, 0xe6, 0xe6, 0xaf, 0xd5, 0x67, 0xf3, 0xce, 0x7e, 0x7c, 0x93, 0x7b, 0x5a, 0x10, 0x12, 0x0e, 0x6c, 0x06, 0x11, 0x75}} , - {{0xd5, 0xfc, 0x86, 0xa3, 0x3b, 0xa3, 0x3e, 0x0a, 0xfb, 0x0b, 0xf7, 0x36, 0xb1, 0x5b, 0xda, 0x70, 0xb7, 0x00, 0xa7, 0xda, 0x88, 0x8f, 0x84, 0xa8, 0xbc, 0x1c, 0x39, 0xb8, 0x65, 0xf3, 0x4d, 0x60}}}, -{{{0x96, 0x9d, 0x31, 0xf4, 0xa2, 0xbe, 0x81, 0xb9, 0xa5, 0x59, 0x9e, 0xba, 0x07, 0xbe, 0x74, 0x58, 0xd8, 0xeb, 0xc5, 0x9f, 0x3d, 0xd1, 0xf4, 0xae, 0xce, 0x53, 0xdf, 0x4f, 0xc7, 0x2a, 0x89, 0x4d}} , - {{0x29, 0xd8, 0xf2, 0xaa, 0xe9, 0x0e, 0xf7, 0x2e, 0x5f, 0x9d, 0x8a, 0x5b, 0x09, 0xed, 0xc9, 0x24, 0x22, 0xf4, 0x0f, 0x25, 0x8f, 0x1c, 0x84, 0x6e, 0x34, 0x14, 0x6c, 0xea, 0xb3, 0x86, 0x5d, 0x04}}}, -{{{0x07, 0x98, 0x61, 0xe8, 0x6a, 0xd2, 0x81, 0x49, 0x25, 0xd5, 0x5b, 0x18, 0xc7, 0x35, 0x52, 0x51, 0xa4, 0x46, 0xad, 0x18, 0x0d, 0xc9, 0x5f, 0x18, 0x91, 0x3b, 0xb4, 0xc0, 0x60, 0x59, 0x8d, 0x66}} , - {{0x03, 0x1b, 0x79, 0x53, 0x6e, 0x24, 0xae, 0x57, 0xd9, 0x58, 0x09, 0x85, 0x48, 0xa2, 0xd3, 0xb5, 0xe2, 0x4d, 0x11, 0x82, 0xe6, 0x86, 0x3c, 0xe9, 0xb1, 0x00, 0x19, 0xc2, 0x57, 0xf7, 0x66, 0x7a}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0x0f, 0xe3, 0x89, 0x03, 0xd7, 0x22, 0x95, 0x9f, 0xca, 0xb4, 0x8d, 0x9e, 0x6d, 0x97, 0xff, 0x8d, 0x21, 0x59, 0x07, 0xef, 0x03, 0x2d, 0x5e, 0xf8, 0x44, 0x46, 0xe7, 0x85, 0x80, 0xc5, 0x89, 0x50}} , - {{0x8b, 0xd8, 0x53, 0x86, 0x24, 0x86, 0x29, 0x52, 0x01, 0xfa, 0x20, 0xc3, 0x4e, 0x95, 0xcb, 0xad, 0x7b, 0x34, 0x94, 0x30, 0xb7, 0x7a, 0xfa, 0x96, 0x41, 0x60, 0x2b, 0xcb, 0x59, 0xb9, 0xca, 0x50}}}, -{{{0xc2, 0x5b, 0x9b, 0x78, 0x23, 0x1b, 0x3a, 0x88, 0x94, 0x5f, 0x0a, 0x9b, 0x98, 0x2b, 0x6e, 0x53, 0x11, 0xf6, 0xff, 0xc6, 0x7d, 0x42, 0xcc, 0x02, 0x80, 0x40, 0x0d, 0x1e, 0xfb, 0xaf, 0x61, 0x07}} , - {{0xb0, 0xe6, 0x2f, 0x81, 0x70, 0xa1, 0x2e, 0x39, 0x04, 0x7c, 0xc4, 0x2c, 0x87, 0x45, 0x4a, 0x5b, 0x69, 0x97, 0xac, 0x6d, 0x2c, 0x10, 0x42, 0x7c, 0x3b, 0x15, 0x70, 0x60, 0x0e, 0x11, 0x6d, 0x3a}}}, -{{{0x9b, 0x18, 0x80, 0x5e, 0xdb, 0x05, 0xbd, 0xc6, 0xb7, 0x3c, 0xc2, 0x40, 0x4d, 0x5d, 0xce, 0x97, 0x8a, 0x34, 0x15, 0xab, 0x28, 0x5d, 0x10, 0xf0, 0x37, 0x0c, 0xcc, 0x16, 0xfa, 0x1f, 0x33, 0x0d}} , - {{0x19, 0xf9, 0x35, 0xaa, 0x59, 0x1a, 0x0c, 0x5c, 0x06, 0xfc, 0x6a, 0x0b, 0x97, 0x53, 0x36, 0xfc, 0x2a, 0xa5, 0x5a, 0x9b, 0x30, 0xef, 0x23, 0xaf, 0x39, 0x5d, 0x9a, 0x6b, 0x75, 0x57, 0x48, 0x0b}}}, -{{{0x26, 0xdc, 0x76, 0x3b, 0xfc, 0xf9, 0x9c, 0x3f, 0x89, 0x0b, 0x62, 0x53, 0xaf, 0x83, 0x01, 0x2e, 0xbc, 0x6a, 0xc6, 0x03, 0x0d, 0x75, 0x2a, 0x0d, 0xe6, 0x94, 0x54, 0xcf, 0xb3, 0xe5, 0x96, 0x25}} , - {{0xfe, 0x82, 0xb1, 0x74, 0x31, 0x8a, 0xa7, 0x6f, 0x56, 0xbd, 0x8d, 0xf4, 0xe0, 0x94, 0x51, 0x59, 0xde, 0x2c, 0x5a, 0xf4, 0x84, 0x6b, 0x4a, 0x88, 0x93, 0xc0, 0x0c, 0x9a, 0xac, 0xa7, 0xa0, 0x68}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0x25, 0x0d, 0xd6, 0xc7, 0x23, 0x47, 0x10, 0xad, 0xc7, 0x08, 0x5c, 0x87, 0x87, 0x93, 0x98, 0x18, 0xb8, 0xd3, 0x9c, 0xac, 0x5a, 0x3d, 0xc5, 0x75, 0xf8, 0x49, 0x32, 0x14, 0xcc, 0x51, 0x96, 0x24}} , - {{0x65, 0x9c, 0x5d, 0xf0, 0x37, 0x04, 0xf0, 0x34, 0x69, 0x2a, 0xf0, 0xa5, 0x64, 0xca, 0xde, 0x2b, 0x5b, 0x15, 0x10, 0xd2, 0xab, 0x06, 0xdd, 0xc4, 0xb0, 0xb6, 0x5b, 0xc1, 0x17, 0xdf, 0x8f, 0x02}}}, -{{{0xbd, 0x59, 0x3d, 0xbf, 0x5c, 0x31, 0x44, 0x2c, 0x32, 0x94, 0x04, 0x60, 0x84, 0x0f, 0xad, 0x00, 0xb6, 0x8f, 0xc9, 0x1d, 0xcc, 0x5c, 0xa2, 0x49, 0x0e, 0x50, 0x91, 0x08, 0x9a, 0x43, 0x55, 0x05}} , - {{0x5d, 0x93, 0x55, 0xdf, 0x9b, 0x12, 0x19, 0xec, 0x93, 0x85, 0x42, 0x9e, 0x66, 0x0f, 0x9d, 0xaf, 0x99, 0xaf, 0x26, 0x89, 0xbc, 0x61, 0xfd, 0xff, 0xce, 0x4b, 0xf4, 0x33, 0x95, 0xc9, 0x35, 0x58}}}, -{{{0x12, 0x55, 0xf9, 0xda, 0xcb, 0x44, 0xa7, 0xdc, 0x57, 0xe2, 0xf9, 0x9a, 0xe6, 0x07, 0x23, 0x60, 0x54, 0xa7, 0x39, 0xa5, 0x9b, 0x84, 0x56, 0x6e, 0xaa, 0x8b, 0x8f, 0xb0, 0x2c, 0x87, 0xaf, 0x67}} , - {{0x00, 0xa9, 0x4c, 0xb2, 0x12, 0xf8, 0x32, 0xa8, 0x7a, 0x00, 0x4b, 0x49, 0x32, 0xba, 0x1f, 0x5d, 0x44, 0x8e, 0x44, 0x7a, 0xdc, 0x11, 0xfb, 0x39, 0x08, 0x57, 0x87, 0xa5, 0x12, 0x42, 0x93, 0x0e}}}, -{{{0x17, 0xb4, 0xae, 0x72, 0x59, 0xd0, 0xaa, 0xa8, 0x16, 0x8b, 0x63, 0x11, 0xb3, 0x43, 0x04, 0xda, 0x0c, 0xa8, 0xb7, 0x68, 0xdd, 0x4e, 0x54, 0xe7, 0xaf, 0x5d, 0x5d, 0x05, 0x76, 0x36, 0xec, 0x0d}} , - {{0x6d, 0x7c, 0x82, 0x32, 0x38, 0x55, 0x57, 0x74, 0x5b, 0x7d, 0xc3, 0xc4, 0xfb, 0x06, 0x29, 0xf0, 0x13, 0x55, 0x54, 0xc6, 0xa7, 0xdc, 0x4c, 0x9f, 0x98, 0x49, 0x20, 0xa8, 0xc3, 0x8d, 0xfa, 0x48}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0x87, 0x47, 0x9d, 0xe9, 0x25, 0xd5, 0xe3, 0x47, 0x78, 0xdf, 0x85, 0xa7, 0x85, 0x5e, 0x7a, 0x4c, 0x5f, 0x79, 0x1a, 0xf3, 0xa2, 0xb2, 0x28, 0xa0, 0x9c, 0xdd, 0x30, 0x40, 0xd4, 0x38, 0xbd, 0x28}} , - {{0xfc, 0xbb, 0xd5, 0x78, 0x6d, 0x1d, 0xd4, 0x99, 0xb4, 0xaa, 0x44, 0x44, 0x7a, 0x1b, 0xd8, 0xfe, 0xb4, 0x99, 0xb9, 0xcc, 0xe7, 0xc4, 0xd3, 0x3a, 0x73, 0x83, 0x41, 0x5c, 0x40, 0xd7, 0x2d, 0x55}}}, -{{{0x26, 0xe1, 0x7b, 0x5f, 0xe5, 0xdc, 0x3f, 0x7d, 0xa1, 0xa7, 0x26, 0x44, 0x22, 0x23, 0xc0, 0x8f, 0x7d, 0xf1, 0xb5, 0x11, 0x47, 0x7b, 0x19, 0xd4, 0x75, 0x6f, 0x1e, 0xa5, 0x27, 0xfe, 0xc8, 0x0e}} , - {{0xd3, 0x11, 0x3d, 0xab, 0xef, 0x2c, 0xed, 0xb1, 0x3d, 0x7c, 0x32, 0x81, 0x6b, 0xfe, 0xf8, 0x1c, 0x3c, 0x7b, 0xc0, 0x61, 0xdf, 0xb8, 0x75, 0x76, 0x7f, 0xaa, 0xd8, 0x93, 0xaf, 0x3d, 0xe8, 0x3d}}}, -{{{0xfd, 0x5b, 0x4e, 0x8d, 0xb6, 0x7e, 0x82, 0x9b, 0xef, 0xce, 0x04, 0x69, 0x51, 0x52, 0xff, 0xef, 0xa0, 0x52, 0xb5, 0x79, 0x17, 0x5e, 0x2f, 0xde, 0xd6, 0x3c, 0x2d, 0xa0, 0x43, 0xb4, 0x0b, 0x19}} , - {{0xc0, 0x61, 0x48, 0x48, 0x17, 0xf4, 0x9e, 0x18, 0x51, 0x2d, 0xea, 0x2f, 0xf2, 0xf2, 0xe0, 0xa3, 0x14, 0xb7, 0x8b, 0x3a, 0x30, 0xf5, 0x81, 0xc1, 0x5d, 0x71, 0x39, 0x62, 0x55, 0x1f, 0x60, 0x5a}}}, -{{{0xe5, 0x89, 0x8a, 0x76, 0x6c, 0xdb, 0x4d, 0x0a, 0x5b, 0x72, 0x9d, 0x59, 0x6e, 0x63, 0x63, 0x18, 0x7c, 0xe3, 0xfa, 0xe2, 0xdb, 0xa1, 0x8d, 0xf4, 0xa5, 0xd7, 0x16, 0xb2, 0xd0, 0xb3, 0x3f, 0x39}} , - {{0xce, 0x60, 0x09, 0x6c, 0xf5, 0x76, 0x17, 0x24, 0x80, 0x3a, 0x96, 0xc7, 0x94, 0x2e, 0xf7, 0x6b, 0xef, 0xb5, 0x05, 0x96, 0xef, 0xd3, 0x7b, 0x51, 0xda, 0x05, 0x44, 0x67, 0xbc, 0x07, 0x21, 0x4e}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0xe9, 0x73, 0x6f, 0x21, 0xb9, 0xde, 0x22, 0x7d, 0xeb, 0x97, 0x31, 0x10, 0xa3, 0xea, 0xe1, 0xc6, 0x37, 0xeb, 0x8f, 0x43, 0x58, 0xde, 0x41, 0x64, 0x0e, 0x3e, 0x07, 0x99, 0x3d, 0xf1, 0xdf, 0x1e}} , - {{0xf8, 0xad, 0x43, 0xc2, 0x17, 0x06, 0xe2, 0xe4, 0xa9, 0x86, 0xcd, 0x18, 0xd7, 0x78, 0xc8, 0x74, 0x66, 0xd2, 0x09, 0x18, 0xa5, 0xf1, 0xca, 0xa6, 0x62, 0x92, 0xc1, 0xcb, 0x00, 0xeb, 0x42, 0x2e}}}, -{{{0x7b, 0x34, 0x24, 0x4c, 0xcf, 0x38, 0xe5, 0x6c, 0x0a, 0x01, 0x2c, 0x22, 0x0b, 0x24, 0x38, 0xad, 0x24, 0x7e, 0x19, 0xf0, 0x6c, 0xf9, 0x31, 0xf4, 0x35, 0x11, 0xf6, 0x46, 0x33, 0x3a, 0x23, 0x59}} , - {{0x20, 0x0b, 0xa1, 0x08, 0x19, 0xad, 0x39, 0x54, 0xea, 0x3e, 0x23, 0x09, 0xb6, 0xe2, 0xd2, 0xbc, 0x4d, 0xfc, 0x9c, 0xf0, 0x13, 0x16, 0x22, 0x3f, 0xb9, 0xd2, 0x11, 0x86, 0x90, 0x55, 0xce, 0x3c}}}, -{{{0xc4, 0x0b, 0x4b, 0x62, 0x99, 0x37, 0x84, 0x3f, 0x74, 0xa2, 0xf9, 0xce, 0xe2, 0x0b, 0x0f, 0x2a, 0x3d, 0xa3, 0xe3, 0xdb, 0x5a, 0x9d, 0x93, 0xcc, 0xa5, 0xef, 0x82, 0x91, 0x1d, 0xe6, 0x6c, 0x68}} , - {{0xa3, 0x64, 0x17, 0x9b, 0x8b, 0xc8, 0x3a, 0x61, 0xe6, 0x9d, 0xc6, 0xed, 0x7b, 0x03, 0x52, 0x26, 0x9d, 0x3a, 0xb3, 0x13, 0xcc, 0x8a, 0xfd, 0x2c, 0x1a, 0x1d, 0xed, 0x13, 0xd0, 0x55, 0x57, 0x0e}}}, -{{{0x1a, 0xea, 0xbf, 0xfd, 0x4a, 0x3c, 0x8e, 0xec, 0x29, 0x7e, 0x77, 0x77, 0x12, 0x99, 0xd7, 0x84, 0xf9, 0x55, 0x7f, 0xf1, 0x8b, 0xb4, 0xd2, 0x95, 0xa3, 0x8d, 0xf0, 0x8a, 0xa7, 0xeb, 0x82, 0x4b}} , - {{0x2c, 0x28, 0xf4, 0x3a, 0xf6, 0xde, 0x0a, 0xe0, 0x41, 0x44, 0x23, 0xf8, 0x3f, 0x03, 0x64, 0x9f, 0xc3, 0x55, 0x4c, 0xc6, 0xc1, 0x94, 0x1c, 0x24, 0x5d, 0x5f, 0x92, 0x45, 0x96, 0x57, 0x37, 0x14}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0xc1, 0xcd, 0x90, 0x66, 0xb9, 0x76, 0xa0, 0x5b, 0xa5, 0x85, 0x75, 0x23, 0xf9, 0x89, 0xa5, 0x82, 0xb2, 0x6f, 0xb1, 0xeb, 0xc4, 0x69, 0x6f, 0x18, 0x5a, 0xed, 0x94, 0x3d, 0x9d, 0xd9, 0x2c, 0x1a}} , - {{0x35, 0xb0, 0xe6, 0x73, 0x06, 0xb7, 0x37, 0xe0, 0xf8, 0xb0, 0x22, 0xe8, 0xd2, 0xed, 0x0b, 0xef, 0xe6, 0xc6, 0x5a, 0x99, 0x9e, 0x1a, 0x9f, 0x04, 0x97, 0xe4, 0x4d, 0x0b, 0xbe, 0xba, 0x44, 0x40}}}, -{{{0xc1, 0x56, 0x96, 0x91, 0x5f, 0x1f, 0xbb, 0x54, 0x6f, 0x88, 0x89, 0x0a, 0xb2, 0xd6, 0x41, 0x42, 0x6a, 0x82, 0xee, 0x14, 0xaa, 0x76, 0x30, 0x65, 0x0f, 0x67, 0x39, 0xa6, 0x51, 0x7c, 0x49, 0x24}} , - {{0x35, 0xa3, 0x78, 0xd1, 0x11, 0x0f, 0x75, 0xd3, 0x70, 0x46, 0xdb, 0x20, 0x51, 0xcb, 0x92, 0x80, 0x54, 0x10, 0x74, 0x36, 0x86, 0xa9, 0xd7, 0xa3, 0x08, 0x78, 0xf1, 0x01, 0x29, 0xf8, 0x80, 0x3b}}}, -{{{0xdb, 0xa7, 0x9d, 0x9d, 0xbf, 0xa0, 0xcc, 0xed, 0x53, 0xa2, 0xa2, 0x19, 0x39, 0x48, 0x83, 0x19, 0x37, 0x58, 0xd1, 0x04, 0x28, 0x40, 0xf7, 0x8a, 0xc2, 0x08, 0xb7, 0xa5, 0x42, 0xcf, 0x53, 0x4c}} , - {{0xa7, 0xbb, 0xf6, 0x8e, 0xad, 0xdd, 0xf7, 0x90, 0xdd, 0x5f, 0x93, 0x89, 0xae, 0x04, 0x37, 0xe6, 0x9a, 0xb7, 0xe8, 0xc0, 0xdf, 0x16, 0x2a, 0xbf, 0xc4, 0x3a, 0x3c, 0x41, 0xd5, 0x89, 0x72, 0x5a}}}, -{{{0x1f, 0x96, 0xff, 0x34, 0x2c, 0x13, 0x21, 0xcb, 0x0a, 0x89, 0x85, 0xbe, 0xb3, 0x70, 0x9e, 0x1e, 0xde, 0x97, 0xaf, 0x96, 0x30, 0xf7, 0x48, 0x89, 0x40, 0x8d, 0x07, 0xf1, 0x25, 0xf0, 0x30, 0x58}} , - {{0x1e, 0xd4, 0x93, 0x57, 0xe2, 0x17, 0xe7, 0x9d, 0xab, 0x3c, 0x55, 0x03, 0x82, 0x2f, 0x2b, 0xdb, 0x56, 0x1e, 0x30, 0x2e, 0x24, 0x47, 0x6e, 0xe6, 0xff, 0x33, 0x24, 0x2c, 0x75, 0x51, 0xd4, 0x67}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0x2b, 0x06, 0xd9, 0xa1, 0x5d, 0xe1, 0xf4, 0xd1, 0x1e, 0x3c, 0x9a, 0xc6, 0x29, 0x2b, 0x13, 0x13, 0x78, 0xc0, 0xd8, 0x16, 0x17, 0x2d, 0x9e, 0xa9, 0xc9, 0x79, 0x57, 0xab, 0x24, 0x91, 0x92, 0x19}} , - {{0x69, 0xfb, 0xa1, 0x9c, 0xa6, 0x75, 0x49, 0x7d, 0x60, 0x73, 0x40, 0x42, 0xc4, 0x13, 0x0a, 0x95, 0x79, 0x1e, 0x04, 0x83, 0x94, 0x99, 0x9b, 0x1e, 0x0c, 0xe8, 0x1f, 0x54, 0xef, 0xcb, 0xc0, 0x52}}}, -{{{0x14, 0x89, 0x73, 0xa1, 0x37, 0x87, 0x6a, 0x7a, 0xcf, 0x1d, 0xd9, 0x2e, 0x1a, 0x67, 0xed, 0x74, 0xc0, 0xf0, 0x9c, 0x33, 0xdd, 0xdf, 0x08, 0xbf, 0x7b, 0xd1, 0x66, 0xda, 0xe6, 0xc9, 0x49, 0x08}} , - {{0xe9, 0xdd, 0x5e, 0x55, 0xb0, 0x0a, 0xde, 0x21, 0x4c, 0x5a, 0x2e, 0xd4, 0x80, 0x3a, 0x57, 0x92, 0x7a, 0xf1, 0xc4, 0x2c, 0x40, 0xaf, 0x2f, 0xc9, 0x92, 0x03, 0xe5, 0x5a, 0xbc, 0xdc, 0xf4, 0x09}}}, -{{{0xf3, 0xe1, 0x2b, 0x7c, 0x05, 0x86, 0x80, 0x93, 0x4a, 0xad, 0xb4, 0x8f, 0x7e, 0x99, 0x0c, 0xfd, 0xcd, 0xef, 0xd1, 0xff, 0x2c, 0x69, 0x34, 0x13, 0x41, 0x64, 0xcf, 0x3b, 0xd0, 0x90, 0x09, 0x1e}} , - {{0x9d, 0x45, 0xd6, 0x80, 0xe6, 0x45, 0xaa, 0xf4, 0x15, 0xaa, 0x5c, 0x34, 0x87, 0x99, 0xa2, 0x8c, 0x26, 0x84, 0x62, 0x7d, 0xb6, 0x29, 0xc0, 0x52, 0xea, 0xf5, 0x81, 0x18, 0x0f, 0x35, 0xa9, 0x0e}}}, -{{{0xe7, 0x20, 0x72, 0x7c, 0x6d, 0x94, 0x5f, 0x52, 0x44, 0x54, 0xe3, 0xf1, 0xb2, 0xb0, 0x36, 0x46, 0x0f, 0xae, 0x92, 0xe8, 0x70, 0x9d, 0x6e, 0x79, 0xb1, 0xad, 0x37, 0xa9, 0x5f, 0xc0, 0xde, 0x03}} , - {{0x15, 0x55, 0x37, 0xc6, 0x1c, 0x27, 0x1c, 0x6d, 0x14, 0x4f, 0xca, 0xa4, 0xc4, 0x88, 0x25, 0x46, 0x39, 0xfc, 0x5a, 0xe5, 0xfe, 0x29, 0x11, 0x69, 0xf5, 0x72, 0x84, 0x4d, 0x78, 0x9f, 0x94, 0x15}}}, -{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, - {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, -{{{0xec, 0xd3, 0xff, 0x57, 0x0b, 0xb0, 0xb2, 0xdc, 0xf8, 0x4f, 0xe2, 0x12, 0xd5, 0x36, 0xbe, 0x6b, 0x09, 0x43, 0x6d, 0xa3, 0x4d, 0x90, 0x2d, 0xb8, 0x74, 0xe8, 0x71, 0x45, 0x19, 0x8b, 0x0c, 0x6a}} , - {{0xb8, 0x42, 0x1c, 0x03, 0xad, 0x2c, 0x03, 0x8e, 0xac, 0xd7, 0x98, 0x29, 0x13, 0xc6, 0x02, 0x29, 0xb5, 0xd4, 0xe7, 0xcf, 0xcc, 0x8b, 0x83, 0xec, 0x35, 0xc7, 0x9c, 0x74, 0xb7, 0xad, 0x85, 0x5f}}}, -{{{0x78, 0x84, 0xe1, 0x56, 0x45, 0x69, 0x68, 0x5a, 0x4f, 0xb8, 0xb1, 0x29, 0xff, 0x33, 0x03, 0x31, 0xb7, 0xcb, 0x96, 0x25, 0xe6, 0xe6, 0x41, 0x98, 0x1a, 0xbb, 0x03, 0x56, 0xf2, 0xb2, 0x91, 0x34}} , - {{0x2c, 0x6c, 0xf7, 0x66, 0xa4, 0x62, 0x6b, 0x39, 0xb3, 0xba, 0x65, 0xd3, 0x1c, 0xf8, 0x11, 0xaa, 0xbe, 0xdc, 0x80, 0x59, 0x87, 0xf5, 0x7b, 0xe5, 0xe3, 0xb3, 0x3e, 0x39, 0xda, 0xbe, 0x88, 0x09}}}, -{{{0x8b, 0xf1, 0xa0, 0xf5, 0xdc, 0x29, 0xb4, 0xe2, 0x07, 0xc6, 0x7a, 0x00, 0xd0, 0x89, 0x17, 0x51, 0xd4, 0xbb, 0xd4, 0x22, 0xea, 0x7e, 0x7d, 0x7c, 0x24, 0xea, 0xf2, 0xe8, 0x22, 0x12, 0x95, 0x06}} , - {{0xda, 0x7c, 0xa4, 0x0c, 0xf4, 0xba, 0x6e, 0xe1, 0x89, 0xb5, 0x59, 0xca, 0xf1, 0xc0, 0x29, 0x36, 0x09, 0x44, 0xe2, 0x7f, 0xd1, 0x63, 0x15, 0x99, 0xea, 0x25, 0xcf, 0x0c, 0x9d, 0xc0, 0x44, 0x6f}}}, -{{{0x1d, 0x86, 0x4e, 0xcf, 0xf7, 0x37, 0x10, 0x25, 0x8f, 0x12, 0xfb, 0x19, 0xfb, 0xe0, 0xed, 0x10, 0xc8, 0xe2, 0xf5, 0x75, 0xb1, 0x33, 0xc0, 0x96, 0x0d, 0xfb, 0x15, 0x6c, 0x0d, 0x07, 0x5f, 0x05}} , - {{0x69, 0x3e, 0x47, 0x97, 0x2c, 0xaf, 0x52, 0x7c, 0x78, 0x83, 0xad, 0x1b, 0x39, 0x82, 0x2f, 0x02, 0x6f, 0x47, 0xdb, 0x2a, 0xb0, 0xe1, 0x91, 0x99, 0x55, 0xb8, 0x99, 0x3a, 0xa0, 0x44, 0x11, 0x51}}} -}; - -static inline void p1p1_to_p2(ge25519_p2 *r, const ge25519_p1p1 *p) -{ - fe25519_mul(&r->x, &p->x, &p->t); - fe25519_mul(&r->y, &p->y, &p->z); - fe25519_mul(&r->z, &p->z, &p->t); -} - -static inline void p1p1_to_p2_2(ge25519_p3 *r, const ge25519_p1p1 *p) -{ - fe25519_mul(&r->x, &p->x, &p->t); - fe25519_mul(&r->y, &p->y, &p->z); - fe25519_mul(&r->z, &p->z, &p->t); -} - -static inline void p1p1_to_p3(ge25519_p3 *r, const ge25519_p1p1 *p) -{ - p1p1_to_p2_2(r, p); - fe25519_mul(&r->t, &p->x, &p->y); -} - -static inline void ge25519_mixadd2(ge25519_p3 *r, const ge25519_aff *q) -{ - fe25519 a,b,t1,t2,c,d,e,f,g,h,qt; - fe25519_mul(&qt, &q->x, &q->y); - fe25519_sub(&a, &r->y, &r->x); /* A = (Y1-X1)*(Y2-X2) */ - fe25519_add(&b, &r->y, &r->x); /* B = (Y1+X1)*(Y2+X2) */ - fe25519_sub(&t1, &q->y, &q->x); - fe25519_add(&t2, &q->y, &q->x); - fe25519_mul(&a, &a, &t1); - fe25519_mul(&b, &b, &t2); - fe25519_sub(&e, &b, &a); /* E = B-A */ - fe25519_add(&h, &b, &a); /* H = B+A */ - fe25519_mul(&c, &r->t, &qt); /* C = T1*k*T2 */ - fe25519_mul(&c, &c, &ge25519_ec2d); - fe25519_add(&d, &r->z, &r->z); /* D = Z1*2 */ - fe25519_sub(&f, &d, &c); /* F = D-C */ - fe25519_add(&g, &d, &c); /* G = D+C */ - fe25519_mul(&r->x, &e, &f); - fe25519_mul(&r->y, &h, &g); - fe25519_mul(&r->z, &g, &f); - fe25519_mul(&r->t, &e, &h); -} - -static inline void add_p1p1(ge25519_p1p1 *r, const ge25519_p3 *p, const ge25519_p3 *q) -{ - fe25519 a, b, c, d, t; - - fe25519_sub(&a, &p->y, &p->x); /* A = (Y1-X1)*(Y2-X2) */ - fe25519_sub(&t, &q->y, &q->x); - fe25519_mul(&a, &a, &t); - fe25519_add(&b, &p->x, &p->y); /* B = (Y1+X1)*(Y2+X2) */ - fe25519_add(&t, &q->x, &q->y); - fe25519_mul(&b, &b, &t); - fe25519_mul(&c, &p->t, &q->t); /* C = T1*k*T2 */ - fe25519_mul(&c, &c, &ge25519_ec2d); - fe25519_mul(&d, &p->z, &q->z); /* D = Z1*2*Z2 */ - fe25519_add(&d, &d, &d); - fe25519_sub(&r->x, &b, &a); /* E = B-A */ - fe25519_sub(&r->t, &d, &c); /* F = D-C */ - fe25519_add(&r->z, &d, &c); /* G = D+C */ - fe25519_add(&r->y, &b, &a); /* H = B+A */ -} - -/* See http://www.hyperelliptic.org/EFD/g1p/auto-twisted-extended-1.html#doubling-dbl-2008-hwcd */ -static inline void dbl_p1p1(ge25519_p1p1 *r, const ge25519_p2 *p) -{ - fe25519 a,b,c,d; - fe25519_square(&a, &p->x); - fe25519_square(&b, &p->y); - fe25519_square(&c, &p->z); - fe25519_add(&c, &c, &c); - fe25519_neg(&d, &a); - - fe25519_add(&r->x, &p->x, &p->y); - fe25519_square(&r->x, &r->x); - fe25519_sub(&r->x, &r->x, &a); - fe25519_sub(&r->x, &r->x, &b); - fe25519_add(&r->z, &d, &b); - fe25519_sub(&r->t, &r->z, &c); - fe25519_sub(&r->y, &d, &b); -} - -/* Constant-time version of: if(b) r = p */ -static inline void cmov_aff(ge25519_aff *r, const ge25519_aff *p, unsigned char b) -{ - fe25519_cmov(&r->x, &p->x, b); - fe25519_cmov(&r->y, &p->y, b); -} - -static inline unsigned char equal(signed char b,signed char c) -{ - unsigned char ub = b; - unsigned char uc = c; - unsigned char x = ub ^ uc; /* 0: yes; 1..255: no */ - crypto_uint32 y = x; /* 0: yes; 1..255: no */ - y -= 1; /* 4294967295: yes; 0..254: no */ - y >>= 31; /* 1: yes; 0: no */ - return (unsigned char)y; -} - -static inline unsigned char negative(signed char b) -{ - unsigned long long x = b; /* 18446744073709551361..18446744073709551615: yes; 0..255: no */ - x >>= 63; /* 1: yes; 0: no */ - return (unsigned char)x; -} - -static inline void choose_t(ge25519_aff *t, unsigned long long pos, signed char b) -{ - /* constant time */ - fe25519 v; - *t = ge25519_base_multiples_affine[5*pos+0]; - cmov_aff(t, &ge25519_base_multiples_affine[5*pos+1],equal(b,1) | equal(b,-1)); - cmov_aff(t, &ge25519_base_multiples_affine[5*pos+2],equal(b,2) | equal(b,-2)); - cmov_aff(t, &ge25519_base_multiples_affine[5*pos+3],equal(b,3) | equal(b,-3)); - cmov_aff(t, &ge25519_base_multiples_affine[5*pos+4],equal(b,-4)); - fe25519_neg(&v, &t->x); - fe25519_cmov(&t->x, &v, negative(b)); -} - -static inline void setneutral(ge25519 *r) -{ - fe25519_setzero(&r->x); - fe25519_setone(&r->y); - fe25519_setone(&r->z); - fe25519_setzero(&r->t); -} - -/* return 0 on success, -1 otherwise */ -static inline int ge25519_unpackneg_vartime(ge25519_p3 *r, const unsigned char p[32]) -{ - unsigned char par; - fe25519 t, chk, num, den, den2, den4, den6; - fe25519_setone(&r->z); - par = p[31] >> 7; - fe25519_unpack(&r->y, p); - fe25519_square(&num, &r->y); /* x = y^2 */ - fe25519_mul(&den, &num, &ge25519_ecd); /* den = dy^2 */ - fe25519_sub(&num, &num, &r->z); /* x = y^2-1 */ - fe25519_add(&den, &r->z, &den); /* den = dy^2+1 */ - - /* Computation of sqrt(num/den) */ - /* 1.: computation of num^((p-5)/8)*den^((7p-35)/8) = (num*den^7)^((p-5)/8) */ - fe25519_square(&den2, &den); - fe25519_square(&den4, &den2); - fe25519_mul(&den6, &den4, &den2); - fe25519_mul(&t, &den6, &num); - fe25519_mul(&t, &t, &den); - - fe25519_pow2523(&t, &t); - /* 2. computation of r->x = t * num * den^3 */ - fe25519_mul(&t, &t, &num); - fe25519_mul(&t, &t, &den); - fe25519_mul(&t, &t, &den); - fe25519_mul(&r->x, &t, &den); - - /* 3. Check whether sqrt computation gave correct result, multiply by sqrt(-1) if not: */ - fe25519_square(&chk, &r->x); - fe25519_mul(&chk, &chk, &den); - if (!fe25519_iseq_vartime(&chk, &num)) { - fe25519_mul(&r->x, &r->x, &ge25519_sqrtm1); - } - - /* 4. Now we have one of the two square roots, except if input was not a square */ - fe25519_square(&chk, &r->x); - fe25519_mul(&chk, &chk, &den); - if (!fe25519_iseq_vartime(&chk, &num)) { - return -1; - } - - /* 5. Choose the desired square root according to parity: */ - if(fe25519_getparity(&r->x) != (1-par)) { - fe25519_neg(&r->x, &r->x); - } - - fe25519_mul(&r->t, &r->x, &r->y); - return 0; -} - -static inline void ge25519_pack(unsigned char r[32], const ge25519_p3 *p) -{ - fe25519 tx, ty, zi; - fe25519_invert(&zi, &p->z); - fe25519_mul(&tx, &p->x, &zi); - fe25519_mul(&ty, &p->y, &zi); - fe25519_pack(r, &ty); - r[31] ^= fe25519_getparity(&tx) << 7; -} - -/* computes [s1]p1 + [s2]p2 */ -static inline void ge25519_double_scalarmult_vartime(ge25519_p3 *r, const ge25519_p3 *p1, const sc25519 *s1, const ge25519_p3 *p2, const sc25519 *s2) -{ - ge25519_p1p1 tp1p1; - ge25519_p3 pre[16]; - char *pre5 = (char *)(&(pre[5])); // eliminate type punning warning - unsigned char b[127]; - int i; - - /* precomputation s2 s1 */ - setneutral(pre); /* 00 00 */ - pre[1] = *p1; /* 00 01 */ - dbl_p1p1(&tp1p1,(ge25519_p2 *)p1); p1p1_to_p3( &pre[2], &tp1p1); /* 00 10 */ - add_p1p1(&tp1p1,&pre[1], &pre[2]); p1p1_to_p3( &pre[3], &tp1p1); /* 00 11 */ - pre[4] = *p2; /* 01 00 */ - add_p1p1(&tp1p1,&pre[1], &pre[4]); p1p1_to_p3( &pre[5], &tp1p1); /* 01 01 */ - add_p1p1(&tp1p1,&pre[2], &pre[4]); p1p1_to_p3( &pre[6], &tp1p1); /* 01 10 */ - add_p1p1(&tp1p1,&pre[3], &pre[4]); p1p1_to_p3( &pre[7], &tp1p1); /* 01 11 */ - dbl_p1p1(&tp1p1,(ge25519_p2 *)p2); p1p1_to_p3( &pre[8], &tp1p1); /* 10 00 */ - add_p1p1(&tp1p1,&pre[1], &pre[8]); p1p1_to_p3( &pre[9], &tp1p1); /* 10 01 */ - dbl_p1p1(&tp1p1,(ge25519_p2 *)pre5); p1p1_to_p3(&pre[10], &tp1p1); /* 10 10 */ - add_p1p1(&tp1p1,&pre[3], &pre[8]); p1p1_to_p3(&pre[11], &tp1p1); /* 10 11 */ - add_p1p1(&tp1p1,&pre[4], &pre[8]); p1p1_to_p3(&pre[12], &tp1p1); /* 11 00 */ - add_p1p1(&tp1p1,&pre[1],&pre[12]); p1p1_to_p3(&pre[13], &tp1p1); /* 11 01 */ - add_p1p1(&tp1p1,&pre[2],&pre[12]); p1p1_to_p3(&pre[14], &tp1p1); /* 11 10 */ - add_p1p1(&tp1p1,&pre[3],&pre[12]); p1p1_to_p3(&pre[15], &tp1p1); /* 11 11 */ - - sc25519_2interleave2(b,s1,s2); - - /* scalar multiplication */ - *r = pre[b[126]]; - for(i=125;i>=0;i--) { - dbl_p1p1(&tp1p1, (ge25519_p2 *)r); - p1p1_to_p2((ge25519_p2 *) r, &tp1p1); - dbl_p1p1(&tp1p1, (ge25519_p2 *)r); - if(b[i]!=0) { - p1p1_to_p3(r, &tp1p1); - add_p1p1(&tp1p1, r, &pre[b[i]]); - } - if (i != 0) { - p1p1_to_p2((ge25519_p2 *)r, &tp1p1); - } else { - p1p1_to_p3(r, &tp1p1); - } - } -} - -static inline void ge25519_scalarmult_base(ge25519_p3 *r, const sc25519 *s) -{ - signed char b[85]; - int i; - ge25519_aff t; - sc25519_window3(b,s); - - choose_t((ge25519_aff *)r, 0, b[0]); - fe25519_setone(&r->z); - fe25519_mul(&r->t, &r->x, &r->y); - for(i=1;i<85;i++) { - choose_t(&t, (unsigned long long) i, b[i]); - ge25519_mixadd2(r, &t); - } -} - -static inline void get_hram(unsigned char *hram, const unsigned char *sm, const unsigned char *pk, unsigned char *playground, unsigned long long smlen) -{ - unsigned long long i; - - for (i = 0;i < 32;++i) { - playground[i] = sm[i]; - } - for (i = 32;i < 64;++i) { - playground[i] = pk[i-32]; - } - for (i = 64;i < smlen;++i) { - playground[i] = sm[i]; - } - - ZeroTier::SHA512(hram,playground,(unsigned int)smlen); -} - -////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////// - -} // anonymous namespace - -#ifdef ZT_USE_FAST_X64_ED25519 -extern "C" void ed25519_amd64_asm_sign(const unsigned char *sk,const unsigned char *pk,const unsigned char *digest,unsigned char *sig); -#endif - -namespace ZeroTier { - -void C25519::agree(const C25519::Private &mine,const C25519::Public &their,void *keybuf,unsigned int keylen) -{ - unsigned char rawkey[32]; - unsigned char digest[64]; - - crypto_scalarmult(rawkey,mine.data,their.data); - SHA512(digest,rawkey,32); - for(unsigned int i=0,k=0;i - static inline Pair generateSatisfying(F cond) - { - Pair kp; - void *const priv = (void *)kp.priv.data; - Utils::getSecureRandom(priv,ZT_C25519_PRIVATE_KEY_LEN); - _calcPubED(kp); // do Ed25519 key -- bytes 32-63 of pub and priv - do { - ++(((uint64_t *)priv)[1]); - --(((uint64_t *)priv)[2]); - _calcPubDH(kp); // keep regenerating bytes 0-31 until satisfied - } while (!cond(kp)); - return kp; - } - - /** - * Perform C25519 ECC key agreement - * - * Actual key bytes are generated from one or more SHA-512 digests of - * the raw result of key agreement. - * - * @param mine My private key - * @param their Their public key - * @param keybuf Buffer to fill - * @param keylen Number of key bytes to generate - */ - static void agree(const Private &mine,const Public &their,void *keybuf,unsigned int keylen); - static inline void agree(const Pair &mine,const Public &their,void *keybuf,unsigned int keylen) { agree(mine.priv,their,keybuf,keylen); } - - /** - * Sign a message with a sender's key pair - * - * This takes the SHA-521 of msg[] and then signs the first 32 bytes of this - * digest, returning it and the 64-byte ed25519 signature in signature[]. - * This results in a signature that verifies both the signer's authenticity - * and the integrity of the message. - * - * This is based on the original ed25519 code from NaCl and the SUPERCOP - * cipher benchmark suite, but with the modification that it always - * produces a signature of fixed 96-byte length based on the hash of an - * arbitrary-length message. - * - * @param myPrivate My private key - * @param myPublic My public key - * @param msg Message to sign - * @param len Length of message in bytes - * @param signature Buffer to fill with signature -- MUST be 96 bytes in length - */ - static void sign(const Private &myPrivate,const Public &myPublic,const void *msg,unsigned int len,void *signature); - static inline void sign(const Pair &mine,const void *msg,unsigned int len,void *signature) { sign(mine.priv,mine.pub,msg,len,signature); } - - /** - * Sign a message with a sender's key pair - * - * @param myPrivate My private key - * @param myPublic My public key - * @param msg Message to sign - * @param len Length of message in bytes - * @return Signature - */ - static inline Signature sign(const Private &myPrivate,const Public &myPublic,const void *msg,unsigned int len) - { - Signature sig; - sign(myPrivate,myPublic,msg,len,sig.data); - return sig; - } - static inline Signature sign(const Pair &mine,const void *msg,unsigned int len) - { - Signature sig; - sign(mine.priv,mine.pub,msg,len,sig.data); - return sig; - } - - /** - * Verify a message's signature - * - * @param their Public key to verify against - * @param msg Message to verify signature integrity against - * @param len Length of message in bytes - * @param signature 96-byte signature - * @return True if signature is valid and the message is authentic and unmodified - */ - static bool verify(const Public &their,const void *msg,unsigned int len,const void *signature); - - /** - * Verify a message's signature - * - * @param their Public key to verify against - * @param msg Message to verify signature integrity against - * @param len Length of message in bytes - * @param signature 96-byte signature - * @return True if signature is valid and the message is authentic and unmodified - */ - static inline bool verify(const Public &their,const void *msg,unsigned int len,const Signature &signature) - { - return verify(their,msg,len,signature.data); - } - -private: - // derive first 32 bytes of kp.pub from first 32 bytes of kp.priv - // this is the ECDH key - static void _calcPubDH(Pair &kp); - - // derive 2nd 32 bytes of kp.pub from 2nd 32 bytes of kp.priv - // this is the Ed25519 sign/verify key - static void _calcPubED(Pair &kp); -}; - -} // namespace ZeroTier - -#endif diff --git a/node/Capability.cpp b/node/Capability.cpp index 6e19fca3..1578a0aa 100644 --- a/node/Capability.cpp +++ b/node/Capability.cpp @@ -12,54 +12,60 @@ /****/ #include "Capability.hpp" -#include "RuntimeEnvironment.hpp" + #include "Identity.hpp" -#include "Topology.hpp" -#include "Switch.hpp" #include "Network.hpp" #include "Node.hpp" +#include "RuntimeEnvironment.hpp" +#include "Switch.hpp" +#include "Topology.hpp" namespace ZeroTier { -int Capability::verify(const RuntimeEnvironment *RR,void *tPtr) const +int Capability::verify(const RuntimeEnvironment* RR, void* tPtr) const { - try { - // There must be at least one entry, and sanity check for bad chain max length - if ((_maxCustodyChainLength < 1)||(_maxCustodyChainLength > ZT_MAX_CAPABILITY_CUSTODY_CHAIN_LENGTH)) { - return -1; - } + try { + // There must be at least one entry, and sanity check for bad chain max length + if ((_maxCustodyChainLength < 1) || (_maxCustodyChainLength > ZT_MAX_CAPABILITY_CUSTODY_CHAIN_LENGTH)) { + return -1; + } - // Validate all entries in chain of custody - Buffer<(sizeof(Capability) * 2)> tmp; - this->serialize(tmp,true); - for(unsigned int c=0;c<_maxCustodyChainLength;++c) { - if (c == 0) { - if ((!_custody[c].to)||(!_custody[c].from)||(_custody[c].from != Network::controllerFor(_nwid))) { - return -1; // the first entry must be present and from the network's controller - } - } else { - if (!_custody[c].to) { - return 0; // all previous entries were valid, so we are valid - } else if ((!_custody[c].from)||(_custody[c].from != _custody[c-1].to)) { - return -1; // otherwise if we have another entry it must be from the previous holder in the chain - } - } + // Validate all entries in chain of custody + Buffer<(sizeof(Capability) * 2)> tmp; + this->serialize(tmp, true); + for (unsigned int c = 0; c < _maxCustodyChainLength; ++c) { + if (c == 0) { + if ((! _custody[c].to) || (! _custody[c].from) || (_custody[c].from != Network::controllerFor(_nwid))) { + return -1; // the first entry must be present and from the network's controller + } + } + else { + if (! _custody[c].to) { + return 0; // all previous entries were valid, so we are valid + } + else if ((! _custody[c].from) || (_custody[c].from != _custody[c - 1].to)) { + return -1; // otherwise if we have another entry it must be from the previous holder in the chain + } + } - const Identity id(RR->topology->getIdentity(tPtr,_custody[c].from)); - if (id) { - if (!id.verify(tmp.data(),tmp.size(),_custody[c].signature)) { - return -1; - } - } else { - RR->sw->requestWhois(tPtr,RR->node->now(),_custody[c].from); - return 1; - } - } + const Identity id(RR->topology->getIdentity(tPtr, _custody[c].from)); + if (id) { + if (! id.verify(tmp.data(), tmp.size(), _custody[c].signature)) { + return -1; + } + } + else { + RR->sw->requestWhois(tPtr, RR->node->now(), _custody[c].from); + return 1; + } + } - // We reached max custody chain length and everything was valid - return 0; - } catch ( ... ) {} - return -1; + // We reached max custody chain length and everything was valid + return 0; + } + catch (...) { + } + return -1; } -} // namespace ZeroTier +} // namespace ZeroTier diff --git a/node/Capability.hpp b/node/Capability.hpp index e57eec5b..9cf60e07 100644 --- a/node/Capability.hpp +++ b/node/Capability.hpp @@ -14,19 +14,19 @@ #ifndef ZT_CAPABILITY_HPP #define ZT_CAPABILITY_HPP +#include "../include/ZeroTierOne.h" +#include "Address.hpp" +#include "Buffer.hpp" +#include "Constants.hpp" +#include "Credential.hpp" +#include "ECC.hpp" +#include "Identity.hpp" +#include "Utils.hpp" + #include #include #include -#include "Constants.hpp" -#include "Credential.hpp" -#include "Address.hpp" -#include "C25519.hpp" -#include "Utils.hpp" -#include "Buffer.hpp" -#include "Identity.hpp" -#include "../include/ZeroTierOne.h" - namespace ZeroTier { class RuntimeEnvironment; @@ -54,452 +54,474 @@ class RuntimeEnvironment; * handed off between nodes. Limited transferability of capabilities is * a feature of true capability based security. */ -class Capability : public Credential -{ -public: - static inline Credential::Type credentialType() { return Credential::CREDENTIAL_TYPE_CAPABILITY; } +class Capability : public Credential { + public: + static inline Credential::Type credentialType() + { + return Credential::CREDENTIAL_TYPE_CAPABILITY; + } - Capability() : - _nwid(0), - _ts(0), - _id(0), - _maxCustodyChainLength(0), - _ruleCount(0) - { - memset(_rules,0,sizeof(_rules)); - memset(_custody,0,sizeof(_custody)); - } + Capability() : _nwid(0), _ts(0), _id(0), _maxCustodyChainLength(0), _ruleCount(0) + { + memset(_rules, 0, sizeof(_rules)); + memset(_custody, 0, sizeof(_custody)); + } - /** - * @param id Capability ID - * @param nwid Network ID - * @param ts Timestamp (at controller) - * @param mccl Maximum custody chain length (1 to create non-transferable capability) - * @param rules Network flow rules for this capability - * @param ruleCount Number of flow rules - */ - Capability(uint32_t id,uint64_t nwid,int64_t ts,unsigned int mccl,const ZT_VirtualNetworkRule *rules,unsigned int ruleCount) : - _nwid(nwid), - _ts(ts), - _id(id), - _maxCustodyChainLength((mccl > 0) ? ((mccl < ZT_MAX_CAPABILITY_CUSTODY_CHAIN_LENGTH) ? mccl : (unsigned int)ZT_MAX_CAPABILITY_CUSTODY_CHAIN_LENGTH) : 1), - _ruleCount((ruleCount < ZT_MAX_CAPABILITY_RULES) ? ruleCount : ZT_MAX_CAPABILITY_RULES) - { - if (_ruleCount > 0) { - memcpy(_rules,rules,sizeof(ZT_VirtualNetworkRule) * _ruleCount); - } - } + /** + * @param id Capability ID + * @param nwid Network ID + * @param ts Timestamp (at controller) + * @param mccl Maximum custody chain length (1 to create non-transferable capability) + * @param rules Network flow rules for this capability + * @param ruleCount Number of flow rules + */ + Capability(uint32_t id, uint64_t nwid, int64_t ts, unsigned int mccl, const ZT_VirtualNetworkRule* rules, unsigned int ruleCount) + : _nwid(nwid) + , _ts(ts) + , _id(id) + , _maxCustodyChainLength((mccl > 0) ? ((mccl < ZT_MAX_CAPABILITY_CUSTODY_CHAIN_LENGTH) ? mccl : (unsigned int)ZT_MAX_CAPABILITY_CUSTODY_CHAIN_LENGTH) : 1) + , _ruleCount((ruleCount < ZT_MAX_CAPABILITY_RULES) ? ruleCount : ZT_MAX_CAPABILITY_RULES) + { + if (_ruleCount > 0) { + memcpy(_rules, rules, sizeof(ZT_VirtualNetworkRule) * _ruleCount); + } + } - /** - * @return Rules -- see ruleCount() for size of array - */ - inline const ZT_VirtualNetworkRule *rules() const { return _rules; } + /** + * @return Rules -- see ruleCount() for size of array + */ + inline const ZT_VirtualNetworkRule* rules() const + { + return _rules; + } - /** - * @return Number of rules in rules() - */ - inline unsigned int ruleCount() const { return _ruleCount; } + /** + * @return Number of rules in rules() + */ + inline unsigned int ruleCount() const + { + return _ruleCount; + } - /** - * @return ID and evaluation order of this capability in network - */ - inline uint32_t id() const { return _id; } + /** + * @return ID and evaluation order of this capability in network + */ + inline uint32_t id() const + { + return _id; + } - /** - * @return Network ID for which this capability was issued - */ - inline uint64_t networkId() const { return _nwid; } + /** + * @return Network ID for which this capability was issued + */ + inline uint64_t networkId() const + { + return _nwid; + } - /** - * @return Timestamp - */ - inline int64_t timestamp() const { return _ts; } + /** + * @return Timestamp + */ + inline int64_t timestamp() const + { + return _ts; + } - /** - * @return Last 'to' address in chain of custody - */ - inline Address issuedTo() const - { - Address i2; - for(unsigned int i=0;i tmp; - this->serialize(tmp,true); - _custody[i].to = to; - _custody[i].from = from.address(); - _custody[i].signature = from.sign(tmp.data(),tmp.size()); - return true; - } - } - } catch ( ... ) {} - return false; - } + /** + * Sign this capability and add signature to its chain of custody + * + * If this returns false, this object should be considered to be + * in an undefined state and should be discarded. False can be returned + * if there is no more room for signatures (max chain length reached) + * or if the 'from' identity does not include a secret key to allow + * it to sign anything. + * + * @param from Signing identity (must have secret) + * @param to Recipient of this signature + * @return True if signature successful and chain of custody appended + */ + inline bool sign(const Identity& from, const Address& to) + { + try { + for (unsigned int i = 0; ((i < _maxCustodyChainLength) && (i < ZT_MAX_CAPABILITY_CUSTODY_CHAIN_LENGTH)); ++i) { + if (! (_custody[i].to)) { + Buffer<(sizeof(Capability) * 2)> tmp; + this->serialize(tmp, true); + _custody[i].to = to; + _custody[i].from = from.address(); + _custody[i].signature = from.sign(tmp.data(), tmp.size()); + return true; + } + } + } + catch (...) { + } + return false; + } - /** - * Verify this capability's chain of custody and signatures - * - * @param RR Runtime environment to provide for peer lookup, etc. - * @return 0 == OK, 1 == waiting for WHOIS, -1 == BAD signature or chain - */ - int verify(const RuntimeEnvironment *RR,void *tPtr) const; + /** + * Verify this capability's chain of custody and signatures + * + * @param RR Runtime environment to provide for peer lookup, etc. + * @return 0 == OK, 1 == waiting for WHOIS, -1 == BAD signature or chain + */ + int verify(const RuntimeEnvironment* RR, void* tPtr) const; - template - static inline void serializeRules(Buffer &b,const ZT_VirtualNetworkRule *rules,unsigned int ruleCount) - { - for(unsigned int i=0;i static inline void serializeRules(Buffer& b, const ZT_VirtualNetworkRule* rules, unsigned int ruleCount) + { + for (unsigned int i = 0; i < ruleCount; ++i) { + // Each rule consists of its 8-bit type followed by the size of that type's + // field followed by field data. The inclusion of the size will allow non-supported + // rules to be ignored but still parsed. + b.append((uint8_t)rules[i].t); + switch ((ZT_VirtualNetworkRuleType)(rules[i].t & 0x3f)) { + default: + b.append((uint8_t)0); + break; + case ZT_NETWORK_RULE_ACTION_TEE: + case ZT_NETWORK_RULE_ACTION_WATCH: + case ZT_NETWORK_RULE_ACTION_REDIRECT: + b.append((uint8_t)14); + b.append((uint64_t)rules[i].v.fwd.address); + b.append((uint32_t)rules[i].v.fwd.flags); + b.append((uint16_t)rules[i].v.fwd.length); // unused for redirect + break; + case ZT_NETWORK_RULE_MATCH_SOURCE_ZEROTIER_ADDRESS: + case ZT_NETWORK_RULE_MATCH_DEST_ZEROTIER_ADDRESS: + b.append((uint8_t)5); + Address(rules[i].v.zt).appendTo(b); + break; + case ZT_NETWORK_RULE_MATCH_VLAN_ID: + b.append((uint8_t)2); + b.append((uint16_t)rules[i].v.vlanId); + break; + case ZT_NETWORK_RULE_MATCH_VLAN_PCP: + b.append((uint8_t)1); + b.append((uint8_t)rules[i].v.vlanPcp); + break; + case ZT_NETWORK_RULE_MATCH_VLAN_DEI: + b.append((uint8_t)1); + b.append((uint8_t)rules[i].v.vlanDei); + break; + case ZT_NETWORK_RULE_MATCH_MAC_SOURCE: + case ZT_NETWORK_RULE_MATCH_MAC_DEST: + b.append((uint8_t)6); + b.append(rules[i].v.mac, 6); + break; + case ZT_NETWORK_RULE_MATCH_IPV4_SOURCE: + case ZT_NETWORK_RULE_MATCH_IPV4_DEST: + b.append((uint8_t)5); + b.append(&(rules[i].v.ipv4.ip), 4); + b.append((uint8_t)rules[i].v.ipv4.mask); + break; + case ZT_NETWORK_RULE_MATCH_IPV6_SOURCE: + case ZT_NETWORK_RULE_MATCH_IPV6_DEST: + b.append((uint8_t)17); + b.append(rules[i].v.ipv6.ip, 16); + b.append((uint8_t)rules[i].v.ipv6.mask); + break; + case ZT_NETWORK_RULE_MATCH_IP_TOS: + b.append((uint8_t)3); + b.append((uint8_t)rules[i].v.ipTos.mask); + b.append((uint8_t)rules[i].v.ipTos.value[0]); + b.append((uint8_t)rules[i].v.ipTos.value[1]); + break; + case ZT_NETWORK_RULE_MATCH_IP_PROTOCOL: + b.append((uint8_t)1); + b.append((uint8_t)rules[i].v.ipProtocol); + break; + case ZT_NETWORK_RULE_MATCH_ETHERTYPE: + b.append((uint8_t)2); + b.append((uint16_t)rules[i].v.etherType); + break; + case ZT_NETWORK_RULE_MATCH_ICMP: + b.append((uint8_t)3); + b.append((uint8_t)rules[i].v.icmp.type); + b.append((uint8_t)rules[i].v.icmp.code); + b.append((uint8_t)rules[i].v.icmp.flags); + break; + case ZT_NETWORK_RULE_MATCH_IP_SOURCE_PORT_RANGE: + case ZT_NETWORK_RULE_MATCH_IP_DEST_PORT_RANGE: + b.append((uint8_t)4); + b.append((uint16_t)rules[i].v.port[0]); + b.append((uint16_t)rules[i].v.port[1]); + break; + case ZT_NETWORK_RULE_MATCH_CHARACTERISTICS: + b.append((uint8_t)8); + b.append((uint64_t)rules[i].v.characteristics); + break; + case ZT_NETWORK_RULE_MATCH_FRAME_SIZE_RANGE: + b.append((uint8_t)4); + b.append((uint16_t)rules[i].v.frameSize[0]); + b.append((uint16_t)rules[i].v.frameSize[1]); + break; + case ZT_NETWORK_RULE_MATCH_RANDOM: + b.append((uint8_t)4); + b.append((uint32_t)rules[i].v.randomProbability); + break; + case ZT_NETWORK_RULE_MATCH_TAGS_DIFFERENCE: + case ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_AND: + case ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_OR: + case ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_XOR: + case ZT_NETWORK_RULE_MATCH_TAGS_EQUAL: + case ZT_NETWORK_RULE_MATCH_TAG_SENDER: + case ZT_NETWORK_RULE_MATCH_TAG_RECEIVER: + b.append((uint8_t)8); + b.append((uint32_t)rules[i].v.tag.id); + b.append((uint32_t)rules[i].v.tag.value); + break; + case ZT_NETWORK_RULE_MATCH_INTEGER_RANGE: + b.append((uint8_t)19); + b.append((uint64_t)rules[i].v.intRange.start); + b.append((uint64_t)(rules[i].v.intRange.start + (uint64_t)rules[i].v.intRange.end)); // more future-proof + b.append((uint16_t)rules[i].v.intRange.idx); + b.append((uint8_t)rules[i].v.intRange.format); + break; + } + } + } - template - static inline void deserializeRules(const Buffer &b,unsigned int &p,ZT_VirtualNetworkRule *rules,unsigned int &ruleCount,const unsigned int maxRuleCount) - { - while ((ruleCount < maxRuleCount)&&(p < b.size())) { - rules[ruleCount].t = (uint8_t)b[p++]; - const unsigned int fieldLen = (unsigned int)b[p++]; - switch((ZT_VirtualNetworkRuleType)(rules[ruleCount].t & 0x3f)) { - default: - break; - case ZT_NETWORK_RULE_ACTION_TEE: - case ZT_NETWORK_RULE_ACTION_WATCH: - case ZT_NETWORK_RULE_ACTION_REDIRECT: - rules[ruleCount].v.fwd.address = b.template at(p); - rules[ruleCount].v.fwd.flags = b.template at(p + 8); - rules[ruleCount].v.fwd.length = b.template at(p + 12); - break; - case ZT_NETWORK_RULE_MATCH_SOURCE_ZEROTIER_ADDRESS: - case ZT_NETWORK_RULE_MATCH_DEST_ZEROTIER_ADDRESS: - rules[ruleCount].v.zt = Address(b.field(p,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH).toInt(); - break; - case ZT_NETWORK_RULE_MATCH_VLAN_ID: - rules[ruleCount].v.vlanId = b.template at(p); - break; - case ZT_NETWORK_RULE_MATCH_VLAN_PCP: - rules[ruleCount].v.vlanPcp = (uint8_t)b[p]; - break; - case ZT_NETWORK_RULE_MATCH_VLAN_DEI: - rules[ruleCount].v.vlanDei = (uint8_t)b[p]; - break; - case ZT_NETWORK_RULE_MATCH_MAC_SOURCE: - case ZT_NETWORK_RULE_MATCH_MAC_DEST: - memcpy(rules[ruleCount].v.mac,b.field(p,6),6); - break; - case ZT_NETWORK_RULE_MATCH_IPV4_SOURCE: - case ZT_NETWORK_RULE_MATCH_IPV4_DEST: - memcpy(&(rules[ruleCount].v.ipv4.ip),b.field(p,4),4); - rules[ruleCount].v.ipv4.mask = (uint8_t)b[p + 4]; - break; - case ZT_NETWORK_RULE_MATCH_IPV6_SOURCE: - case ZT_NETWORK_RULE_MATCH_IPV6_DEST: - memcpy(rules[ruleCount].v.ipv6.ip,b.field(p,16),16); - rules[ruleCount].v.ipv6.mask = (uint8_t)b[p + 16]; - break; - case ZT_NETWORK_RULE_MATCH_IP_TOS: - rules[ruleCount].v.ipTos.mask = (uint8_t)b[p]; - rules[ruleCount].v.ipTos.value[0] = (uint8_t)b[p+1]; - rules[ruleCount].v.ipTos.value[1] = (uint8_t)b[p+2]; - break; - case ZT_NETWORK_RULE_MATCH_IP_PROTOCOL: - rules[ruleCount].v.ipProtocol = (uint8_t)b[p]; - break; - case ZT_NETWORK_RULE_MATCH_ETHERTYPE: - rules[ruleCount].v.etherType = b.template at(p); - break; - case ZT_NETWORK_RULE_MATCH_ICMP: - rules[ruleCount].v.icmp.type = (uint8_t)b[p]; - rules[ruleCount].v.icmp.code = (uint8_t)b[p+1]; - rules[ruleCount].v.icmp.flags = (uint8_t)b[p+2]; - break; - case ZT_NETWORK_RULE_MATCH_IP_SOURCE_PORT_RANGE: - case ZT_NETWORK_RULE_MATCH_IP_DEST_PORT_RANGE: - rules[ruleCount].v.port[0] = b.template at(p); - rules[ruleCount].v.port[1] = b.template at(p + 2); - break; - case ZT_NETWORK_RULE_MATCH_CHARACTERISTICS: - rules[ruleCount].v.characteristics = b.template at(p); - break; - case ZT_NETWORK_RULE_MATCH_FRAME_SIZE_RANGE: - rules[ruleCount].v.frameSize[0] = b.template at(p); - rules[ruleCount].v.frameSize[1] = b.template at(p + 2); - break; - case ZT_NETWORK_RULE_MATCH_RANDOM: - rules[ruleCount].v.randomProbability = b.template at(p); - break; - case ZT_NETWORK_RULE_MATCH_TAGS_DIFFERENCE: - case ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_AND: - case ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_OR: - case ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_XOR: - case ZT_NETWORK_RULE_MATCH_TAGS_EQUAL: - case ZT_NETWORK_RULE_MATCH_TAG_SENDER: - case ZT_NETWORK_RULE_MATCH_TAG_RECEIVER: - rules[ruleCount].v.tag.id = b.template at(p); - rules[ruleCount].v.tag.value = b.template at(p + 4); - break; - case ZT_NETWORK_RULE_MATCH_INTEGER_RANGE: - rules[ruleCount].v.intRange.start = b.template at(p); - rules[ruleCount].v.intRange.end = (uint32_t)(b.template at(p + 8) - rules[ruleCount].v.intRange.start); - rules[ruleCount].v.intRange.idx = b.template at(p + 16); - rules[ruleCount].v.intRange.format = (uint8_t)b[p + 18]; - break; - } - p += fieldLen; - ++ruleCount; - } - } + template static inline void deserializeRules(const Buffer& b, unsigned int& p, ZT_VirtualNetworkRule* rules, unsigned int& ruleCount, const unsigned int maxRuleCount) + { + while ((ruleCount < maxRuleCount) && (p < b.size())) { + rules[ruleCount].t = (uint8_t)b[p++]; + const unsigned int fieldLen = (unsigned int)b[p++]; + switch ((ZT_VirtualNetworkRuleType)(rules[ruleCount].t & 0x3f)) { + default: + break; + case ZT_NETWORK_RULE_ACTION_TEE: + case ZT_NETWORK_RULE_ACTION_WATCH: + case ZT_NETWORK_RULE_ACTION_REDIRECT: + rules[ruleCount].v.fwd.address = b.template at(p); + rules[ruleCount].v.fwd.flags = b.template at(p + 8); + rules[ruleCount].v.fwd.length = b.template at(p + 12); + break; + case ZT_NETWORK_RULE_MATCH_SOURCE_ZEROTIER_ADDRESS: + case ZT_NETWORK_RULE_MATCH_DEST_ZEROTIER_ADDRESS: + rules[ruleCount].v.zt = Address(b.field(p, ZT_ADDRESS_LENGTH), ZT_ADDRESS_LENGTH).toInt(); + break; + case ZT_NETWORK_RULE_MATCH_VLAN_ID: + rules[ruleCount].v.vlanId = b.template at(p); + break; + case ZT_NETWORK_RULE_MATCH_VLAN_PCP: + rules[ruleCount].v.vlanPcp = (uint8_t)b[p]; + break; + case ZT_NETWORK_RULE_MATCH_VLAN_DEI: + rules[ruleCount].v.vlanDei = (uint8_t)b[p]; + break; + case ZT_NETWORK_RULE_MATCH_MAC_SOURCE: + case ZT_NETWORK_RULE_MATCH_MAC_DEST: + memcpy(rules[ruleCount].v.mac, b.field(p, 6), 6); + break; + case ZT_NETWORK_RULE_MATCH_IPV4_SOURCE: + case ZT_NETWORK_RULE_MATCH_IPV4_DEST: + memcpy(&(rules[ruleCount].v.ipv4.ip), b.field(p, 4), 4); + rules[ruleCount].v.ipv4.mask = (uint8_t)b[p + 4]; + break; + case ZT_NETWORK_RULE_MATCH_IPV6_SOURCE: + case ZT_NETWORK_RULE_MATCH_IPV6_DEST: + memcpy(rules[ruleCount].v.ipv6.ip, b.field(p, 16), 16); + rules[ruleCount].v.ipv6.mask = (uint8_t)b[p + 16]; + break; + case ZT_NETWORK_RULE_MATCH_IP_TOS: + rules[ruleCount].v.ipTos.mask = (uint8_t)b[p]; + rules[ruleCount].v.ipTos.value[0] = (uint8_t)b[p + 1]; + rules[ruleCount].v.ipTos.value[1] = (uint8_t)b[p + 2]; + break; + case ZT_NETWORK_RULE_MATCH_IP_PROTOCOL: + rules[ruleCount].v.ipProtocol = (uint8_t)b[p]; + break; + case ZT_NETWORK_RULE_MATCH_ETHERTYPE: + rules[ruleCount].v.etherType = b.template at(p); + break; + case ZT_NETWORK_RULE_MATCH_ICMP: + rules[ruleCount].v.icmp.type = (uint8_t)b[p]; + rules[ruleCount].v.icmp.code = (uint8_t)b[p + 1]; + rules[ruleCount].v.icmp.flags = (uint8_t)b[p + 2]; + break; + case ZT_NETWORK_RULE_MATCH_IP_SOURCE_PORT_RANGE: + case ZT_NETWORK_RULE_MATCH_IP_DEST_PORT_RANGE: + rules[ruleCount].v.port[0] = b.template at(p); + rules[ruleCount].v.port[1] = b.template at(p + 2); + break; + case ZT_NETWORK_RULE_MATCH_CHARACTERISTICS: + rules[ruleCount].v.characteristics = b.template at(p); + break; + case ZT_NETWORK_RULE_MATCH_FRAME_SIZE_RANGE: + rules[ruleCount].v.frameSize[0] = b.template at(p); + rules[ruleCount].v.frameSize[1] = b.template at(p + 2); + break; + case ZT_NETWORK_RULE_MATCH_RANDOM: + rules[ruleCount].v.randomProbability = b.template at(p); + break; + case ZT_NETWORK_RULE_MATCH_TAGS_DIFFERENCE: + case ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_AND: + case ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_OR: + case ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_XOR: + case ZT_NETWORK_RULE_MATCH_TAGS_EQUAL: + case ZT_NETWORK_RULE_MATCH_TAG_SENDER: + case ZT_NETWORK_RULE_MATCH_TAG_RECEIVER: + rules[ruleCount].v.tag.id = b.template at(p); + rules[ruleCount].v.tag.value = b.template at(p + 4); + break; + case ZT_NETWORK_RULE_MATCH_INTEGER_RANGE: + rules[ruleCount].v.intRange.start = b.template at(p); + rules[ruleCount].v.intRange.end = (uint32_t)(b.template at(p + 8) - rules[ruleCount].v.intRange.start); + rules[ruleCount].v.intRange.idx = b.template at(p + 16); + rules[ruleCount].v.intRange.format = (uint8_t)b[p + 18]; + break; + } + p += fieldLen; + ++ruleCount; + } + } - template - inline void serialize(Buffer &b,const bool forSign = false) const - { - if (forSign) { - b.append((uint64_t)0x7f7f7f7f7f7f7f7fULL); - } + template inline void serialize(Buffer& b, const bool forSign = false) const + { + if (forSign) { + b.append((uint64_t)0x7f7f7f7f7f7f7f7fULL); + } - // These are the same between Tag and Capability - b.append(_nwid); - b.append(_ts); - b.append(_id); + // These are the same between Tag and Capability + b.append(_nwid); + b.append(_ts); + b.append(_id); - b.append((uint16_t)_ruleCount); - serializeRules(b,_rules,_ruleCount); - b.append((uint8_t)_maxCustodyChainLength); + b.append((uint16_t)_ruleCount); + serializeRules(b, _rules, _ruleCount); + b.append((uint8_t)_maxCustodyChainLength); - if (!forSign) { - for(unsigned int i=0;;++i) { - if ((i < _maxCustodyChainLength)&&(i < ZT_MAX_CAPABILITY_CUSTODY_CHAIN_LENGTH)&&(_custody[i].to)) { - _custody[i].to.appendTo(b); - _custody[i].from.appendTo(b); - b.append((uint8_t)1); // 1 == Ed25519 signature - b.append((uint16_t)ZT_C25519_SIGNATURE_LEN); // length of signature - b.append(_custody[i].signature.data,ZT_C25519_SIGNATURE_LEN); - } else { - b.append((unsigned char)0,ZT_ADDRESS_LENGTH); // zero 'to' terminates chain - break; - } - } - } + if (! forSign) { + for (unsigned int i = 0;; ++i) { + if ((i < _maxCustodyChainLength) && (i < ZT_MAX_CAPABILITY_CUSTODY_CHAIN_LENGTH) && (_custody[i].to)) { + _custody[i].to.appendTo(b); + _custody[i].from.appendTo(b); + b.append((uint8_t)1); // 1 == Ed25519 signature + b.append((uint16_t)ZT_ECC_SIGNATURE_LEN); // length of signature + b.append(_custody[i].signature.data, ZT_ECC_SIGNATURE_LEN); + } + else { + b.append((unsigned char)0, ZT_ADDRESS_LENGTH); // zero 'to' terminates chain + break; + } + } + } - // This is the size of any additional fields, currently 0. - b.append((uint16_t)0); + // This is the size of any additional fields, currently 0. + b.append((uint16_t)0); - if (forSign) { - b.append((uint64_t)0x7f7f7f7f7f7f7f7fULL); - } - } + if (forSign) { + b.append((uint64_t)0x7f7f7f7f7f7f7f7fULL); + } + } - template - inline unsigned int deserialize(const Buffer &b,unsigned int startAt = 0) - { - *this = Capability(); + template inline unsigned int deserialize(const Buffer& b, unsigned int startAt = 0) + { + *this = Capability(); - unsigned int p = startAt; + unsigned int p = startAt; - _nwid = b.template at(p); - p += 8; - _ts = b.template at(p); - p += 8; - _id = b.template at(p); - p += 4; + _nwid = b.template at(p); + p += 8; + _ts = b.template at(p); + p += 8; + _id = b.template at(p); + p += 4; - const unsigned int rc = b.template at(p); - p += 2; - if (rc > ZT_MAX_CAPABILITY_RULES) { - throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_OVERFLOW; - } - deserializeRules(b,p,_rules,_ruleCount,rc); + const unsigned int rc = b.template at(p); + p += 2; + if (rc > ZT_MAX_CAPABILITY_RULES) { + throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_OVERFLOW; + } + deserializeRules(b, p, _rules, _ruleCount, rc); - _maxCustodyChainLength = (unsigned int)b[p++]; - if ((_maxCustodyChainLength < 1)||(_maxCustodyChainLength > ZT_MAX_CAPABILITY_CUSTODY_CHAIN_LENGTH)) { - throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_OVERFLOW; - } + _maxCustodyChainLength = (unsigned int)b[p++]; + if ((_maxCustodyChainLength < 1) || (_maxCustodyChainLength > ZT_MAX_CAPABILITY_CUSTODY_CHAIN_LENGTH)) { + throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_OVERFLOW; + } - for(unsigned int i=0;;++i) { - const Address to(b.field(p,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); - p += ZT_ADDRESS_LENGTH; - if (!to) { - break; - } - if ((i >= _maxCustodyChainLength)||(i >= ZT_MAX_CAPABILITY_CUSTODY_CHAIN_LENGTH)) { - throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_OVERFLOW; - } - _custody[i].to = to; - _custody[i].from.setTo(b.field(p,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); - p += ZT_ADDRESS_LENGTH; - if (b[p++] == 1) { - if (b.template at(p) != ZT_C25519_SIGNATURE_LEN) { - throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_INVALID_CRYPTOGRAPHIC_TOKEN; - } - p += 2; - memcpy(_custody[i].signature.data,b.field(p,ZT_C25519_SIGNATURE_LEN),ZT_C25519_SIGNATURE_LEN); - p += ZT_C25519_SIGNATURE_LEN; - } else { - p += 2 + b.template at(p); - } - } + for (unsigned int i = 0;; ++i) { + const Address to(b.field(p, ZT_ADDRESS_LENGTH), ZT_ADDRESS_LENGTH); + p += ZT_ADDRESS_LENGTH; + if (! to) { + break; + } + if ((i >= _maxCustodyChainLength) || (i >= ZT_MAX_CAPABILITY_CUSTODY_CHAIN_LENGTH)) { + throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_OVERFLOW; + } + _custody[i].to = to; + _custody[i].from.setTo(b.field(p, ZT_ADDRESS_LENGTH), ZT_ADDRESS_LENGTH); + p += ZT_ADDRESS_LENGTH; + if (b[p++] == 1) { + if (b.template at(p) != ZT_ECC_SIGNATURE_LEN) { + throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_INVALID_CRYPTOGRAPHIC_TOKEN; + } + p += 2; + memcpy(_custody[i].signature.data, b.field(p, ZT_ECC_SIGNATURE_LEN), ZT_ECC_SIGNATURE_LEN); + p += ZT_ECC_SIGNATURE_LEN; + } + else { + p += 2 + b.template at(p); + } + } - p += 2 + b.template at(p); - if (p > b.size()) { - throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_OVERFLOW; - } + p += 2 + b.template at(p); + if (p > b.size()) { + throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_OVERFLOW; + } - return (p - startAt); - } + return (p - startAt); + } - // Provides natural sort order by ID - inline bool operator<(const Capability &c) const { return (_id < c._id); } + // Provides natural sort order by ID + inline bool operator<(const Capability& c) const + { + return (_id < c._id); + } - inline bool operator==(const Capability &c) const { return (memcmp(this,&c,sizeof(Capability)) == 0); } - inline bool operator!=(const Capability &c) const { return (memcmp(this,&c,sizeof(Capability)) != 0); } + inline bool operator==(const Capability& c) const + { + return (memcmp(this, &c, sizeof(Capability)) == 0); + } + inline bool operator!=(const Capability& c) const + { + return (memcmp(this, &c, sizeof(Capability)) != 0); + } -private: - uint64_t _nwid; - int64_t _ts; - uint32_t _id; + private: + uint64_t _nwid; + int64_t _ts; + uint32_t _id; - unsigned int _maxCustodyChainLength; + unsigned int _maxCustodyChainLength; - unsigned int _ruleCount; - ZT_VirtualNetworkRule _rules[ZT_MAX_CAPABILITY_RULES]; + unsigned int _ruleCount; + ZT_VirtualNetworkRule _rules[ZT_MAX_CAPABILITY_RULES]; - struct { - Address to; - Address from; - C25519::Signature signature; - } _custody[ZT_MAX_CAPABILITY_CUSTODY_CHAIN_LENGTH]; + struct { + Address to; + Address from; + ECC::Signature signature; + } _custody[ZT_MAX_CAPABILITY_CUSTODY_CHAIN_LENGTH]; }; -} // namespace ZeroTier +} // namespace ZeroTier #endif diff --git a/node/CertificateOfMembership.cpp b/node/CertificateOfMembership.cpp index 65820c29..eac45250 100644 --- a/node/CertificateOfMembership.cpp +++ b/node/CertificateOfMembership.cpp @@ -12,127 +12,130 @@ /****/ #include "CertificateOfMembership.hpp" -#include "RuntimeEnvironment.hpp" -#include "Topology.hpp" -#include "Switch.hpp" + +#include "ECC.hpp" #include "Network.hpp" #include "Node.hpp" +#include "RuntimeEnvironment.hpp" +#include "Switch.hpp" +#include "Topology.hpp" namespace ZeroTier { -CertificateOfMembership::CertificateOfMembership(uint64_t timestamp,uint64_t timestampMaxDelta,uint64_t nwid,const Identity &issuedTo) +CertificateOfMembership::CertificateOfMembership(uint64_t timestamp, uint64_t timestampMaxDelta, uint64_t nwid, const Identity& issuedTo) { - _qualifiers[0].id = COM_RESERVED_ID_TIMESTAMP; - _qualifiers[0].value = timestamp; - _qualifiers[0].maxDelta = timestampMaxDelta; - _qualifiers[1].id = COM_RESERVED_ID_NETWORK_ID; - _qualifiers[1].value = nwid; - _qualifiers[1].maxDelta = 0; - _qualifiers[2].id = COM_RESERVED_ID_ISSUED_TO; - _qualifiers[2].value = issuedTo.address().toInt(); - _qualifiers[2].maxDelta = 0xffffffffffffffffULL; + _qualifiers[0].id = COM_RESERVED_ID_TIMESTAMP; + _qualifiers[0].value = timestamp; + _qualifiers[0].maxDelta = timestampMaxDelta; + _qualifiers[1].id = COM_RESERVED_ID_NETWORK_ID; + _qualifiers[1].value = nwid; + _qualifiers[1].maxDelta = 0; + _qualifiers[2].id = COM_RESERVED_ID_ISSUED_TO; + _qualifiers[2].value = issuedTo.address().toInt(); + _qualifiers[2].maxDelta = 0xffffffffffffffffULL; - // Include hash of full identity public key in COM for hardening purposes. Pack it in - // using the original COM format. Format may be revised in the future to make this cleaner. - uint64_t idHash[6]; - issuedTo.publicKeyHash(idHash); - for(unsigned long i=0;i<4;++i) { - _qualifiers[i + 3].id = (uint64_t)(i + 3); - _qualifiers[i + 3].value = Utils::ntoh(idHash[i]); - _qualifiers[i + 3].maxDelta = 0xffffffffffffffffULL; - } + // Include hash of full identity public key in COM for hardening purposes. Pack it in + // using the original COM format. Format may be revised in the future to make this cleaner. + uint64_t idHash[6]; + issuedTo.publicKeyHash(idHash); + for (unsigned long i = 0; i < 4; ++i) { + _qualifiers[i + 3].id = (uint64_t)(i + 3); + _qualifiers[i + 3].value = Utils::ntoh(idHash[i]); + _qualifiers[i + 3].maxDelta = 0xffffffffffffffffULL; + } - _qualifierCount = 7; - memset(_signature.data,0,ZT_C25519_SIGNATURE_LEN); + _qualifierCount = 7; + memset(_signature.data, 0, ZT_ECC_SIGNATURE_LEN); } -bool CertificateOfMembership::agreesWith(const CertificateOfMembership &other, const Identity &otherIdentity) const +bool CertificateOfMembership::agreesWith(const CertificateOfMembership& other, const Identity& otherIdentity) const { - if ((_qualifierCount == 0)||(other._qualifierCount == 0)) { - return false; - } + if ((_qualifierCount == 0) || (other._qualifierCount == 0)) { + return false; + } - std::map< uint64_t, uint64_t > otherFields; - for(unsigned int i=0;i otherFields; + for (unsigned int i = 0; i < other._qualifierCount; ++i) { + otherFields[other._qualifiers[i].id] = other._qualifiers[i].value; + } - bool fullIdentityVerification = false; - for(unsigned int i=0;i<_qualifierCount;++i) { - const uint64_t qid = _qualifiers[i].id; - if ((qid >= 3)&&(qid <= 6)) { - fullIdentityVerification = true; - } - std::map< uint64_t, uint64_t >::iterator otherQ(otherFields.find(qid)); - if (otherQ == otherFields.end()) { - return false; - } - const uint64_t a = _qualifiers[i].value; - const uint64_t b = otherQ->second; - if (((a >= b) ? (a - b) : (b - a)) > _qualifiers[i].maxDelta) { - return false; - } - } + bool fullIdentityVerification = false; + for (unsigned int i = 0; i < _qualifierCount; ++i) { + const uint64_t qid = _qualifiers[i].id; + if ((qid >= 3) && (qid <= 6)) { + fullIdentityVerification = true; + } + std::map::iterator otherQ(otherFields.find(qid)); + if (otherQ == otherFields.end()) { + return false; + } + const uint64_t a = _qualifiers[i].value; + const uint64_t b = otherQ->second; + if (((a >= b) ? (a - b) : (b - a)) > _qualifiers[i].maxDelta) { + return false; + } + } - // If this COM has a full hash of its identity, assume the other must have this as well. - // Otherwise we are on a controller that does not incorporate these. - if (fullIdentityVerification) { - uint64_t idHash[6]; - otherIdentity.publicKeyHash(idHash); - for(unsigned long i=0;i<4;++i) { - std::map< uint64_t, uint64_t >::iterator otherQ(otherFields.find((uint64_t)(i + 3))); - if (otherQ == otherFields.end()) { - return false; - } - if (otherQ->second != Utils::ntoh(idHash[i])) { - return false; - } - } - } + // If this COM has a full hash of its identity, assume the other must have this as well. + // Otherwise we are on a controller that does not incorporate these. + if (fullIdentityVerification) { + uint64_t idHash[6]; + otherIdentity.publicKeyHash(idHash); + for (unsigned long i = 0; i < 4; ++i) { + std::map::iterator otherQ(otherFields.find((uint64_t)(i + 3))); + if (otherQ == otherFields.end()) { + return false; + } + if (otherQ->second != Utils::ntoh(idHash[i])) { + return false; + } + } + } - return true; + return true; } -bool CertificateOfMembership::sign(const Identity &with) +bool CertificateOfMembership::sign(const Identity& with) { - uint64_t buf[ZT_NETWORK_COM_MAX_QUALIFIERS * 3]; - unsigned int ptr = 0; - for(unsigned int i=0;i<_qualifierCount;++i) { - buf[ptr++] = Utils::hton(_qualifiers[i].id); - buf[ptr++] = Utils::hton(_qualifiers[i].value); - buf[ptr++] = Utils::hton(_qualifiers[i].maxDelta); - } + uint64_t buf[ZT_NETWORK_COM_MAX_QUALIFIERS * 3]; + unsigned int ptr = 0; + for (unsigned int i = 0; i < _qualifierCount; ++i) { + buf[ptr++] = Utils::hton(_qualifiers[i].id); + buf[ptr++] = Utils::hton(_qualifiers[i].value); + buf[ptr++] = Utils::hton(_qualifiers[i].maxDelta); + } - try { - _signature = with.sign(buf,ptr * sizeof(uint64_t)); - _signedBy = with.address(); - return true; - } catch ( ... ) { - _signedBy.zero(); - return false; - } + try { + _signature = with.sign(buf, ptr * sizeof(uint64_t)); + _signedBy = with.address(); + return true; + } + catch (...) { + _signedBy.zero(); + return false; + } } -int CertificateOfMembership::verify(const RuntimeEnvironment *RR,void *tPtr) const +int CertificateOfMembership::verify(const RuntimeEnvironment* RR, void* tPtr) const { - if ((!_signedBy)||(_signedBy != Network::controllerFor(networkId()))||(_qualifierCount > ZT_NETWORK_COM_MAX_QUALIFIERS)) { - return -1; - } + if ((! _signedBy) || (_signedBy != Network::controllerFor(networkId())) || (_qualifierCount > ZT_NETWORK_COM_MAX_QUALIFIERS)) { + return -1; + } - const Identity id(RR->topology->getIdentity(tPtr,_signedBy)); - if (!id) { - RR->sw->requestWhois(tPtr,RR->node->now(),_signedBy); - return 1; - } + const Identity id(RR->topology->getIdentity(tPtr, _signedBy)); + if (! id) { + RR->sw->requestWhois(tPtr, RR->node->now(), _signedBy); + return 1; + } - uint64_t buf[ZT_NETWORK_COM_MAX_QUALIFIERS * 3]; - unsigned int ptr = 0; - for(unsigned int i=0;i<_qualifierCount;++i) { - buf[ptr++] = Utils::hton(_qualifiers[i].id); - buf[ptr++] = Utils::hton(_qualifiers[i].value); - buf[ptr++] = Utils::hton(_qualifiers[i].maxDelta); - } - return (id.verify(buf,ptr * sizeof(uint64_t),_signature) ? 0 : -1); + uint64_t buf[ZT_NETWORK_COM_MAX_QUALIFIERS * 3]; + unsigned int ptr = 0; + for (unsigned int i = 0; i < _qualifierCount; ++i) { + buf[ptr++] = Utils::hton(_qualifiers[i].id); + buf[ptr++] = Utils::hton(_qualifiers[i].value); + buf[ptr++] = Utils::hton(_qualifiers[i].maxDelta); + } + return (id.verify(buf, ptr * sizeof(uint64_t), _signature) ? 0 : -1); } -} // namespace ZeroTier +} // namespace ZeroTier diff --git a/node/CertificateOfMembership.hpp b/node/CertificateOfMembership.hpp index 2c289bfa..9f1409cf 100644 --- a/node/CertificateOfMembership.hpp +++ b/node/CertificateOfMembership.hpp @@ -14,21 +14,20 @@ #ifndef ZT_CERTIFICATEOFMEMBERSHIP_HPP #define ZT_CERTIFICATEOFMEMBERSHIP_HPP -#include -#include - -#include -#include -#include - +#include "Address.hpp" +#include "Buffer.hpp" #include "Constants.hpp" #include "Credential.hpp" -#include "Buffer.hpp" -#include "Address.hpp" -#include "C25519.hpp" +#include "ECC.hpp" #include "Identity.hpp" #include "Utils.hpp" +#include +#include +#include +#include +#include + /** * Maximum number of qualifiers allowed in a COM (absolute max: 65535) */ @@ -64,255 +63,275 @@ class RuntimeEnvironment; * This is a memcpy()'able structure and is safe (in a crash sense) to modify * without locks. */ -class CertificateOfMembership : public Credential -{ -public: - static inline Credential::Type credentialType() { return Credential::CREDENTIAL_TYPE_COM; } +class CertificateOfMembership : public Credential { + public: + static inline Credential::Type credentialType() + { + return Credential::CREDENTIAL_TYPE_COM; + } - /** - * Reserved qualifier IDs - * - * IDs below 1024 are reserved for use as standard IDs. Others are available - * for user-defined use. - * - * Addition of new required fields requires that code in hasRequiredFields - * be updated as well. - */ - enum ReservedId - { - /** - * Timestamp of certificate - */ - COM_RESERVED_ID_TIMESTAMP = 0, + /** + * Reserved qualifier IDs + * + * IDs below 1024 are reserved for use as standard IDs. Others are available + * for user-defined use. + * + * Addition of new required fields requires that code in hasRequiredFields + * be updated as well. + */ + enum ReservedId { + /** + * Timestamp of certificate + */ + COM_RESERVED_ID_TIMESTAMP = 0, - /** - * Network ID for which certificate was issued - */ - COM_RESERVED_ID_NETWORK_ID = 1, + /** + * Network ID for which certificate was issued + */ + COM_RESERVED_ID_NETWORK_ID = 1, - /** - * ZeroTier address to whom certificate was issued - */ - COM_RESERVED_ID_ISSUED_TO = 2 + /** + * ZeroTier address to whom certificate was issued + */ + COM_RESERVED_ID_ISSUED_TO = 2 - // IDs 3-6 reserved for full hash of identity to which this COM was issued. - }; + // IDs 3-6 reserved for full hash of identity to which this COM was issued. + }; - /** - * Create an empty certificate of membership - */ - CertificateOfMembership() : - _qualifierCount(0) {} + /** + * Create an empty certificate of membership + */ + CertificateOfMembership() : _qualifierCount(0) + { + } - /** - * Create from required fields common to all networks - * - * @param timestamp Timestamp of certificate - * @param timestampMaxDelta Maximum variation between timestamps on this net - * @param nwid Network ID - * @param issuedTo Certificate recipient - */ - CertificateOfMembership(uint64_t timestamp,uint64_t timestampMaxDelta,uint64_t nwid,const Identity &issuedTo); + /** + * Create from required fields common to all networks + * + * @param timestamp Timestamp of certificate + * @param timestampMaxDelta Maximum variation between timestamps on this net + * @param nwid Network ID + * @param issuedTo Certificate recipient + */ + CertificateOfMembership(uint64_t timestamp, uint64_t timestampMaxDelta, uint64_t nwid, const Identity& issuedTo); - /** - * Create from binary-serialized COM in buffer - * - * @param b Buffer to deserialize from - * @param startAt Position to start in buffer - */ - template - CertificateOfMembership(const Buffer &b,unsigned int startAt = 0) - { - deserialize(b,startAt); - } + /** + * Create from binary-serialized COM in buffer + * + * @param b Buffer to deserialize from + * @param startAt Position to start in buffer + */ + template CertificateOfMembership(const Buffer& b, unsigned int startAt = 0) + { + deserialize(b, startAt); + } - /** - * @return True if there's something here - */ - inline operator bool() const { return (_qualifierCount != 0); } + /** + * @return True if there's something here + */ + inline operator bool() const + { + return (_qualifierCount != 0); + } - /** - * @return Credential ID, always 0 for COMs - */ - inline uint32_t id() const { return 0; } + /** + * @return Credential ID, always 0 for COMs + */ + inline uint32_t id() const + { + return 0; + } - /** - * @return Timestamp for this cert and maximum delta for timestamp - */ - inline int64_t timestamp() const - { - for(unsigned int i=0;i<_qualifierCount;++i) { - if (_qualifiers[i].id == COM_RESERVED_ID_TIMESTAMP) { - return _qualifiers[i].value; - } - } - return 0; - } + /** + * @return Timestamp for this cert and maximum delta for timestamp + */ + inline int64_t timestamp() const + { + for (unsigned int i = 0; i < _qualifierCount; ++i) { + if (_qualifiers[i].id == COM_RESERVED_ID_TIMESTAMP) { + return _qualifiers[i].value; + } + } + return 0; + } - /** - * @return Address to which this cert was issued - */ - inline Address issuedTo() const - { - for(unsigned int i=0;i<_qualifierCount;++i) { - if (_qualifiers[i].id == COM_RESERVED_ID_ISSUED_TO) { - return Address(_qualifiers[i].value); - } - } - return Address(); - } + /** + * @return Address to which this cert was issued + */ + inline Address issuedTo() const + { + for (unsigned int i = 0; i < _qualifierCount; ++i) { + if (_qualifiers[i].id == COM_RESERVED_ID_ISSUED_TO) { + return Address(_qualifiers[i].value); + } + } + return Address(); + } - /** - * @return Network ID for which this cert was issued - */ - inline uint64_t networkId() const - { - for(unsigned int i=0;i<_qualifierCount;++i) { - if (_qualifiers[i].id == COM_RESERVED_ID_NETWORK_ID) { - return _qualifiers[i].value; - } - } - return 0ULL; - } + /** + * @return Network ID for which this cert was issued + */ + inline uint64_t networkId() const + { + for (unsigned int i = 0; i < _qualifierCount; ++i) { + if (_qualifiers[i].id == COM_RESERVED_ID_NETWORK_ID) { + return _qualifiers[i].value; + } + } + return 0ULL; + } - /** - * Compare two certificates for parameter agreement - * - * This compares this certificate with the other and returns true if all - * parameters in this cert are present in the other and if they agree to - * within this cert's max delta value for each given parameter. - * - * Tuples present in other but not in this cert are ignored, but any - * tuples present in this cert but not in other result in 'false'. - * - * @param other Cert to compare with - * @param otherIdentity Identity of other node - * @return True if certs agree and 'other' may be communicated with - */ - bool agreesWith(const CertificateOfMembership &other, const Identity &otherIdentity) const; + /** + * Compare two certificates for parameter agreement + * + * This compares this certificate with the other and returns true if all + * parameters in this cert are present in the other and if they agree to + * within this cert's max delta value for each given parameter. + * + * Tuples present in other but not in this cert are ignored, but any + * tuples present in this cert but not in other result in 'false'. + * + * @param other Cert to compare with + * @param otherIdentity Identity of other node + * @return True if certs agree and 'other' may be communicated with + */ + bool agreesWith(const CertificateOfMembership& other, const Identity& otherIdentity) const; - /** - * Sign this certificate - * - * @param with Identity to sign with, must include private key - * @return True if signature was successful - */ - bool sign(const Identity &with); + /** + * Sign this certificate + * + * @param with Identity to sign with, must include private key + * @return True if signature was successful + */ + bool sign(const Identity& with); - /** - * Verify this COM and its signature - * - * @param RR Runtime environment for looking up peers - * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call - * @return 0 == OK, 1 == waiting for WHOIS, -1 == BAD signature or credential - */ - int verify(const RuntimeEnvironment *RR,void *tPtr) const; + /** + * Verify this COM and its signature + * + * @param RR Runtime environment for looking up peers + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call + * @return 0 == OK, 1 == waiting for WHOIS, -1 == BAD signature or credential + */ + int verify(const RuntimeEnvironment* RR, void* tPtr) const; - /** - * @return True if signed - */ - inline bool isSigned() const { return (_signedBy); } + /** + * @return True if signed + */ + inline bool isSigned() const + { + return (_signedBy); + } - /** - * @return Address that signed this certificate or null address if none - */ - inline const Address &signedBy() const { return _signedBy; } + /** + * @return Address that signed this certificate or null address if none + */ + inline const Address& signedBy() const + { + return _signedBy; + } - template - inline void serialize(Buffer &b) const - { - b.append((uint8_t)1); - b.append((uint16_t)_qualifierCount); - for(unsigned int i=0;i<_qualifierCount;++i) { - b.append(_qualifiers[i].id); - b.append(_qualifiers[i].value); - b.append(_qualifiers[i].maxDelta); - } - _signedBy.appendTo(b); - if (_signedBy) { - b.append(_signature.data,ZT_C25519_SIGNATURE_LEN); - } - } + template inline void serialize(Buffer& b) const + { + b.append((uint8_t)1); + b.append((uint16_t)_qualifierCount); + for (unsigned int i = 0; i < _qualifierCount; ++i) { + b.append(_qualifiers[i].id); + b.append(_qualifiers[i].value); + b.append(_qualifiers[i].maxDelta); + } + _signedBy.appendTo(b); + if (_signedBy) { + b.append(_signature.data, ZT_ECC_SIGNATURE_LEN); + } + } - template - inline unsigned int deserialize(const Buffer &b,unsigned int startAt = 0) - { - unsigned int p = startAt; + template inline unsigned int deserialize(const Buffer& b, unsigned int startAt = 0) + { + unsigned int p = startAt; - _qualifierCount = 0; - _signedBy.zero(); + _qualifierCount = 0; + _signedBy.zero(); - if (b[p++] != 1) { - throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_INVALID_TYPE; - } + if (b[p++] != 1) { + throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_INVALID_TYPE; + } - unsigned int numq = b.template at(p); - p += sizeof(uint16_t); - uint64_t lastId = 0; - for(unsigned int i=0;i(p); - if (qid < lastId) { - throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_BAD_ENCODING; - } else { - lastId = qid; - } - if (_qualifierCount < ZT_NETWORK_COM_MAX_QUALIFIERS) { - _qualifiers[_qualifierCount].id = qid; - _qualifiers[_qualifierCount].value = b.template at(p + 8); - _qualifiers[_qualifierCount].maxDelta = b.template at(p + 16); - p += 24; - ++_qualifierCount; - } else { - throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_OVERFLOW; - } - } + unsigned int numq = b.template at(p); + p += sizeof(uint16_t); + uint64_t lastId = 0; + for (unsigned int i = 0; i < numq; ++i) { + const uint64_t qid = b.template at(p); + if (qid < lastId) { + throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_BAD_ENCODING; + } + else { + lastId = qid; + } + if (_qualifierCount < ZT_NETWORK_COM_MAX_QUALIFIERS) { + _qualifiers[_qualifierCount].id = qid; + _qualifiers[_qualifierCount].value = b.template at(p + 8); + _qualifiers[_qualifierCount].maxDelta = b.template at(p + 16); + p += 24; + ++_qualifierCount; + } + else { + throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_OVERFLOW; + } + } - _signedBy.setTo(b.field(p,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); - p += ZT_ADDRESS_LENGTH; + _signedBy.setTo(b.field(p, ZT_ADDRESS_LENGTH), ZT_ADDRESS_LENGTH); + p += ZT_ADDRESS_LENGTH; - if (_signedBy) { - memcpy(_signature.data,b.field(p,ZT_C25519_SIGNATURE_LEN),ZT_C25519_SIGNATURE_LEN); - p += ZT_C25519_SIGNATURE_LEN; - } + if (_signedBy) { + memcpy(_signature.data, b.field(p, ZT_ECC_SIGNATURE_LEN), ZT_ECC_SIGNATURE_LEN); + p += ZT_ECC_SIGNATURE_LEN; + } - return (p - startAt); - } + return (p - startAt); + } - inline bool operator==(const CertificateOfMembership &c) const - { - if (_signedBy != c._signedBy) { - return false; - } - if (_qualifierCount != c._qualifierCount) { - return false; - } - for(unsigned int i=0;i<_qualifierCount;++i) { - const _Qualifier &a = _qualifiers[i]; - const _Qualifier &b = c._qualifiers[i]; - if ((a.id != b.id)||(a.value != b.value)||(a.maxDelta != b.maxDelta)) { - return false; - } - } - return (memcmp(_signature.data,c._signature.data,ZT_C25519_SIGNATURE_LEN) == 0); - } - inline bool operator!=(const CertificateOfMembership &c) const { return (!(*this == c)); } + inline bool operator==(const CertificateOfMembership& c) const + { + if (_signedBy != c._signedBy) { + return false; + } + if (_qualifierCount != c._qualifierCount) { + return false; + } + for (unsigned int i = 0; i < _qualifierCount; ++i) { + const _Qualifier& a = _qualifiers[i]; + const _Qualifier& b = c._qualifiers[i]; + if ((a.id != b.id) || (a.value != b.value) || (a.maxDelta != b.maxDelta)) { + return false; + } + } + return (memcmp(_signature.data, c._signature.data, ZT_ECC_SIGNATURE_LEN) == 0); + } + inline bool operator!=(const CertificateOfMembership& c) const + { + return (! (*this == c)); + } -private: - struct _Qualifier - { - _Qualifier() : id(0),value(0),maxDelta(0) {} - uint64_t id; - uint64_t value; - uint64_t maxDelta; - inline bool operator<(const _Qualifier &q) const { return (id < q.id); } // sort order - }; + private: + struct _Qualifier { + _Qualifier() : id(0), value(0), maxDelta(0) + { + } + uint64_t id; + uint64_t value; + uint64_t maxDelta; + inline bool operator<(const _Qualifier& q) const + { + return (id < q.id); + } // sort order + }; - Address _signedBy; - _Qualifier _qualifiers[ZT_NETWORK_COM_MAX_QUALIFIERS]; - unsigned int _qualifierCount; - C25519::Signature _signature; + Address _signedBy; + _Qualifier _qualifiers[ZT_NETWORK_COM_MAX_QUALIFIERS]; + unsigned int _qualifierCount; + ECC::Signature _signature; }; -} // namespace ZeroTier +} // namespace ZeroTier #endif diff --git a/node/CertificateOfOwnership.cpp b/node/CertificateOfOwnership.cpp index db5b2eb0..259c3765 100644 --- a/node/CertificateOfOwnership.cpp +++ b/node/CertificateOfOwnership.cpp @@ -12,51 +12,53 @@ /****/ #include "CertificateOfOwnership.hpp" -#include "RuntimeEnvironment.hpp" + #include "Identity.hpp" -#include "Topology.hpp" -#include "Switch.hpp" #include "Network.hpp" #include "Node.hpp" +#include "RuntimeEnvironment.hpp" +#include "Switch.hpp" +#include "Topology.hpp" namespace ZeroTier { -int CertificateOfOwnership::verify(const RuntimeEnvironment *RR,void *tPtr) const +int CertificateOfOwnership::verify(const RuntimeEnvironment* RR, void* tPtr) const { - if ((!_signedBy)||(_signedBy != Network::controllerFor(_networkId))) { - return -1; - } - const Identity id(RR->topology->getIdentity(tPtr,_signedBy)); - if (!id) { - RR->sw->requestWhois(tPtr,RR->node->now(),_signedBy); - return 1; - } - try { - Buffer<(sizeof(CertificateOfOwnership) + 64)> tmp; - this->serialize(tmp,true); - return (id.verify(tmp.data(),tmp.size(),_signature) ? 0 : -1); - } catch ( ... ) { - return -1; - } + if ((! _signedBy) || (_signedBy != Network::controllerFor(_networkId))) { + return -1; + } + const Identity id(RR->topology->getIdentity(tPtr, _signedBy)); + if (! id) { + RR->sw->requestWhois(tPtr, RR->node->now(), _signedBy); + return 1; + } + try { + Buffer<(sizeof(CertificateOfOwnership) + 64)> tmp; + this->serialize(tmp, true); + return (id.verify(tmp.data(), tmp.size(), _signature) ? 0 : -1); + } + catch (...) { + return -1; + } } -bool CertificateOfOwnership::_owns(const CertificateOfOwnership::Thing &t,const void *v,unsigned int l) const +bool CertificateOfOwnership::_owns(const CertificateOfOwnership::Thing& t, const void* v, unsigned int l) const { - for(unsigned int i=0,j=_thingCount;i(v)[k] != _thingValues[i][k]) { - break; - } - ++k; - } - if (k == l) { - return true; - } - } - } - return false; + for (unsigned int i = 0, j = _thingCount; i < j; ++i) { + if (_thingTypes[i] == (uint8_t)t) { + unsigned int k = 0; + while (k < l) { + if (reinterpret_cast(v)[k] != _thingValues[i][k]) { + break; + } + ++k; + } + if (k == l) { + return true; + } + } + } + return false; } -} // namespace ZeroTier +} // namespace ZeroTier diff --git a/node/CertificateOfOwnership.hpp b/node/CertificateOfOwnership.hpp index e7b80f72..1cf3674d 100644 --- a/node/CertificateOfOwnership.hpp +++ b/node/CertificateOfOwnership.hpp @@ -14,20 +14,20 @@ #ifndef ZT_CERTIFICATEOFOWNERSHIP_HPP #define ZT_CERTIFICATEOFOWNERSHIP_HPP +#include "Address.hpp" +#include "Buffer.hpp" +#include "Constants.hpp" +#include "Credential.hpp" +#include "ECC.hpp" +#include "Identity.hpp" +#include "InetAddress.hpp" +#include "MAC.hpp" + #include #include #include #include -#include "Constants.hpp" -#include "Credential.hpp" -#include "C25519.hpp" -#include "Address.hpp" -#include "Identity.hpp" -#include "Buffer.hpp" -#include "InetAddress.hpp" -#include "MAC.hpp" - // Max things per CertificateOfOwnership #define ZT_CERTIFICATEOFOWNERSHIP_MAX_THINGS 16 @@ -41,211 +41,237 @@ class RuntimeEnvironment; /** * Certificate indicating ownership of a network identifier */ -class CertificateOfOwnership : public Credential -{ -public: - static inline Credential::Type credentialType() { return Credential::CREDENTIAL_TYPE_COO; } +class CertificateOfOwnership : public Credential { + public: + static inline Credential::Type credentialType() + { + return Credential::CREDENTIAL_TYPE_COO; + } - enum Thing - { - THING_NULL = 0, - THING_MAC_ADDRESS = 1, - THING_IPV4_ADDRESS = 2, - THING_IPV6_ADDRESS = 3 - }; + enum Thing { THING_NULL = 0, THING_MAC_ADDRESS = 1, THING_IPV4_ADDRESS = 2, THING_IPV6_ADDRESS = 3 }; - CertificateOfOwnership() - { - memset(reinterpret_cast(this),0,sizeof(CertificateOfOwnership)); - } + CertificateOfOwnership() + { + memset(reinterpret_cast(this), 0, sizeof(CertificateOfOwnership)); + } - CertificateOfOwnership(const uint64_t nwid,const int64_t ts,const Address &issuedTo,const uint32_t id) - { - memset(reinterpret_cast(this),0,sizeof(CertificateOfOwnership)); - _networkId = nwid; - _ts = ts; - _id = id; - _issuedTo = issuedTo; - } + CertificateOfOwnership(const uint64_t nwid, const int64_t ts, const Address& issuedTo, const uint32_t id) + { + memset(reinterpret_cast(this), 0, sizeof(CertificateOfOwnership)); + _networkId = nwid; + _ts = ts; + _id = id; + _issuedTo = issuedTo; + } - inline uint64_t networkId() const { return _networkId; } - inline int64_t timestamp() const { return _ts; } - inline uint32_t id() const { return _id; } - inline unsigned int thingCount() const { return (unsigned int)_thingCount; } + inline uint64_t networkId() const + { + return _networkId; + } + inline int64_t timestamp() const + { + return _ts; + } + inline uint32_t id() const + { + return _id; + } + inline unsigned int thingCount() const + { + return (unsigned int)_thingCount; + } - inline Thing thingType(const unsigned int i) const { return (Thing)_thingTypes[i]; } - inline const uint8_t *thingValue(const unsigned int i) const { return _thingValues[i]; } + inline Thing thingType(const unsigned int i) const + { + return (Thing)_thingTypes[i]; + } + inline const uint8_t* thingValue(const unsigned int i) const + { + return _thingValues[i]; + } - inline const Address &issuedTo() const { return _issuedTo; } + inline const Address& issuedTo() const + { + return _issuedTo; + } - inline bool owns(const InetAddress &ip) const - { - if (ip.ss_family == AF_INET) { - return this->_owns(THING_IPV4_ADDRESS,&(reinterpret_cast(&ip)->sin_addr.s_addr),4); - } - if (ip.ss_family == AF_INET6) { - return this->_owns(THING_IPV6_ADDRESS,reinterpret_cast(&ip)->sin6_addr.s6_addr,16); - } - return false; - } + inline bool owns(const InetAddress& ip) const + { + if (ip.ss_family == AF_INET) { + return this->_owns(THING_IPV4_ADDRESS, &(reinterpret_cast(&ip)->sin_addr.s_addr), 4); + } + if (ip.ss_family == AF_INET6) { + return this->_owns(THING_IPV6_ADDRESS, reinterpret_cast(&ip)->sin6_addr.s6_addr, 16); + } + return false; + } - inline bool owns(const MAC &mac) const - { - uint8_t tmp[6]; - mac.copyTo(tmp,6); - return this->_owns(THING_MAC_ADDRESS,tmp,6); - } + inline bool owns(const MAC& mac) const + { + uint8_t tmp[6]; + mac.copyTo(tmp, 6); + return this->_owns(THING_MAC_ADDRESS, tmp, 6); + } - inline void addThing(const InetAddress &ip) - { - if (_thingCount >= ZT_CERTIFICATEOFOWNERSHIP_MAX_THINGS) { - return; - } - if (ip.ss_family == AF_INET) { - _thingTypes[_thingCount] = THING_IPV4_ADDRESS; - memcpy(_thingValues[_thingCount],&(reinterpret_cast(&ip)->sin_addr.s_addr),4); - ++_thingCount; - } else if (ip.ss_family == AF_INET6) { - _thingTypes[_thingCount] = THING_IPV6_ADDRESS; - memcpy(_thingValues[_thingCount],reinterpret_cast(&ip)->sin6_addr.s6_addr,16); - ++_thingCount; - } - } + inline void addThing(const InetAddress& ip) + { + if (_thingCount >= ZT_CERTIFICATEOFOWNERSHIP_MAX_THINGS) { + return; + } + if (ip.ss_family == AF_INET) { + _thingTypes[_thingCount] = THING_IPV4_ADDRESS; + memcpy(_thingValues[_thingCount], &(reinterpret_cast(&ip)->sin_addr.s_addr), 4); + ++_thingCount; + } + else if (ip.ss_family == AF_INET6) { + _thingTypes[_thingCount] = THING_IPV6_ADDRESS; + memcpy(_thingValues[_thingCount], reinterpret_cast(&ip)->sin6_addr.s6_addr, 16); + ++_thingCount; + } + } - inline void addThing(const MAC &mac) - { - if (_thingCount >= ZT_CERTIFICATEOFOWNERSHIP_MAX_THINGS) { - return; - } - _thingTypes[_thingCount] = THING_MAC_ADDRESS; - mac.copyTo(_thingValues[_thingCount],6); - ++_thingCount; - } + inline void addThing(const MAC& mac) + { + if (_thingCount >= ZT_CERTIFICATEOFOWNERSHIP_MAX_THINGS) { + return; + } + _thingTypes[_thingCount] = THING_MAC_ADDRESS; + mac.copyTo(_thingValues[_thingCount], 6); + ++_thingCount; + } - /** - * @param signer Signing identity, must have private key - * @return True if signature was successful - */ - inline bool sign(const Identity &signer) - { - if (signer.hasPrivate()) { - Buffer tmp; - _signedBy = signer.address(); - this->serialize(tmp,true); - _signature = signer.sign(tmp.data(),tmp.size()); - return true; - } - return false; - } + /** + * @param signer Signing identity, must have private key + * @return True if signature was successful + */ + inline bool sign(const Identity& signer) + { + if (signer.hasPrivate()) { + Buffer tmp; + _signedBy = signer.address(); + this->serialize(tmp, true); + _signature = signer.sign(tmp.data(), tmp.size()); + return true; + } + return false; + } - /** - * @param RR Runtime environment to allow identity lookup for signedBy - * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call - * @return 0 == OK, 1 == waiting for WHOIS, -1 == BAD signature - */ - int verify(const RuntimeEnvironment *RR,void *tPtr) const; + /** + * @param RR Runtime environment to allow identity lookup for signedBy + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call + * @return 0 == OK, 1 == waiting for WHOIS, -1 == BAD signature + */ + int verify(const RuntimeEnvironment* RR, void* tPtr) const; - template - inline void serialize(Buffer &b,const bool forSign = false) const - { - if (forSign) { - b.append((uint64_t)0x7f7f7f7f7f7f7f7fULL); - } + template inline void serialize(Buffer& b, const bool forSign = false) const + { + if (forSign) { + b.append((uint64_t)0x7f7f7f7f7f7f7f7fULL); + } - b.append(_networkId); - b.append(_ts); - b.append(_flags); - b.append(_id); - b.append((uint16_t)_thingCount); - for(unsigned int i=0,j=_thingCount;i - inline unsigned int deserialize(const Buffer &b,unsigned int startAt = 0) - { - unsigned int p = startAt; + template inline unsigned int deserialize(const Buffer& b, unsigned int startAt = 0) + { + unsigned int p = startAt; - *this = CertificateOfOwnership(); + *this = CertificateOfOwnership(); - _networkId = b.template at(p); - p += 8; - _ts = b.template at(p); - p += 8; - _flags = b.template at(p); - p += 8; - _id = b.template at(p); - p += 4; - _thingCount = b.template at(p); - p += 2; - for(unsigned int i=0,j=_thingCount;i(p); + p += 8; + _ts = b.template at(p); + p += 8; + _flags = b.template at(p); + p += 8; + _id = b.template at(p); + p += 4; + _thingCount = b.template at(p); + p += 2; + for (unsigned int i = 0, j = _thingCount; i < j; ++i) { + if (i < ZT_CERTIFICATEOFOWNERSHIP_MAX_THINGS) { + _thingTypes[i] = (uint8_t)b[p++]; + memcpy(_thingValues[i], b.field(p, ZT_CERTIFICATEOFOWNERSHIP_MAX_THING_VALUE_SIZE), ZT_CERTIFICATEOFOWNERSHIP_MAX_THING_VALUE_SIZE); + p += ZT_CERTIFICATEOFOWNERSHIP_MAX_THING_VALUE_SIZE; + } + } - _issuedTo.setTo(b.field(p,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); - p += ZT_ADDRESS_LENGTH; - _signedBy.setTo(b.field(p,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); - p += ZT_ADDRESS_LENGTH; - if (b[p++] == 1) { - if (b.template at(p) != ZT_C25519_SIGNATURE_LEN) { - throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_INVALID_CRYPTOGRAPHIC_TOKEN; - } - p += 2; - memcpy(_signature.data,b.field(p,ZT_C25519_SIGNATURE_LEN),ZT_C25519_SIGNATURE_LEN); - p += ZT_C25519_SIGNATURE_LEN; - } else { - p += 2 + b.template at(p); - } + _issuedTo.setTo(b.field(p, ZT_ADDRESS_LENGTH), ZT_ADDRESS_LENGTH); + p += ZT_ADDRESS_LENGTH; + _signedBy.setTo(b.field(p, ZT_ADDRESS_LENGTH), ZT_ADDRESS_LENGTH); + p += ZT_ADDRESS_LENGTH; + if (b[p++] == 1) { + if (b.template at(p) != ZT_ECC_SIGNATURE_LEN) { + throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_INVALID_CRYPTOGRAPHIC_TOKEN; + } + p += 2; + memcpy(_signature.data, b.field(p, ZT_ECC_SIGNATURE_LEN), ZT_ECC_SIGNATURE_LEN); + p += ZT_ECC_SIGNATURE_LEN; + } + else { + p += 2 + b.template at(p); + } - p += 2 + b.template at(p); - if (p > b.size()) { - throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_OVERFLOW; - } + p += 2 + b.template at(p); + if (p > b.size()) { + throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_OVERFLOW; + } - return (p - startAt); - } + return (p - startAt); + } - // Provides natural sort order by ID - inline bool operator<(const CertificateOfOwnership &coo) const { return (_id < coo._id); } + // Provides natural sort order by ID + inline bool operator<(const CertificateOfOwnership& coo) const + { + return (_id < coo._id); + } - inline bool operator==(const CertificateOfOwnership &coo) const { return (memcmp(this,&coo,sizeof(CertificateOfOwnership)) == 0); } - inline bool operator!=(const CertificateOfOwnership &coo) const { return (memcmp(this,&coo,sizeof(CertificateOfOwnership)) != 0); } + inline bool operator==(const CertificateOfOwnership& coo) const + { + return (memcmp(this, &coo, sizeof(CertificateOfOwnership)) == 0); + } + inline bool operator!=(const CertificateOfOwnership& coo) const + { + return (memcmp(this, &coo, sizeof(CertificateOfOwnership)) != 0); + } -private: - bool _owns(const Thing &t,const void *v,unsigned int l) const; + private: + bool _owns(const Thing& t, const void* v, unsigned int l) const; - uint64_t _networkId; - int64_t _ts; - uint64_t _flags; - uint32_t _id; - uint16_t _thingCount; - uint8_t _thingTypes[ZT_CERTIFICATEOFOWNERSHIP_MAX_THINGS]; - uint8_t _thingValues[ZT_CERTIFICATEOFOWNERSHIP_MAX_THINGS][ZT_CERTIFICATEOFOWNERSHIP_MAX_THING_VALUE_SIZE]; - Address _issuedTo; - Address _signedBy; - C25519::Signature _signature; + uint64_t _networkId; + int64_t _ts; + uint64_t _flags; + uint32_t _id; + uint16_t _thingCount; + uint8_t _thingTypes[ZT_CERTIFICATEOFOWNERSHIP_MAX_THINGS]; + uint8_t _thingValues[ZT_CERTIFICATEOFOWNERSHIP_MAX_THINGS][ZT_CERTIFICATEOFOWNERSHIP_MAX_THING_VALUE_SIZE]; + Address _issuedTo; + Address _signedBy; + ECC::Signature _signature; }; -} // namespace ZeroTier +} // namespace ZeroTier #endif diff --git a/node/Constants.hpp b/node/Constants.hpp index 95f093b3..1c7acf36 100644 --- a/node/Constants.hpp +++ b/node/Constants.hpp @@ -61,8 +61,8 @@ #ifdef ZT_SSO_SUPPORTED #define ZT_SSO_ENABLED 1 #endif -#define likely(x) __builtin_expect((x),1) -#define unlikely(x) __builtin_expect((x),0) +#define likely(x) __builtin_expect((x), 1) +#define unlikely(x) __builtin_expect((x), 0) #include #ifndef __UNIX_LIKE__ #define __UNIX_LIKE__ @@ -85,9 +85,9 @@ #endif #include #ifndef __BYTE_ORDER -#define __BYTE_ORDER _BYTE_ORDER +#define __BYTE_ORDER _BYTE_ORDER #define __LITTLE_ENDIAN _LITTLE_ENDIAN -#define __BIG_ENDIAN _BIG_ENDIAN +#define __BIG_ENDIAN _BIG_ENDIAN #endif #endif @@ -106,25 +106,25 @@ #pragma warning(disable : 4101) #undef __UNIX_LIKE__ #undef __BSD__ -#include #include +#include #endif #ifdef __NetBSD__ #ifndef RTF_MULTICAST -#define RTF_MULTICAST 0x20000000 +#define RTF_MULTICAST 0x20000000 #endif #endif #if (defined(__amd64) || defined(__amd64__) || defined(__x86_64) || defined(__x86_64__) || defined(__AMD64) || defined(__AMD64__) || defined(_M_X64)) #define ZT_ARCH_X64 1 -#include #include #include +#include #endif #if (defined(__ARM_NEON) || defined(__ARM_NEON__) || defined(ZT_ARCH_ARM_HAS_NEON)) -#if (defined(__APPLE__) && !defined(__LP64__)) || (defined(__ANDROID__) && defined(__arm__)) +#if (defined(__APPLE__) && ! defined(__LP64__)) || (defined(__ANDROID__) && defined(__arm__)) #ifdef ZT_ARCH_ARM_HAS_NEON #undef ZT_ARCH_ARM_HAS_NEON #endif @@ -145,7 +145,8 @@ #endif // Define ZT_NO_TYPE_PUNNING to disable reckless casts on anything other than x86/x64. -#if (!(defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64) || defined(_M_AMD64) || defined(_M_X64) || defined(i386) || defined(__i386) || defined(__i386__) || defined(__i486__) || defined(__i586__) || defined(__i686__) || defined(_M_IX86) || defined(__X86__) || defined(_X86_) || defined(__I86__) || defined(__INTEL__) || defined(__386))) +#if (! (defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64) || defined(_M_AMD64) || defined(_M_X64) || defined(i386) || defined(__i386) || defined(__i386__) || defined(__i486__) || defined(__i586__) \ + || defined(__i686__) || defined(_M_IX86) || defined(__X86__) || defined(_X86_) || defined(__I86__) || defined(__INTEL__) || defined(__386))) #ifndef ZT_NO_TYPE_PUNNING #define ZT_NO_TYPE_PUNNING 1 #endif @@ -157,23 +158,23 @@ #endif // Assume little endian if not defined -#if (defined(__APPLE__) || defined(__WINDOWS__)) && (!defined(__BYTE_ORDER)) +#if (defined(__APPLE__) || defined(__WINDOWS__)) && (! defined(__BYTE_ORDER)) #undef __BYTE_ORDER #undef __LITTLE_ENDIAN #undef __BIG_ENDIAN -#define __BIG_ENDIAN 4321 +#define __BIG_ENDIAN 4321 #define __LITTLE_ENDIAN 1234 -#define __BYTE_ORDER 1234 +#define __BYTE_ORDER 1234 #endif #ifdef __WINDOWS__ -#define ZT_PATH_SEPARATOR '\\' +#define ZT_PATH_SEPARATOR '\\' #define ZT_PATH_SEPARATOR_S "\\" -#define ZT_EOL_S "\r\n" +#define ZT_EOL_S "\r\n" #else -#define ZT_PATH_SEPARATOR '/' +#define ZT_PATH_SEPARATOR '/' #define ZT_PATH_SEPARATOR_S "/" -#define ZT_EOL_S "\n" +#define ZT_EOL_S "\n" #endif #ifndef __BYTE_ORDER @@ -182,10 +183,10 @@ #if (defined(__GNUC__) && (__GNUC__ >= 3)) || (defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 800)) || defined(__clang__) #ifndef likely -#define likely(x) __builtin_expect((x),1) +#define likely(x) __builtin_expect((x), 1) #endif #ifndef unlikely -#define unlikely(x) __builtin_expect((x),0) +#define unlikely(x) __builtin_expect((x), 0) #endif #else #ifndef likely @@ -197,43 +198,43 @@ #endif #ifdef __WINDOWS__ -#define ZT_PACKED_STRUCT(D) __pragma(pack(push,1)) D __pragma(pack(pop)) +#define ZT_PACKED_STRUCT(D) __pragma(pack(push, 1)) D __pragma(pack(pop)) #else #define ZT_PACKED_STRUCT(D) D __attribute__((packed)) #endif #if defined(_WIN32) -#define ZT_PLATFORM_NAME "windows" // Windows +#define ZT_PLATFORM_NAME "windows" // Windows #elif defined(_WIN64) -#define ZT_PLATFORM_NAME "windows" // Windows +#define ZT_PLATFORM_NAME "windows" // Windows #elif defined(__CYGWIN__) -#define ZT_PLATFORM_NAME "windows" // Windows (Cygwin POSIX under Microsoft Window) +#define ZT_PLATFORM_NAME "windows" // Windows (Cygwin POSIX under Microsoft Window) #elif defined(__ANDROID__) -#define ZT_PLATFORM_NAME "android" // Android (implies Linux, so it must come first) +#define ZT_PLATFORM_NAME "android" // Android (implies Linux, so it must come first) #elif defined(__linux__) -#define ZT_PLATFORM_NAME "linux" // Debian, Ubuntu, Gentoo, Fedora, openSUSE, RedHat, Centos and other -#elif defined(__unix__) || !defined(__APPLE__) && defined(__MACH__) +#define ZT_PLATFORM_NAME "linux" // Debian, Ubuntu, Gentoo, Fedora, openSUSE, RedHat, Centos and other +#elif defined(__unix__) || ! defined(__APPLE__) && defined(__MACH__) #include #if defined(BSD) -#define ZT_PLATFORM_NAME "bsd" // FreeBSD, NetBSD, OpenBSD, DragonFly BSD +#define ZT_PLATFORM_NAME "bsd" // FreeBSD, NetBSD, OpenBSD, DragonFly BSD #endif #elif defined(__hpux) -#define ZT_PLATFORM_NAME "hp-ux" // HP-UX +#define ZT_PLATFORM_NAME "hp-ux" // HP-UX #elif defined(_AIX) -#define ZT_PLATFORM_NAME "aix" // IBM AIX -#elif defined(__APPLE__) && defined(__MACH__) // Apple OSX and iOS (Darwin) +#define ZT_PLATFORM_NAME "aix" // IBM AIX +#elif defined(__APPLE__) && defined(__MACH__) // Apple OSX and iOS (Darwin) #include #if defined(TARGET_IPHONE_SIMULATOR) && TARGET_IPHONE_SIMULATOR == 1 -#define ZT_PLATFORM_NAME "ios_sim" // Apple iOS +#define ZT_PLATFORM_NAME "ios_sim" // Apple iOS #elif defined(TARGET_OS_IPAD) && TARGET_OS_IPAD == 1 #define ZT_PLATFORM_NAME "ios_ipad" #elif defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE == 1 -#define ZT_PLATFORM_NAME "ios_iphone" // Apple iOS +#define ZT_PLATFORM_NAME "ios_iphone" // Apple iOS #elif defined(TARGET_OS_MAC) && TARGET_OS_MAC == 1 -#define ZT_PLATFORM_NAME "macos" // Apple OSX +#define ZT_PLATFORM_NAME "macos" // Apple OSX #endif #elif defined(__sun) && defined(__SVR4) -#define ZT_PLATFORM_NAME "solaris" // Oracle Solaris, Open Indiana +#define ZT_PLATFORM_NAME "solaris" // Oracle Solaris, Open Indiana #else #define ZT_PLATFORM_NAME "unknown" #endif @@ -255,7 +256,7 @@ #define ZT_ARCH_NAME "mips" #elif defined(__riscv) || defined(__riscv_xlen) #define ZT_ARCH_NAME "riscv" -#elif defined(__powerpc__) || defined(__powerpc64__) || defined(__ppc__) || defined(__ppc64__) || defined (_M_PPC) +#elif defined(__powerpc__) || defined(__powerpc64__) || defined(__ppc__) || defined(__ppc64__) || defined(_M_PPC) #define ZT_ARCH_NAME "powerpc" #elif defined(__s390__) || defined(__s390x__) || defined(__zarch__) #define ZT_ARCH_NAME "s390" @@ -580,23 +581,23 @@ /** * Drainage constants for VERB_ECHO rate-limiters */ -#define ZT_ECHO_CUTOFF_LIMIT ((1000 / ZT_CORE_TIMER_TASK_GRANULARITY) * ZT_MAX_PEER_NETWORK_PATHS) +#define ZT_ECHO_CUTOFF_LIMIT ((1000 / ZT_CORE_TIMER_TASK_GRANULARITY) * ZT_MAX_PEER_NETWORK_PATHS) #define ZT_ECHO_DRAINAGE_DIVISOR (1000 / ZT_ECHO_CUTOFF_LIMIT) /** * Drainage constants for VERB_QOS rate-limiters */ -#define ZT_QOS_CUTOFF_LIMIT ((1000 / ZT_CORE_TIMER_TASK_GRANULARITY) * ZT_MAX_PEER_NETWORK_PATHS) +#define ZT_QOS_CUTOFF_LIMIT ((1000 / ZT_CORE_TIMER_TASK_GRANULARITY) * ZT_MAX_PEER_NETWORK_PATHS) #define ZT_QOS_DRAINAGE_DIVISOR (1000 / ZT_QOS_CUTOFF_LIMIT) /** * Drainage constants for VERB_ACK rate-limiters */ -#define ZT_ACK_CUTOFF_LIMIT 128 +#define ZT_ACK_CUTOFF_LIMIT 128 #define ZT_ACK_DRAINAGE_DIVISOR (1000 / ZT_ACK_CUTOFF_LIMIT) #define ZT_BOND_DEFAULT_REFRACTORY_PERIOD 8000 -#define ZT_BOND_MAX_REFRACTORY_PERIOD 600000 +#define ZT_BOND_MAX_REFRACTORY_PERIOD 600000 /** * Maximum number of direct path pushes within cutoff time @@ -632,7 +633,6 @@ */ #define ZT_PEER_GENERAL_RATE_LIMIT 1000 - /** * Minimum allowed amount of time between flow/path optimizations (anti-flapping) */ @@ -754,14 +754,14 @@ #define ZT_THREAD_MIN_STACK_SIZE 1048576 // Exceptions thrown in core ZT code -#define ZT_EXCEPTION_OUT_OF_BOUNDS 100 -#define ZT_EXCEPTION_OUT_OF_MEMORY 101 -#define ZT_EXCEPTION_PRIVATE_KEY_REQUIRED 102 -#define ZT_EXCEPTION_INVALID_ARGUMENT 103 -#define ZT_EXCEPTION_INVALID_IDENTITY 104 -#define ZT_EXCEPTION_INVALID_SERIALIZED_DATA_INVALID_TYPE 200 -#define ZT_EXCEPTION_INVALID_SERIALIZED_DATA_OVERFLOW 201 +#define ZT_EXCEPTION_OUT_OF_BOUNDS 100 +#define ZT_EXCEPTION_OUT_OF_MEMORY 101 +#define ZT_EXCEPTION_PRIVATE_KEY_REQUIRED 102 +#define ZT_EXCEPTION_INVALID_ARGUMENT 103 +#define ZT_EXCEPTION_INVALID_IDENTITY 104 +#define ZT_EXCEPTION_INVALID_SERIALIZED_DATA_INVALID_TYPE 200 +#define ZT_EXCEPTION_INVALID_SERIALIZED_DATA_OVERFLOW 201 #define ZT_EXCEPTION_INVALID_SERIALIZED_DATA_INVALID_CRYPTOGRAPHIC_TOKEN 202 -#define ZT_EXCEPTION_INVALID_SERIALIZED_DATA_BAD_ENCODING 203 +#define ZT_EXCEPTION_INVALID_SERIALIZED_DATA_BAD_ENCODING 203 #endif diff --git a/node/Credential.hpp b/node/Credential.hpp index 7fb98ba7..4515d2f5 100644 --- a/node/Credential.hpp +++ b/node/Credential.hpp @@ -14,39 +14,26 @@ #ifndef ZT_CREDENTIAL_HPP #define ZT_CREDENTIAL_HPP -#include -#include -#include - -#include -#include -#include -#include - -#include "Constants.hpp" - namespace ZeroTier { /** * Base class for credentials */ -class Credential -{ -public: - /** - * Do not change type code IDs -- these are used in Revocation objects and elsewhere - */ - enum Type - { - CREDENTIAL_TYPE_NULL = 0, - CREDENTIAL_TYPE_COM = 1, // CertificateOfMembership - CREDENTIAL_TYPE_CAPABILITY = 2, - CREDENTIAL_TYPE_TAG = 3, - CREDENTIAL_TYPE_COO = 4, // CertificateOfOwnership - CREDENTIAL_TYPE_REVOCATION = 6 - }; +class Credential { + public: + /** + * Do not change type code IDs -- these are used in Revocation objects and elsewhere + */ + enum Type { + CREDENTIAL_TYPE_NULL = 0, + CREDENTIAL_TYPE_COM = 1, // CertificateOfMembership + CREDENTIAL_TYPE_CAPABILITY = 2, + CREDENTIAL_TYPE_TAG = 3, + CREDENTIAL_TYPE_COO = 4, // CertificateOfOwnership + CREDENTIAL_TYPE_REVOCATION = 6 + }; }; -} // namespace ZeroTier +} // namespace ZeroTier #endif diff --git a/node/DNS.hpp b/node/DNS.hpp index 3c28c69f..0c814ef5 100644 --- a/node/DNS.hpp +++ b/node/DNS.hpp @@ -13,45 +13,43 @@ #ifndef ZT_DNS_HPP #define ZT_DNS_HPP +#include "../include/ZeroTierOne.h" +#include "Buffer.hpp" +#include "InetAddress.hpp" + #include #include #include -#include "Buffer.hpp" -#include "InetAddress.hpp" -#include "../include/ZeroTierOne.h" - namespace ZeroTier { /** * DNS data serialization methods */ class DNS { -public: - template - static inline void serializeDNS(Buffer &b, const ZT_VirtualNetworkDNS *dns) + public: + template static inline void serializeDNS(Buffer& b, const ZT_VirtualNetworkDNS* dns) { b.append(dns->domain, 128); - for(unsigned int j = 0; j < ZT_MAX_DNS_SERVERS; ++j) { + for (unsigned int j = 0; j < ZT_MAX_DNS_SERVERS; ++j) { InetAddress tmp(dns->server_addr[j]); tmp.serialize(b); } } - template - static inline void deserializeDNS(const Buffer &b, unsigned int &p, ZT_VirtualNetworkDNS *dns) + template static inline void deserializeDNS(const Buffer& b, unsigned int& p, ZT_VirtualNetworkDNS* dns) { - char *d = (char*)b.data()+p; + char* d = (char*)b.data() + p; memset(dns, 0, sizeof(ZT_VirtualNetworkDNS)); memcpy(dns->domain, d, 128); dns->domain[127] = 0; p += 128; for (unsigned int j = 0; j < ZT_MAX_DNS_SERVERS; ++j) { - p += reinterpret_cast(&(dns->server_addr[j]))->deserialize(b, p); + p += reinterpret_cast(&(dns->server_addr[j]))->deserialize(b, p); } } }; -} +} // namespace ZeroTier -#endif // ZT_DNS_HPP +#endif // ZT_DNS_HPP diff --git a/node/Dictionary.hpp b/node/Dictionary.hpp index 746c2b85..7c3f7870 100644 --- a/node/Dictionary.hpp +++ b/node/Dictionary.hpp @@ -14,10 +14,10 @@ #ifndef ZT_DICTIONARY_HPP #define ZT_DICTIONARY_HPP +#include "Address.hpp" +#include "Buffer.hpp" #include "Constants.hpp" #include "Utils.hpp" -#include "Buffer.hpp" -#include "Address.hpp" #include @@ -45,435 +45,462 @@ namespace ZeroTier { * * @tparam C Dictionary max capacity in bytes */ -template -class Dictionary -{ -public: - Dictionary() { memset(_d,0,sizeof(_d)); } - Dictionary(const char *s) { this->load(s); } - Dictionary(const char *s,unsigned int len) - { - for(unsigned int i=0;i class Dictionary { + public: + Dictionary() + { + memset(_d, 0, sizeof(_d)); + } + Dictionary(const char* s) + { + this->load(s); + } + Dictionary(const char* s, unsigned int len) + { + for (unsigned int i = 0; i < C; ++i) { + if ((s) && (i < len)) { + if (! (_d[i] = *s)) { + s = (const char*)0; + } + else { + ++s; + } + } + else { + _d[i] = (char)0; + } + } + _d[C - 1] = (char)0; + } + Dictionary(const Dictionary& d) + { + memcpy(_d, d._d, C); + } - inline Dictionary &operator=(const Dictionary &d) - { - memcpy(_d,d._d,C); - return *this; - } + inline Dictionary& operator=(const Dictionary& d) + { + memcpy(_d, d._d, C); + return *this; + } - inline operator bool() const { return (_d[0] != 0); } + inline operator bool() const + { + return (_d[0] != 0); + } - /** - * Load a dictionary from a C-string - * - * @param s Dictionary in string form - * @return False if 's' was longer than our capacity - */ - inline bool load(const char *s) - { - for(unsigned int i=0;i - inline bool get(const char *key,Buffer &dest) const - { - const int r = this->get(key,const_cast(reinterpret_cast(dest.data())),BC); - if (r >= 0) { - dest.setSize((unsigned int)r); - return true; - } else { - dest.clear(); - return false; - } - } + /** + * Get the contents of a key into a buffer + * + * @param key Key to get + * @param dest Destination buffer + * @return True if key was found (if false, dest will be empty) + * @tparam BC Buffer capacity (usually inferred) + */ + template inline bool get(const char* key, Buffer& dest) const + { + const int r = this->get(key, const_cast(reinterpret_cast(dest.data())), BC); + if (r >= 0) { + dest.setSize((unsigned int)r); + return true; + } + else { + dest.clear(); + return false; + } + } - /** - * Get a boolean value - * - * @param key Key to look up - * @param dfl Default value if not found in dictionary - * @return Boolean value of key or 'dfl' if not found - */ - bool getB(const char *key,bool dfl = false) const - { - char tmp[4]; - if (this->get(key,tmp,sizeof(tmp)) >= 0) { - return ((*tmp == '1')||(*tmp == 't')||(*tmp == 'T')); - } - return dfl; - } + /** + * Get a boolean value + * + * @param key Key to look up + * @param dfl Default value if not found in dictionary + * @return Boolean value of key or 'dfl' if not found + */ + bool getB(const char* key, bool dfl = false) const + { + char tmp[4]; + if (this->get(key, tmp, sizeof(tmp)) >= 0) { + return ((*tmp == '1') || (*tmp == 't') || (*tmp == 'T')); + } + return dfl; + } - /** - * Get an unsigned int64 stored as hex in the dictionary - * - * @param key Key to look up - * @param dfl Default value or 0 if unspecified - * @return Decoded hex UInt value or 'dfl' if not found - */ - inline uint64_t getUI(const char *key,uint64_t dfl = 0) const - { - char tmp[128]; - if (this->get(key,tmp,sizeof(tmp)) >= 1) { - return Utils::hexStrToU64(tmp); - } - return dfl; - } + /** + * Get an unsigned int64 stored as hex in the dictionary + * + * @param key Key to look up + * @param dfl Default value or 0 if unspecified + * @return Decoded hex UInt value or 'dfl' if not found + */ + inline uint64_t getUI(const char* key, uint64_t dfl = 0) const + { + char tmp[128]; + if (this->get(key, tmp, sizeof(tmp)) >= 1) { + return Utils::hexStrToU64(tmp); + } + return dfl; + } - /** - * Get an unsigned int64 stored as hex in the dictionary - * - * @param key Key to look up - * @param dfl Default value or 0 if unspecified - * @return Decoded hex UInt value or 'dfl' if not found - */ - inline int64_t getI(const char *key,int64_t dfl = 0) const - { - char tmp[128]; - if (this->get(key,tmp,sizeof(tmp)) >= 1) { - return Utils::hexStrTo64(tmp); - } - return dfl; - } + /** + * Get an unsigned int64 stored as hex in the dictionary + * + * @param key Key to look up + * @param dfl Default value or 0 if unspecified + * @return Decoded hex UInt value or 'dfl' if not found + */ + inline int64_t getI(const char* key, int64_t dfl = 0) const + { + char tmp[128]; + if (this->get(key, tmp, sizeof(tmp)) >= 1) { + return Utils::hexStrTo64(tmp); + } + return dfl; + } - /** - * Add a new key=value pair - * - * If the key is already present this will append another, but the first - * will always be returned by get(). This is not checked. If you want to - * ensure a key is not present use erase() first. - * - * Use the vlen parameter to add binary values. Nulls will be escaped. - * - * @param key Key -- nulls, CR/LF, and equals (=) are illegal characters - * @param value Value to set - * @param vlen Length of value in bytes or -1 to treat value[] as a C-string and look for terminating 0 - * @return True if there was enough room to add this key=value pair - */ - inline bool add(const char *key,const char *value,int vlen = -1) - { - for(unsigned int i=0;i 0) { - _d[j++] = (char)10; - if (j == C) { - _d[i] = (char)0; - return false; - } - } + if (j > 0) { + _d[j++] = (char)10; + if (j == C) { + _d[i] = (char)0; + return false; + } + } - const char *p = key; - while (*p) { - _d[j++] = *(p++); - if (j == C) { - _d[i] = (char)0; - return false; - } - } + const char* p = key; + while (*p) { + _d[j++] = *(p++); + if (j == C) { + _d[i] = (char)0; + return false; + } + } - _d[j++] = '='; - if (j == C) { - _d[i] = (char)0; - return false; - } + _d[j++] = '='; + if (j == C) { + _d[i] = (char)0; + return false; + } - p = value; - int k = 0; - while ( ((vlen < 0)&&(*p)) || (k < vlen) ) { - switch(*p) { - case 0: - case 13: - case 10: - case '\\': - case '=': - _d[j++] = '\\'; - if (j == C) { - _d[i] = (char)0; - return false; - } - switch(*p) { - case 0: - _d[j++] = '0'; - break; - case 13: - _d[j++] = 'r'; - break; - case 10: - _d[j++] = 'n'; - break; - case '\\': - _d[j++] = '\\'; - break; - case '=': - _d[j++] = 'e'; - break; - } - if (j == C) { - _d[i] = (char)0; - return false; - } - break; - default: - _d[j++] = *p; - if (j == C) { - _d[i] = (char)0; - return false; - } - break; - } - ++p; - ++k; - } + p = value; + int k = 0; + while (((vlen < 0) && (*p)) || (k < vlen)) { + switch (*p) { + case 0: + case 13: + case 10: + case '\\': + case '=': + _d[j++] = '\\'; + if (j == C) { + _d[i] = (char)0; + return false; + } + switch (*p) { + case 0: + _d[j++] = '0'; + break; + case 13: + _d[j++] = 'r'; + break; + case 10: + _d[j++] = 'n'; + break; + case '\\': + _d[j++] = '\\'; + break; + case '=': + _d[j++] = 'e'; + break; + } + if (j == C) { + _d[i] = (char)0; + return false; + } + break; + default: + _d[j++] = *p; + if (j == C) { + _d[i] = (char)0; + return false; + } + break; + } + ++p; + ++k; + } - _d[j] = (char)0; + _d[j] = (char)0; - return true; - } - } - return false; - } + return true; + } + } + return false; + } - /** - * Add a boolean as a '1' or a '0' - */ - inline bool add(const char *key,bool value) - { - return this->add(key,(value) ? "1" : "0",1); - } + /** + * Add a boolean as a '1' or a '0' + */ + inline bool add(const char* key, bool value) + { + return this->add(key, (value) ? "1" : "0", 1); + } - /** - * Add a 64-bit integer (unsigned) as a hex value - */ - inline bool add(const char *key,uint64_t value) - { - char tmp[32]; - return this->add(key,Utils::hex(value,tmp),-1); - } + /** + * Add a 64-bit integer (unsigned) as a hex value + */ + inline bool add(const char* key, uint64_t value) + { + char tmp[32]; + return this->add(key, Utils::hex(value, tmp), -1); + } - /** - * Add a 64-bit integer (unsigned) as a hex value - */ - inline bool add(const char *key,int64_t value) - { - char tmp[32]; - if (value >= 0) { - return this->add(key,Utils::hex((uint64_t)value,tmp),-1); - } else { - tmp[0] = '-'; - return this->add(key,Utils::hex((uint64_t)(value * -1),tmp+1),-1); - } - } + /** + * Add a 64-bit integer (unsigned) as a hex value + */ + inline bool add(const char* key, int64_t value) + { + char tmp[32]; + if (value >= 0) { + return this->add(key, Utils::hex((uint64_t)value, tmp), -1); + } + else { + tmp[0] = '-'; + return this->add(key, Utils::hex((uint64_t)(value * -1), tmp + 1), -1); + } + } - /** - * Add a 64-bit integer (unsigned) as a hex value - */ - inline bool add(const char *key,const Address &a) - { - char tmp[32]; - return this->add(key,Utils::hex(a.toInt(),tmp),-1); - } + /** + * Add a 64-bit integer (unsigned) as a hex value + */ + inline bool add(const char* key, const Address& a) + { + char tmp[32]; + return this->add(key, Utils::hex(a.toInt(), tmp), -1); + } - /** - * Add a binary buffer's contents as a value - * - * @tparam BC Buffer capacity (usually inferred) - */ - template - inline bool add(const char *key,const Buffer &value) - { - return this->add(key,(const char *)value.data(),(int)value.size()); - } + /** + * Add a binary buffer's contents as a value + * + * @tparam BC Buffer capacity (usually inferred) + */ + template inline bool add(const char* key, const Buffer& value) + { + return this->add(key, (const char*)value.data(), (int)value.size()); + } - /** - * @param key Key to check - * @return True if key is present - */ - inline bool contains(const char *key) const - { - char tmp[2]; - return (this->get(key,tmp,2) >= 0); - } + /** + * @param key Key to check + * @return True if key is present + */ + inline bool contains(const char* key) const + { + char tmp[2]; + return (this->get(key, tmp, 2) >= 0); + } - /** - * @return Value of C template parameter - */ - inline unsigned int capacity() const { return C; } + /** + * @return Value of C template parameter + */ + inline unsigned int capacity() const + { + return C; + } - inline const char *data() const { return _d; } - inline char *unsafeData() { return _d; } + inline const char* data() const + { + return _d; + } + inline char* unsafeData() + { + return _d; + } -private: - char _d[C]; + private: + char _d[C]; }; -} // namespace ZeroTier +} // namespace ZeroTier #endif diff --git a/node/ECC.cpp b/node/ECC.cpp new file mode 100644 index 00000000..60415f53 --- /dev/null +++ b/node/ECC.cpp @@ -0,0 +1,2581 @@ +/* +Matthew Dempsky +Public domain. +Derived from public domain code by D. J. Bernstein. +*/ + +// Modified very slightly for ZeroTier One by Adam Ierymenko +// This code remains in the public domain. + +#include "ECC.hpp" + +#include "SHA512.hpp" + +#include +#include + +#ifdef __WINDOWS__ +#pragma warning(disable : 4146) +#endif + +#ifdef __GNUC__ +#pragma GCC diagnostic ignored "-Wunused-function" +#endif + +namespace { + +#define crypto_int32 int32_t +#define crypto_uint32 uint32_t +#define crypto_int64 int64_t +#define crypto_uint64 uint64_t +#define crypto_hash_sha512_BYTES 64 + +////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + +typedef uint8_t u8; +typedef int32_t s32; +typedef int64_t limb; + +static inline void fsum(limb* output, const limb* in) +{ + unsigned i; + for (i = 0; i < 10; i += 2) { + output[0 + i] = output[0 + i] + in[0 + i]; + output[1 + i] = output[1 + i] + in[1 + i]; + } +} + +static inline void fdifference(limb* output, const limb* in) +{ + unsigned i; + for (i = 0; i < 10; ++i) { + output[i] = in[i] - output[i]; + } +} + +static inline void fscalar_product(limb* output, const limb* in, const limb scalar) +{ + unsigned i; + for (i = 0; i < 10; ++i) { + output[i] = in[i] * scalar; + } +} + +static inline void fproduct(limb* output, const limb* in2, const limb* in) +{ + output[0] = ((limb)((s32)in2[0])) * ((s32)in[0]); + output[1] = ((limb)((s32)in2[0])) * ((s32)in[1]) + ((limb)((s32)in2[1])) * ((s32)in[0]); + output[2] = 2 * ((limb)((s32)in2[1])) * ((s32)in[1]) + ((limb)((s32)in2[0])) * ((s32)in[2]) + ((limb)((s32)in2[2])) * ((s32)in[0]); + output[3] = ((limb)((s32)in2[1])) * ((s32)in[2]) + ((limb)((s32)in2[2])) * ((s32)in[1]) + ((limb)((s32)in2[0])) * ((s32)in[3]) + ((limb)((s32)in2[3])) * ((s32)in[0]); + output[4] = ((limb)((s32)in2[2])) * ((s32)in[2]) + 2 * (((limb)((s32)in2[1])) * ((s32)in[3]) + ((limb)((s32)in2[3])) * ((s32)in[1])) + ((limb)((s32)in2[0])) * ((s32)in[4]) + ((limb)((s32)in2[4])) * ((s32)in[0]); + output[5] = + ((limb)((s32)in2[2])) * ((s32)in[3]) + ((limb)((s32)in2[3])) * ((s32)in[2]) + ((limb)((s32)in2[1])) * ((s32)in[4]) + ((limb)((s32)in2[4])) * ((s32)in[1]) + ((limb)((s32)in2[0])) * ((s32)in[5]) + ((limb)((s32)in2[5])) * ((s32)in[0]); + output[6] = 2 * (((limb)((s32)in2[3])) * ((s32)in[3]) + ((limb)((s32)in2[1])) * ((s32)in[5]) + ((limb)((s32)in2[5])) * ((s32)in[1])) + ((limb)((s32)in2[2])) * ((s32)in[4]) + ((limb)((s32)in2[4])) * ((s32)in[2]) + + ((limb)((s32)in2[0])) * ((s32)in[6]) + ((limb)((s32)in2[6])) * ((s32)in[0]); + output[7] = ((limb)((s32)in2[3])) * ((s32)in[4]) + ((limb)((s32)in2[4])) * ((s32)in[3]) + ((limb)((s32)in2[2])) * ((s32)in[5]) + ((limb)((s32)in2[5])) * ((s32)in[2]) + ((limb)((s32)in2[1])) * ((s32)in[6]) + + ((limb)((s32)in2[6])) * ((s32)in[1]) + ((limb)((s32)in2[0])) * ((s32)in[7]) + ((limb)((s32)in2[7])) * ((s32)in[0]); + output[8] = ((limb)((s32)in2[4])) * ((s32)in[4]) + 2 * (((limb)((s32)in2[3])) * ((s32)in[5]) + ((limb)((s32)in2[5])) * ((s32)in[3]) + ((limb)((s32)in2[1])) * ((s32)in[7]) + ((limb)((s32)in2[7])) * ((s32)in[1])) + + ((limb)((s32)in2[2])) * ((s32)in[6]) + ((limb)((s32)in2[6])) * ((s32)in[2]) + ((limb)((s32)in2[0])) * ((s32)in[8]) + ((limb)((s32)in2[8])) * ((s32)in[0]); + output[9] = ((limb)((s32)in2[4])) * ((s32)in[5]) + ((limb)((s32)in2[5])) * ((s32)in[4]) + ((limb)((s32)in2[3])) * ((s32)in[6]) + ((limb)((s32)in2[6])) * ((s32)in[3]) + ((limb)((s32)in2[2])) * ((s32)in[7]) + + ((limb)((s32)in2[7])) * ((s32)in[2]) + ((limb)((s32)in2[1])) * ((s32)in[8]) + ((limb)((s32)in2[8])) * ((s32)in[1]) + ((limb)((s32)in2[0])) * ((s32)in[9]) + ((limb)((s32)in2[9])) * ((s32)in[0]); + output[10] = 2 * (((limb)((s32)in2[5])) * ((s32)in[5]) + ((limb)((s32)in2[3])) * ((s32)in[7]) + ((limb)((s32)in2[7])) * ((s32)in[3]) + ((limb)((s32)in2[1])) * ((s32)in[9]) + ((limb)((s32)in2[9])) * ((s32)in[1])) + + ((limb)((s32)in2[4])) * ((s32)in[6]) + ((limb)((s32)in2[6])) * ((s32)in[4]) + ((limb)((s32)in2[2])) * ((s32)in[8]) + ((limb)((s32)in2[8])) * ((s32)in[2]); + output[11] = ((limb)((s32)in2[5])) * ((s32)in[6]) + ((limb)((s32)in2[6])) * ((s32)in[5]) + ((limb)((s32)in2[4])) * ((s32)in[7]) + ((limb)((s32)in2[7])) * ((s32)in[4]) + ((limb)((s32)in2[3])) * ((s32)in[8]) + + ((limb)((s32)in2[8])) * ((s32)in[3]) + ((limb)((s32)in2[2])) * ((s32)in[9]) + ((limb)((s32)in2[9])) * ((s32)in[2]); + output[12] = ((limb)((s32)in2[6])) * ((s32)in[6]) + 2 * (((limb)((s32)in2[5])) * ((s32)in[7]) + ((limb)((s32)in2[7])) * ((s32)in[5]) + ((limb)((s32)in2[3])) * ((s32)in[9]) + ((limb)((s32)in2[9])) * ((s32)in[3])) + + ((limb)((s32)in2[4])) * ((s32)in[8]) + ((limb)((s32)in2[8])) * ((s32)in[4]); + output[13] = + ((limb)((s32)in2[6])) * ((s32)in[7]) + ((limb)((s32)in2[7])) * ((s32)in[6]) + ((limb)((s32)in2[5])) * ((s32)in[8]) + ((limb)((s32)in2[8])) * ((s32)in[5]) + ((limb)((s32)in2[4])) * ((s32)in[9]) + ((limb)((s32)in2[9])) * ((s32)in[4]); + output[14] = 2 * (((limb)((s32)in2[7])) * ((s32)in[7]) + ((limb)((s32)in2[5])) * ((s32)in[9]) + ((limb)((s32)in2[9])) * ((s32)in[5])) + ((limb)((s32)in2[6])) * ((s32)in[8]) + ((limb)((s32)in2[8])) * ((s32)in[6]); + output[15] = ((limb)((s32)in2[7])) * ((s32)in[8]) + ((limb)((s32)in2[8])) * ((s32)in[7]) + ((limb)((s32)in2[6])) * ((s32)in[9]) + ((limb)((s32)in2[9])) * ((s32)in[6]); + output[16] = ((limb)((s32)in2[8])) * ((s32)in[8]) + 2 * (((limb)((s32)in2[7])) * ((s32)in[9]) + ((limb)((s32)in2[9])) * ((s32)in[7])); + output[17] = ((limb)((s32)in2[8])) * ((s32)in[9]) + ((limb)((s32)in2[9])) * ((s32)in[8]); + output[18] = 2 * ((limb)((s32)in2[9])) * ((s32)in[9]); +} + +static inline void freduce_degree(limb* output) +{ + output[8] += output[18] << 4; + output[8] += output[18] << 1; + output[8] += output[18]; + output[7] += output[17] << 4; + output[7] += output[17] << 1; + output[7] += output[17]; + output[6] += output[16] << 4; + output[6] += output[16] << 1; + output[6] += output[16]; + output[5] += output[15] << 4; + output[5] += output[15] << 1; + output[5] += output[15]; + output[4] += output[14] << 4; + output[4] += output[14] << 1; + output[4] += output[14]; + output[3] += output[13] << 4; + output[3] += output[13] << 1; + output[3] += output[13]; + output[2] += output[12] << 4; + output[2] += output[12] << 1; + output[2] += output[12]; + output[1] += output[11] << 4; + output[1] += output[11] << 1; + output[1] += output[11]; + output[0] += output[10] << 4; + output[0] += output[10] << 1; + output[0] += output[10]; +} + +#if (-1 & 3) != 3 +#error "This code only works on a two's complement system" +#endif + +static inline limb div_by_2_26(const limb v) +{ + /* High word of v; no shift needed. */ + const uint32_t highword = (uint32_t)(((uint64_t)v) >> 32); + /* Set to all 1s if v was negative; else set to 0s. */ + const int32_t sign = ((int32_t)highword) >> 31; + /* Set to 0x3ffffff if v was negative; else set to 0. */ + const int32_t roundoff = ((uint32_t)sign) >> 6; + /* Should return v / (1<<26) */ + return (v + roundoff) >> 26; +} + +static inline limb div_by_2_25(const limb v) +{ + /* High word of v; no shift needed*/ + const uint32_t highword = (uint32_t)(((uint64_t)v) >> 32); + /* Set to all 1s if v was negative; else set to 0s. */ + const int32_t sign = ((int32_t)highword) >> 31; + /* Set to 0x1ffffff if v was negative; else set to 0. */ + const int32_t roundoff = ((uint32_t)sign) >> 7; + /* Should return v / (1<<25) */ + return (v + roundoff) >> 25; +} + +static inline void freduce_coefficients(limb* output) +{ + unsigned i; + + output[10] = 0; + + for (i = 0; i < 10; i += 2) { + limb over = div_by_2_26(output[i]); + /* The entry condition (that |output[i]| < 280*2^54) means that over is, at + * most, 280*2^28 in the first iteration of this loop. This is added to the + * next limb and we can approximate the resulting bound of that limb by + * 281*2^54. */ + output[i] -= over << 26; + output[i + 1] += over; + + /* For the first iteration, |output[i+1]| < 281*2^54, thus |over| < + * 281*2^29. When this is added to the next limb, the resulting bound can + * be approximated as 281*2^54. + * + * For subsequent iterations of the loop, 281*2^54 remains a conservative + * bound and no overflow occurs. */ + over = div_by_2_25(output[i + 1]); + output[i + 1] -= over << 25; + output[i + 2] += over; + } + /* Now |output[10]| < 281*2^29 and all other coefficients are reduced. */ + output[0] += output[10] << 4; + output[0] += output[10] << 1; + output[0] += output[10]; + + output[10] = 0; + + /* Now output[1..9] are reduced, and |output[0]| < 2^26 + 19*281*2^29 + * So |over| will be no more than 2^16. */ + { + limb over = div_by_2_26(output[0]); + output[0] -= over << 26; + output[1] += over; + } + + /* Now output[0,2..9] are reduced, and |output[1]| < 2^25 + 2^16 < 2^26. The + * bound on |output[1]| is sufficient to meet our needs. */ +} + +static inline void fmul(limb* output, const limb* in, const limb* in2) +{ + limb t[19]; + fproduct(t, in, in2); + /* |t[i]| < 14*2^54 */ + freduce_degree(t); + freduce_coefficients(t); + /* |t[i]| < 2^26 */ + memcpy(output, t, sizeof(limb) * 10); +} + +static inline void fsquare_inner(limb* output, const limb* in) +{ + output[0] = ((limb)((s32)in[0])) * ((s32)in[0]); + output[1] = 2 * ((limb)((s32)in[0])) * ((s32)in[1]); + output[2] = 2 * (((limb)((s32)in[1])) * ((s32)in[1]) + ((limb)((s32)in[0])) * ((s32)in[2])); + output[3] = 2 * (((limb)((s32)in[1])) * ((s32)in[2]) + ((limb)((s32)in[0])) * ((s32)in[3])); + output[4] = ((limb)((s32)in[2])) * ((s32)in[2]) + 4 * ((limb)((s32)in[1])) * ((s32)in[3]) + 2 * ((limb)((s32)in[0])) * ((s32)in[4]); + output[5] = 2 * (((limb)((s32)in[2])) * ((s32)in[3]) + ((limb)((s32)in[1])) * ((s32)in[4]) + ((limb)((s32)in[0])) * ((s32)in[5])); + output[6] = 2 * (((limb)((s32)in[3])) * ((s32)in[3]) + ((limb)((s32)in[2])) * ((s32)in[4]) + ((limb)((s32)in[0])) * ((s32)in[6]) + 2 * ((limb)((s32)in[1])) * ((s32)in[5])); + output[7] = 2 * (((limb)((s32)in[3])) * ((s32)in[4]) + ((limb)((s32)in[2])) * ((s32)in[5]) + ((limb)((s32)in[1])) * ((s32)in[6]) + ((limb)((s32)in[0])) * ((s32)in[7])); + output[8] = ((limb)((s32)in[4])) * ((s32)in[4]) + 2 * (((limb)((s32)in[2])) * ((s32)in[6]) + ((limb)((s32)in[0])) * ((s32)in[8]) + 2 * (((limb)((s32)in[1])) * ((s32)in[7]) + ((limb)((s32)in[3])) * ((s32)in[5]))); + output[9] = 2 * (((limb)((s32)in[4])) * ((s32)in[5]) + ((limb)((s32)in[3])) * ((s32)in[6]) + ((limb)((s32)in[2])) * ((s32)in[7]) + ((limb)((s32)in[1])) * ((s32)in[8]) + ((limb)((s32)in[0])) * ((s32)in[9])); + output[10] = 2 * (((limb)((s32)in[5])) * ((s32)in[5]) + ((limb)((s32)in[4])) * ((s32)in[6]) + ((limb)((s32)in[2])) * ((s32)in[8]) + 2 * (((limb)((s32)in[3])) * ((s32)in[7]) + ((limb)((s32)in[1])) * ((s32)in[9]))); + output[11] = 2 * (((limb)((s32)in[5])) * ((s32)in[6]) + ((limb)((s32)in[4])) * ((s32)in[7]) + ((limb)((s32)in[3])) * ((s32)in[8]) + ((limb)((s32)in[2])) * ((s32)in[9])); + output[12] = ((limb)((s32)in[6])) * ((s32)in[6]) + 2 * (((limb)((s32)in[4])) * ((s32)in[8]) + 2 * (((limb)((s32)in[5])) * ((s32)in[7]) + ((limb)((s32)in[3])) * ((s32)in[9]))); + output[13] = 2 * (((limb)((s32)in[6])) * ((s32)in[7]) + ((limb)((s32)in[5])) * ((s32)in[8]) + ((limb)((s32)in[4])) * ((s32)in[9])); + output[14] = 2 * (((limb)((s32)in[7])) * ((s32)in[7]) + ((limb)((s32)in[6])) * ((s32)in[8]) + 2 * ((limb)((s32)in[5])) * ((s32)in[9])); + output[15] = 2 * (((limb)((s32)in[7])) * ((s32)in[8]) + ((limb)((s32)in[6])) * ((s32)in[9])); + output[16] = ((limb)((s32)in[8])) * ((s32)in[8]) + 4 * ((limb)((s32)in[7])) * ((s32)in[9]); + output[17] = 2 * ((limb)((s32)in[8])) * ((s32)in[9]); + output[18] = 2 * ((limb)((s32)in[9])) * ((s32)in[9]); +} + +static void fsquare(limb* output, const limb* in) +{ + limb t[19]; + fsquare_inner(t, in); + /* |t[i]| < 14*2^54 because the largest product of two limbs will be < + * 2^(27+27) and fsquare_inner adds together, at most, 14 of those + * products. */ + freduce_degree(t); + freduce_coefficients(t); + /* |t[i]| < 2^26 */ + memcpy(output, t, sizeof(limb) * 10); +} + +static inline void fexpand(limb* output, const u8* input) +{ +#define F(n, start, shift, mask) output[n] = ((((limb)input[start + 0]) | ((limb)input[start + 1]) << 8 | ((limb)input[start + 2]) << 16 | ((limb)input[start + 3]) << 24) >> shift) & mask; + F(0, 0, 0, 0x3ffffff); + F(1, 3, 2, 0x1ffffff); + F(2, 6, 3, 0x3ffffff); + F(3, 9, 5, 0x1ffffff); + F(4, 12, 6, 0x3ffffff); + F(5, 16, 0, 0x1ffffff); + F(6, 19, 1, 0x3ffffff); + F(7, 22, 3, 0x1ffffff); + F(8, 25, 4, 0x3ffffff); + F(9, 28, 6, 0x1ffffff); +#undef F +} + +#if (-32 >> 1) != -16 +#error "This code only works when >> does sign-extension on negative numbers" +#endif + +static inline s32 s32_eq(s32 a, s32 b) +{ + a = ~(a ^ b); + a &= a << 16; + a &= a << 8; + a &= a << 4; + a &= a << 2; + a &= a << 1; + return a >> 31; +} + +static inline s32 s32_gte(s32 a, s32 b) +{ + a -= b; + /* a >= 0 iff a >= b. */ + return ~(a >> 31); +} + +static inline void fcontract(u8* output, limb* input_limbs) +{ + int i; + int j; + s32 input[10]; + s32 mask; + + /* |input_limbs[i]| < 2^26, so it's valid to convert to an s32. */ + for (i = 0; i < 10; i++) { + input[i] = input_limbs[i]; + } + + for (j = 0; j < 2; ++j) { + for (i = 0; i < 9; ++i) { + if ((i & 1) == 1) { + /* This calculation is a time-invariant way to make input[i] + * non-negative by borrowing from the next-larger limb. */ + const s32 mask = input[i] >> 31; + const s32 carry = -((input[i] & mask) >> 25); + input[i] = input[i] + (carry << 25); + input[i + 1] = input[i + 1] - carry; + } + else { + const s32 mask = input[i] >> 31; + const s32 carry = -((input[i] & mask) >> 26); + input[i] = input[i] + (carry << 26); + input[i + 1] = input[i + 1] - carry; + } + } + + /* There's no greater limb for input[9] to borrow from, but we can multiply + * by 19 and borrow from input[0], which is valid mod 2^255-19. */ + { + const s32 mask = input[9] >> 31; + const s32 carry = -((input[9] & mask) >> 25); + input[9] = input[9] + (carry << 25); + input[0] = input[0] - (carry * 19); + } + + /* After the first iteration, input[1..9] are non-negative and fit within + * 25 or 26 bits, depending on position. However, input[0] may be + * negative. */ + } + + /* The first borrow-propagation pass above ended with every limb + except (possibly) input[0] non-negative. + + If input[0] was negative after the first pass, then it was because of a + carry from input[9]. On entry, input[9] < 2^26 so the carry was, at most, + one, since (2**26-1) >> 25 = 1. Thus input[0] >= -19. + + In the second pass, each limb is decreased by at most one. Thus the second + borrow-propagation pass could only have wrapped around to decrease + input[0] again if the first pass left input[0] negative *and* input[1] + through input[9] were all zero. In that case, input[1] is now 2^25 - 1, + and this last borrow-propagation step will leave input[1] non-negative. */ + { + const s32 mask = input[0] >> 31; + const s32 carry = -((input[0] & mask) >> 26); + input[0] = input[0] + (carry << 26); + input[1] = input[1] - carry; + } + + /* All input[i] are now non-negative. However, there might be values between + * 2^25 and 2^26 in a limb which is, nominally, 25 bits wide. */ + for (j = 0; j < 2; j++) { + for (i = 0; i < 9; i++) { + if ((i & 1) == 1) { + const s32 carry = input[i] >> 25; + input[i] &= 0x1ffffff; + input[i + 1] += carry; + } + else { + const s32 carry = input[i] >> 26; + input[i] &= 0x3ffffff; + input[i + 1] += carry; + } + } + + { + const s32 carry = input[9] >> 25; + input[9] &= 0x1ffffff; + input[0] += 19 * carry; + } + } + + /* If the first carry-chain pass, just above, ended up with a carry from + * input[9], and that caused input[0] to be out-of-bounds, then input[0] was + * < 2^26 + 2*19, because the carry was, at most, two. + * + * If the second pass carried from input[9] again then input[0] is < 2*19 and + * the input[9] -> input[0] carry didn't push input[0] out of bounds. */ + + /* It still remains the case that input might be between 2^255-19 and 2^255. + * In this case, input[1..9] must take their maximum value and input[0] must + * be >= (2^255-19) & 0x3ffffff, which is 0x3ffffed. */ + mask = s32_gte(input[0], 0x3ffffed); + for (i = 1; i < 10; i++) { + if ((i & 1) == 1) { + mask &= s32_eq(input[i], 0x1ffffff); + } + else { + mask &= s32_eq(input[i], 0x3ffffff); + } + } + + /* mask is either 0xffffffff (if input >= 2^255-19) and zero otherwise. Thus + * this conditionally subtracts 2^255-19. */ + input[0] -= mask & 0x3ffffed; + + for (i = 1; i < 10; i++) { + if ((i & 1) == 1) { + input[i] -= mask & 0x1ffffff; + } + else { + input[i] -= mask & 0x3ffffff; + } + } + + input[1] <<= 2; + input[2] <<= 3; + input[3] <<= 5; + input[4] <<= 6; + input[6] <<= 1; + input[7] <<= 3; + input[8] <<= 4; + input[9] <<= 6; +#define F(i, s) \ + output[s + 0] |= input[i] & 0xff; \ + output[s + 1] = (input[i] >> 8) & 0xff; \ + output[s + 2] = (input[i] >> 16) & 0xff; \ + output[s + 3] = (input[i] >> 24) & 0xff; + output[0] = 0; + output[16] = 0; + F(0, 0); + F(1, 3); + F(2, 6); + F(3, 9); + F(4, 12); + F(5, 16); + F(6, 19); + F(7, 22); + F(8, 25); + F(9, 28); +#undef F +} + +static inline void fmonty( + limb* x2, + limb* z2, /* output 2Q */ + limb* x3, + limb* z3, /* output Q + Q' */ + limb* x, + limb* z, /* input Q */ + limb* xprime, + limb* zprime, /* input Q' */ + const limb* qmqp /* input Q - Q' */) +{ + limb origx[10], origxprime[10], zzz[19], xx[19], zz[19], xxprime[19], zzprime[19], zzzprime[19], xxxprime[19]; + + memcpy(origx, x, 10 * sizeof(limb)); + fsum(x, z); + /* |x[i]| < 2^27 */ + fdifference(z, origx); /* does x - z */ + /* |z[i]| < 2^27 */ + + memcpy(origxprime, xprime, sizeof(limb) * 10); + fsum(xprime, zprime); + /* |xprime[i]| < 2^27 */ + fdifference(zprime, origxprime); + /* |zprime[i]| < 2^27 */ + fproduct(xxprime, xprime, z); + /* |xxprime[i]| < 14*2^54: the largest product of two limbs will be < + * 2^(27+27) and fproduct adds together, at most, 14 of those products. + * (Approximating that to 2^58 doesn't work out.) */ + fproduct(zzprime, x, zprime); + /* |zzprime[i]| < 14*2^54 */ + freduce_degree(xxprime); + freduce_coefficients(xxprime); + /* |xxprime[i]| < 2^26 */ + freduce_degree(zzprime); + freduce_coefficients(zzprime); + /* |zzprime[i]| < 2^26 */ + memcpy(origxprime, xxprime, sizeof(limb) * 10); + fsum(xxprime, zzprime); + /* |xxprime[i]| < 2^27 */ + fdifference(zzprime, origxprime); + /* |zzprime[i]| < 2^27 */ + fsquare(xxxprime, xxprime); + /* |xxxprime[i]| < 2^26 */ + fsquare(zzzprime, zzprime); + /* |zzzprime[i]| < 2^26 */ + fproduct(zzprime, zzzprime, qmqp); + /* |zzprime[i]| < 14*2^52 */ + freduce_degree(zzprime); + freduce_coefficients(zzprime); + /* |zzprime[i]| < 2^26 */ + memcpy(x3, xxxprime, sizeof(limb) * 10); + memcpy(z3, zzprime, sizeof(limb) * 10); + + fsquare(xx, x); + /* |xx[i]| < 2^26 */ + fsquare(zz, z); + /* |zz[i]| < 2^26 */ + fproduct(x2, xx, zz); + /* |x2[i]| < 14*2^52 */ + freduce_degree(x2); + freduce_coefficients(x2); + /* |x2[i]| < 2^26 */ + fdifference(zz, xx); // does zz = xx - zz + /* |zz[i]| < 2^27 */ + memset(zzz + 10, 0, sizeof(limb) * 9); + fscalar_product(zzz, zz, 121665); + /* |zzz[i]| < 2^(27+17) */ + /* No need to call freduce_degree here: + fscalar_product doesn't increase the degree of its input. */ + freduce_coefficients(zzz); + /* |zzz[i]| < 2^26 */ + fsum(zzz, xx); + /* |zzz[i]| < 2^27 */ + fproduct(z2, zz, zzz); + /* |z2[i]| < 14*2^(26+27) */ + freduce_degree(z2); + freduce_coefficients(z2); + /* |z2|i| < 2^26 */ +} + +static inline void swap_conditional(limb a[19], limb b[19], limb iswap) +{ + unsigned i; + const s32 swap = (s32)-iswap; + + for (i = 0; i < 10; ++i) { + const s32 x = swap & (((s32)a[i]) ^ ((s32)b[i])); + a[i] = ((s32)a[i]) ^ x; + b[i] = ((s32)b[i]) ^ x; + } +} + +static inline void cmult(limb* resultx, limb* resultz, const u8* n, const limb* q) +{ + limb a[19] = { 0 }, b[19] = { 1 }, c[19] = { 1 }, d[19] = { 0 }; + limb *nqpqx = a, *nqpqz = b, *nqx = c, *nqz = d, *t; + limb e[19] = { 0 }, f[19] = { 1 }, g[19] = { 0 }, h[19] = { 1 }; + limb *nqpqx2 = e, *nqpqz2 = f, *nqx2 = g, *nqz2 = h; + + unsigned i, j; + + memcpy(nqpqx, q, sizeof(limb) * 10); + + for (i = 0; i < 32; ++i) { + u8 byte = n[31 - i]; + for (j = 0; j < 8; ++j) { + const limb bit = byte >> 7; + + swap_conditional(nqx, nqpqx, bit); + swap_conditional(nqz, nqpqz, bit); + fmonty(nqx2, nqz2, nqpqx2, nqpqz2, nqx, nqz, nqpqx, nqpqz, q); + swap_conditional(nqx2, nqpqx2, bit); + swap_conditional(nqz2, nqpqz2, bit); + + t = nqx; + nqx = nqx2; + nqx2 = t; + t = nqz; + nqz = nqz2; + nqz2 = t; + t = nqpqx; + nqpqx = nqpqx2; + nqpqx2 = t; + t = nqpqz; + nqpqz = nqpqz2; + nqpqz2 = t; + + byte <<= 1; + } + } + + memcpy(resultx, nqx, sizeof(limb) * 10); + memcpy(resultz, nqz, sizeof(limb) * 10); +} + +static inline void crecip(limb* out, const limb* z) +{ + limb z2[10]; + limb z9[10]; + limb z11[10]; + limb z2_5_0[10]; + limb z2_10_0[10]; + limb z2_20_0[10]; + limb z2_50_0[10]; + limb z2_100_0[10]; + limb t0[10]; + limb t1[10]; + int i; + + /* 2 */ fsquare(z2, z); + /* 4 */ fsquare(t1, z2); + /* 8 */ fsquare(t0, t1); + /* 9 */ fmul(z9, t0, z); + /* 11 */ fmul(z11, z9, z2); + /* 22 */ fsquare(t0, z11); + /* 2^5 - 2^0 = 31 */ fmul(z2_5_0, t0, z9); + + /* 2^6 - 2^1 */ fsquare(t0, z2_5_0); + /* 2^7 - 2^2 */ fsquare(t1, t0); + /* 2^8 - 2^3 */ fsquare(t0, t1); + /* 2^9 - 2^4 */ fsquare(t1, t0); + /* 2^10 - 2^5 */ fsquare(t0, t1); + /* 2^10 - 2^0 */ fmul(z2_10_0, t0, z2_5_0); + + /* 2^11 - 2^1 */ fsquare(t0, z2_10_0); + /* 2^12 - 2^2 */ fsquare(t1, t0); + /* 2^20 - 2^10 */ for (i = 2; i < 10; i += 2) { + fsquare(t0, t1); + fsquare(t1, t0); + } + /* 2^20 - 2^0 */ fmul(z2_20_0, t1, z2_10_0); + + /* 2^21 - 2^1 */ fsquare(t0, z2_20_0); + /* 2^22 - 2^2 */ fsquare(t1, t0); + /* 2^40 - 2^20 */ for (i = 2; i < 20; i += 2) { + fsquare(t0, t1); + fsquare(t1, t0); + } + /* 2^40 - 2^0 */ fmul(t0, t1, z2_20_0); + + /* 2^41 - 2^1 */ fsquare(t1, t0); + /* 2^42 - 2^2 */ fsquare(t0, t1); + /* 2^50 - 2^10 */ for (i = 2; i < 10; i += 2) { + fsquare(t1, t0); + fsquare(t0, t1); + } + /* 2^50 - 2^0 */ fmul(z2_50_0, t0, z2_10_0); + + /* 2^51 - 2^1 */ fsquare(t0, z2_50_0); + /* 2^52 - 2^2 */ fsquare(t1, t0); + /* 2^100 - 2^50 */ for (i = 2; i < 50; i += 2) { + fsquare(t0, t1); + fsquare(t1, t0); + } + /* 2^100 - 2^0 */ fmul(z2_100_0, t1, z2_50_0); + + /* 2^101 - 2^1 */ fsquare(t1, z2_100_0); + /* 2^102 - 2^2 */ fsquare(t0, t1); + /* 2^200 - 2^100 */ for (i = 2; i < 100; i += 2) { + fsquare(t1, t0); + fsquare(t0, t1); + } + /* 2^200 - 2^0 */ fmul(t1, t0, z2_100_0); + + /* 2^201 - 2^1 */ fsquare(t0, t1); + /* 2^202 - 2^2 */ fsquare(t1, t0); + /* 2^250 - 2^50 */ for (i = 2; i < 50; i += 2) { + fsquare(t0, t1); + fsquare(t1, t0); + } + /* 2^250 - 2^0 */ fmul(t0, t1, z2_50_0); + + /* 2^251 - 2^1 */ fsquare(t1, t0); + /* 2^252 - 2^2 */ fsquare(t0, t1); + /* 2^253 - 2^3 */ fsquare(t1, t0); + /* 2^254 - 2^4 */ fsquare(t0, t1); + /* 2^255 - 2^5 */ fsquare(t1, t0); + /* 2^255 - 21 */ fmul(out, t1, z11); +} + +static void crypto_scalarmult(u8* mypublic, const u8* secret, const u8* basepoint) +{ + limb bp[10], x[10], z[11], zmone[10]; + uint8_t e[32]; + int i; + + for (i = 0; i < 32; ++i) { + e[i] = secret[i]; + } + e[0] &= 248; + e[31] &= 127; + e[31] |= 64; + + fexpand(bp, basepoint); + cmult(x, z, e, bp); + crecip(zmone, z); + fmul(z, x, zmone); + fcontract(mypublic, z); +} + +static const unsigned char base[32] = { 9 }; +static inline void crypto_scalarmult_base(unsigned char* q, const unsigned char* n) +{ + crypto_scalarmult(q, n, base); +} + +////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + +// Ed25519 ref from: http://bench.cr.yp.to/supercop.html + +typedef struct { + crypto_uint32 v[32]; +} fe25519; + +typedef struct { + crypto_uint32 v[32]; +} sc25519; + +typedef struct { + crypto_uint32 v[16]; +} shortsc25519; + +typedef struct { + fe25519 x; + fe25519 y; + fe25519 z; + fe25519 t; +} ge25519; + +#define ge25519_p3 ge25519 + +typedef struct { + fe25519 x; + fe25519 z; + fe25519 y; + fe25519 t; +} ge25519_p1p1; + +typedef struct { + fe25519 x; + fe25519 y; + fe25519 z; +} ge25519_p2; + +typedef struct { + fe25519 x; + fe25519 y; +} ge25519_aff; + +static inline void fe25519_sub(fe25519* r, const fe25519* x, const fe25519* y); + +static inline crypto_uint32 equal(crypto_uint32 a, crypto_uint32 b) /* 16-bit inputs */ +{ + crypto_uint32 x = a ^ b; /* 0: yes; 1..65535: no */ + x -= 1; /* 4294967295: yes; 0..65534: no */ + x >>= 31; /* 1: yes; 0: no */ + return x; +} + +static inline crypto_uint32 ge(crypto_uint32 a, crypto_uint32 b) /* 16-bit inputs */ +{ + unsigned int x = a; + x -= (unsigned int)b; /* 0..65535: yes; 4294901761..4294967295: no */ + x >>= 31; /* 0: yes; 1: no */ + x ^= 1; /* 1: yes; 0: no */ + return x; +} + +static inline crypto_uint32 times19(crypto_uint32 a) +{ + return (a << 4) + (a << 1) + a; +} + +static inline crypto_uint32 times38(crypto_uint32 a) +{ + return (a << 5) + (a << 2) + (a << 1); +} + +static inline void reduce_add_sub(fe25519* r) +{ + crypto_uint32 t; + int i, rep; + + for (rep = 0; rep < 4; rep++) { + t = r->v[31] >> 7; + r->v[31] &= 127; + t = times19(t); + r->v[0] += t; + for (i = 0; i < 31; i++) { + t = r->v[i] >> 8; + r->v[i + 1] += t; + r->v[i] &= 255; + } + } +} + +static inline void reduce_mul(fe25519* r) +{ + crypto_uint32 t; + int i, rep; + + for (rep = 0; rep < 2; rep++) { + t = r->v[31] >> 7; + r->v[31] &= 127; + t = times19(t); + r->v[0] += t; + for (i = 0; i < 31; i++) { + t = r->v[i] >> 8; + r->v[i + 1] += t; + r->v[i] &= 255; + } + } +} + +/* reduction modulo 2^255-19 */ +static inline void fe25519_freeze(fe25519* r) +{ + int i; + crypto_uint32 m = equal(r->v[31], 127); + for (i = 30; i > 0; i--) { + m &= equal(r->v[i], 255); + } + m &= ge(r->v[0], 237); + + m = -m; + + r->v[31] -= m & 127; + for (i = 30; i > 0; i--) { + r->v[i] -= m & 255; + } + r->v[0] -= m & 237; +} + +static inline void fe25519_unpack(fe25519* r, const unsigned char x[32]) +{ + int i; + for (i = 0; i < 32; i++) { + r->v[i] = x[i]; + } + r->v[31] &= 127; +} + +/* Assumes input x being reduced below 2^255 */ +static inline void fe25519_pack(unsigned char r[32], const fe25519* x) +{ + int i; + fe25519 y = *x; + fe25519_freeze(&y); + for (i = 0; i < 32; i++) { + r[i] = y.v[i]; + } +} + +static inline int fe25519_iseq_vartime(const fe25519* x, const fe25519* y) +{ + int i; + fe25519 t1 = *x; + fe25519 t2 = *y; + fe25519_freeze(&t1); + fe25519_freeze(&t2); + for (i = 0; i < 32; i++) { + if (t1.v[i] != t2.v[i]) { + return 0; + } + } + return 1; +} + +static inline void fe25519_cmov(fe25519* r, const fe25519* x, unsigned char b) +{ + int i; + crypto_uint32 mask = b; + mask = -mask; + for (i = 0; i < 32; i++) { + r->v[i] ^= mask & (x->v[i] ^ r->v[i]); + } +} + +static inline unsigned char fe25519_getparity(const fe25519* x) +{ + fe25519 t = *x; + fe25519_freeze(&t); + return t.v[0] & 1; +} + +static inline void fe25519_setone(fe25519* r) +{ + int i; + r->v[0] = 1; + for (i = 1; i < 32; i++) { + r->v[i] = 0; + } +} + +static inline void fe25519_setzero(fe25519* r) +{ + int i; + for (i = 0; i < 32; i++) { + r->v[i] = 0; + } +} + +static inline void fe25519_neg(fe25519* r, const fe25519* x) +{ + fe25519 t; + int i; + for (i = 0; i < 32; i++) { + t.v[i] = x->v[i]; + } + fe25519_setzero(r); + fe25519_sub(r, r, &t); +} + +static inline void fe25519_add(fe25519* r, const fe25519* x, const fe25519* y) +{ + int i; + for (i = 0; i < 32; i++) { + r->v[i] = x->v[i] + y->v[i]; + } + reduce_add_sub(r); +} + +static inline void fe25519_sub(fe25519* r, const fe25519* x, const fe25519* y) +{ + int i; + crypto_uint32 t[32]; + t[0] = x->v[0] + 0x1da; + t[31] = x->v[31] + 0xfe; + for (i = 1; i < 31; i++) { + t[i] = x->v[i] + 0x1fe; + } + for (i = 0; i < 32; i++) { + r->v[i] = t[i] - y->v[i]; + } + reduce_add_sub(r); +} + +static inline void fe25519_mul(fe25519* r, const fe25519* x, const fe25519* y) +{ + int i, j; + crypto_uint32 t[63]; + for (i = 0; i < 63; i++) { + t[i] = 0; + } + + for (i = 0; i < 32; i++) { + for (j = 0; j < 32; j++) { + t[i + j] += x->v[i] * y->v[j]; + } + } + + for (i = 32; i < 63; i++) { + r->v[i - 32] = t[i - 32] + times38(t[i]); + } + r->v[31] = t[31]; /* result now in r[0]...r[31] */ + + reduce_mul(r); +} + +static inline void fe25519_square(fe25519* r, const fe25519* x) +{ + fe25519_mul(r, x, x); +} + +static inline void fe25519_invert(fe25519* r, const fe25519* x) +{ + fe25519 z2; + fe25519 z9; + fe25519 z11; + fe25519 z2_5_0; + fe25519 z2_10_0; + fe25519 z2_20_0; + fe25519 z2_50_0; + fe25519 z2_100_0; + fe25519 t0; + fe25519 t1; + int i; + + /* 2 */ fe25519_square(&z2, x); + /* 4 */ fe25519_square(&t1, &z2); + /* 8 */ fe25519_square(&t0, &t1); + /* 9 */ fe25519_mul(&z9, &t0, x); + /* 11 */ fe25519_mul(&z11, &z9, &z2); + /* 22 */ fe25519_square(&t0, &z11); + /* 2^5 - 2^0 = 31 */ fe25519_mul(&z2_5_0, &t0, &z9); + + /* 2^6 - 2^1 */ fe25519_square(&t0, &z2_5_0); + /* 2^7 - 2^2 */ fe25519_square(&t1, &t0); + /* 2^8 - 2^3 */ fe25519_square(&t0, &t1); + /* 2^9 - 2^4 */ fe25519_square(&t1, &t0); + /* 2^10 - 2^5 */ fe25519_square(&t0, &t1); + /* 2^10 - 2^0 */ fe25519_mul(&z2_10_0, &t0, &z2_5_0); + + /* 2^11 - 2^1 */ fe25519_square(&t0, &z2_10_0); + /* 2^12 - 2^2 */ fe25519_square(&t1, &t0); + /* 2^20 - 2^10 */ for (i = 2; i < 10; i += 2) { + fe25519_square(&t0, &t1); + fe25519_square(&t1, &t0); + } + /* 2^20 - 2^0 */ fe25519_mul(&z2_20_0, &t1, &z2_10_0); + + /* 2^21 - 2^1 */ fe25519_square(&t0, &z2_20_0); + /* 2^22 - 2^2 */ fe25519_square(&t1, &t0); + /* 2^40 - 2^20 */ for (i = 2; i < 20; i += 2) { + fe25519_square(&t0, &t1); + fe25519_square(&t1, &t0); + } + /* 2^40 - 2^0 */ fe25519_mul(&t0, &t1, &z2_20_0); + + /* 2^41 - 2^1 */ fe25519_square(&t1, &t0); + /* 2^42 - 2^2 */ fe25519_square(&t0, &t1); + /* 2^50 - 2^10 */ for (i = 2; i < 10; i += 2) { + fe25519_square(&t1, &t0); + fe25519_square(&t0, &t1); + } + /* 2^50 - 2^0 */ fe25519_mul(&z2_50_0, &t0, &z2_10_0); + + /* 2^51 - 2^1 */ fe25519_square(&t0, &z2_50_0); + /* 2^52 - 2^2 */ fe25519_square(&t1, &t0); + /* 2^100 - 2^50 */ for (i = 2; i < 50; i += 2) { + fe25519_square(&t0, &t1); + fe25519_square(&t1, &t0); + } + /* 2^100 - 2^0 */ fe25519_mul(&z2_100_0, &t1, &z2_50_0); + + /* 2^101 - 2^1 */ fe25519_square(&t1, &z2_100_0); + /* 2^102 - 2^2 */ fe25519_square(&t0, &t1); + /* 2^200 - 2^100 */ for (i = 2; i < 100; i += 2) { + fe25519_square(&t1, &t0); + fe25519_square(&t0, &t1); + } + /* 2^200 - 2^0 */ fe25519_mul(&t1, &t0, &z2_100_0); + + /* 2^201 - 2^1 */ fe25519_square(&t0, &t1); + /* 2^202 - 2^2 */ fe25519_square(&t1, &t0); + /* 2^250 - 2^50 */ for (i = 2; i < 50; i += 2) { + fe25519_square(&t0, &t1); + fe25519_square(&t1, &t0); + } + /* 2^250 - 2^0 */ fe25519_mul(&t0, &t1, &z2_50_0); + + /* 2^251 - 2^1 */ fe25519_square(&t1, &t0); + /* 2^252 - 2^2 */ fe25519_square(&t0, &t1); + /* 2^253 - 2^3 */ fe25519_square(&t1, &t0); + /* 2^254 - 2^4 */ fe25519_square(&t0, &t1); + /* 2^255 - 2^5 */ fe25519_square(&t1, &t0); + /* 2^255 - 21 */ fe25519_mul(r, &t1, &z11); +} + +static inline void fe25519_pow2523(fe25519* r, const fe25519* x) +{ + fe25519 z2; + fe25519 z9; + fe25519 z11; + fe25519 z2_5_0; + fe25519 z2_10_0; + fe25519 z2_20_0; + fe25519 z2_50_0; + fe25519 z2_100_0; + fe25519 t; + int i; + + /* 2 */ fe25519_square(&z2, x); + /* 4 */ fe25519_square(&t, &z2); + /* 8 */ fe25519_square(&t, &t); + /* 9 */ fe25519_mul(&z9, &t, x); + /* 11 */ fe25519_mul(&z11, &z9, &z2); + /* 22 */ fe25519_square(&t, &z11); + /* 2^5 - 2^0 = 31 */ fe25519_mul(&z2_5_0, &t, &z9); + + /* 2^6 - 2^1 */ fe25519_square(&t, &z2_5_0); + /* 2^10 - 2^5 */ for (i = 1; i < 5; i++) { fe25519_square(&t, &t); } + /* 2^10 - 2^0 */ fe25519_mul(&z2_10_0, &t, &z2_5_0); + + /* 2^11 - 2^1 */ fe25519_square(&t, &z2_10_0); + /* 2^20 - 2^10 */ for (i = 1; i < 10; i++) { fe25519_square(&t, &t); } + /* 2^20 - 2^0 */ fe25519_mul(&z2_20_0, &t, &z2_10_0); + + /* 2^21 - 2^1 */ fe25519_square(&t, &z2_20_0); + /* 2^40 - 2^20 */ for (i = 1; i < 20; i++) { fe25519_square(&t, &t); } + /* 2^40 - 2^0 */ fe25519_mul(&t, &t, &z2_20_0); + + /* 2^41 - 2^1 */ fe25519_square(&t, &t); + /* 2^50 - 2^10 */ for (i = 1; i < 10; i++) { fe25519_square(&t, &t); } + /* 2^50 - 2^0 */ fe25519_mul(&z2_50_0, &t, &z2_10_0); + + /* 2^51 - 2^1 */ fe25519_square(&t, &z2_50_0); + /* 2^100 - 2^50 */ for (i = 1; i < 50; i++) { fe25519_square(&t, &t); } + /* 2^100 - 2^0 */ fe25519_mul(&z2_100_0, &t, &z2_50_0); + + /* 2^101 - 2^1 */ fe25519_square(&t, &z2_100_0); + /* 2^200 - 2^100 */ for (i = 1; i < 100; i++) { fe25519_square(&t, &t); } + /* 2^200 - 2^0 */ fe25519_mul(&t, &t, &z2_100_0); + + /* 2^201 - 2^1 */ fe25519_square(&t, &t); + /* 2^250 - 2^50 */ for (i = 1; i < 50; i++) { fe25519_square(&t, &t); } + /* 2^250 - 2^0 */ fe25519_mul(&t, &t, &z2_50_0); + + /* 2^251 - 2^1 */ fe25519_square(&t, &t); + /* 2^252 - 2^2 */ fe25519_square(&t, &t); + /* 2^252 - 3 */ fe25519_mul(r, &t, x); +} + +static const crypto_uint32 m[32] = { 0xED, 0xD3, 0xF5, 0x5C, 0x1A, 0x63, 0x12, 0x58, 0xD6, 0x9C, 0xF7, 0xA2, 0xDE, 0xF9, 0xDE, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10 }; +static const crypto_uint32 mu[33] = { 0x1B, 0x13, 0x2C, 0x0A, 0xA3, 0xE5, 0x9C, 0xED, 0xA7, 0x29, 0x63, 0x08, 0x5D, 0x21, 0x06, 0x21, 0xEB, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F }; + +static inline crypto_uint32 lt(crypto_uint32 a, crypto_uint32 b) /* 16-bit inputs */ +{ + unsigned int x = a; + x -= (unsigned int)b; /* 0..65535: no; 4294901761..4294967295: yes */ + x >>= 31; /* 0: no; 1: yes */ + return x; +} + +/* Reduce coefficients of r before calling reduce_add_sub */ +static inline void reduce_add_sub(sc25519* r) +{ + crypto_uint32 pb = 0; + crypto_uint32 b; + crypto_uint32 mask; + int i; + unsigned char t[32]; + + for (i = 0; i < 32; i++) { + pb += m[i]; + b = lt(r->v[i], pb); + t[i] = r->v[i] - pb + (b << 8); + pb = b; + } + mask = b - 1; + for (i = 0; i < 32; i++) { + r->v[i] ^= mask & (r->v[i] ^ t[i]); + } +} + +/* Reduce coefficients of x before calling barrett_reduce */ +static inline void barrett_reduce(sc25519* r, const crypto_uint32 x[64]) +{ + /* See HAC, Alg. 14.42 */ + int i, j; + crypto_uint32 q2[66]; + crypto_uint32* q3 = q2 + 33; + crypto_uint32 r1[33]; + crypto_uint32 r2[33]; + crypto_uint32 carry; + crypto_uint32 pb = 0; + crypto_uint32 b; + + for (i = 0; i < 66; ++i) { + q2[i] = 0; + } + for (i = 0; i < 33; ++i) { + r2[i] = 0; + } + + for (i = 0; i < 33; i++) { + for (j = 0; j < 33; j++) { + if (i + j >= 31) { + q2[i + j] += mu[i] * x[j + 31]; + } + } + } + carry = q2[31] >> 8; + q2[32] += carry; + carry = q2[32] >> 8; + q2[33] += carry; + + for (i = 0; i < 33; i++) { + r1[i] = x[i]; + } + for (i = 0; i < 32; i++) { + for (j = 0; j < 33; j++) { + if (i + j < 33) { + r2[i + j] += m[i] * q3[j]; + } + } + } + + for (i = 0; i < 32; i++) { + carry = r2[i] >> 8; + r2[i + 1] += carry; + r2[i] &= 0xff; + } + + for (i = 0; i < 32; i++) { + pb += r2[i]; + b = lt(r1[i], pb); + r->v[i] = r1[i] - pb + (b << 8); + pb = b; + } + + /* XXX: Can it really happen that r<0?, See HAC, Alg 14.42, Step 3 + * If so: Handle it here! + */ + + reduce_add_sub(r); + reduce_add_sub(r); +} + +static inline void sc25519_from32bytes(sc25519* r, const unsigned char x[32]) +{ + int i; + crypto_uint32 t[64]; + for (i = 0; i < 32; i++) { + t[i] = x[i]; + } + for (i = 32; i < 64; ++i) { + t[i] = 0; + } + barrett_reduce(r, t); +} + +static inline void sc25519_from64bytes(sc25519* r, const unsigned char x[64]) +{ + int i; + crypto_uint32 t[64]; + for (i = 0; i < 64; i++) { + t[i] = x[i]; + } + barrett_reduce(r, t); +} + +static inline void sc25519_to32bytes(unsigned char r[32], const sc25519* x) +{ + int i; + for (i = 0; i < 32; i++) { + r[i] = x->v[i]; + } +} + +static inline void sc25519_add(sc25519* r, const sc25519* x, const sc25519* y) +{ + int i, carry; + for (i = 0; i < 32; i++) { + r->v[i] = x->v[i] + y->v[i]; + } + for (i = 0; i < 31; i++) { + carry = r->v[i] >> 8; + r->v[i + 1] += carry; + r->v[i] &= 0xff; + } + reduce_add_sub(r); +} + +static inline void sc25519_mul(sc25519* r, const sc25519* x, const sc25519* y) +{ + int i, j, carry; + crypto_uint32 t[64]; + for (i = 0; i < 64; i++) { + t[i] = 0; + } + + for (i = 0; i < 32; i++) { + for (j = 0; j < 32; j++) { + t[i + j] += x->v[i] * y->v[j]; + } + } + + for (i = 0; i < 63; i++) { + carry = t[i] >> 8; + t[i + 1] += carry; + t[i] &= 0xff; + } + + barrett_reduce(r, t); +} + +static inline void sc25519_window3(signed char r[85], const sc25519* s) +{ + char carry; + int i; + for (i = 0; i < 10; i++) { + r[8 * i + 0] = s->v[3 * i + 0] & 7; + r[8 * i + 1] = (s->v[3 * i + 0] >> 3) & 7; + r[8 * i + 2] = (s->v[3 * i + 0] >> 6) & 7; + r[8 * i + 2] ^= (s->v[3 * i + 1] << 2) & 7; + r[8 * i + 3] = (s->v[3 * i + 1] >> 1) & 7; + r[8 * i + 4] = (s->v[3 * i + 1] >> 4) & 7; + r[8 * i + 5] = (s->v[3 * i + 1] >> 7) & 7; + r[8 * i + 5] ^= (s->v[3 * i + 2] << 1) & 7; + r[8 * i + 6] = (s->v[3 * i + 2] >> 2) & 7; + r[8 * i + 7] = (s->v[3 * i + 2] >> 5) & 7; + } + r[8 * i + 0] = s->v[3 * i + 0] & 7; + r[8 * i + 1] = (s->v[3 * i + 0] >> 3) & 7; + r[8 * i + 2] = (s->v[3 * i + 0] >> 6) & 7; + r[8 * i + 2] ^= (s->v[3 * i + 1] << 2) & 7; + r[8 * i + 3] = (s->v[3 * i + 1] >> 1) & 7; + r[8 * i + 4] = (s->v[3 * i + 1] >> 4) & 7; + + /* Making it signed */ + carry = 0; + for (i = 0; i < 84; i++) { + r[i] += carry; + r[i + 1] += r[i] >> 3; + r[i] &= 7; + carry = r[i] >> 2; + r[i] -= carry << 3; + } + r[84] += carry; +} + +static inline void sc25519_2interleave2(unsigned char r[127], const sc25519* s1, const sc25519* s2) +{ + int i; + for (i = 0; i < 31; i++) { + r[4 * i] = (s1->v[i] & 3) ^ ((s2->v[i] & 3) << 2); + r[4 * i + 1] = ((s1->v[i] >> 2) & 3) ^ (((s2->v[i] >> 2) & 3) << 2); + r[4 * i + 2] = ((s1->v[i] >> 4) & 3) ^ (((s2->v[i] >> 4) & 3) << 2); + r[4 * i + 3] = ((s1->v[i] >> 6) & 3) ^ (((s2->v[i] >> 6) & 3) << 2); + } + r[124] = (s1->v[31] & 3) ^ ((s2->v[31] & 3) << 2); + r[125] = ((s1->v[31] >> 2) & 3) ^ (((s2->v[31] >> 2) & 3) << 2); + r[126] = ((s1->v[31] >> 4) & 3) ^ (((s2->v[31] >> 4) & 3) << 2); +} + +/* d */ +static const fe25519 ge25519_ecd = { { 0xA3, 0x78, 0x59, 0x13, 0xCA, 0x4D, 0xEB, 0x75, 0xAB, 0xD8, 0x41, 0x41, 0x4D, 0x0A, 0x70, 0x00, 0x98, 0xE8, 0x79, 0x77, 0x79, 0x40, 0xC7, 0x8C, 0x73, 0xFE, 0x6F, 0x2B, 0xEE, 0x6C, 0x03, 0x52 } }; +/* 2*d */ +static const fe25519 ge25519_ec2d = { { 0x59, 0xF1, 0xB2, 0x26, 0x94, 0x9B, 0xD6, 0xEB, 0x56, 0xB1, 0x83, 0x82, 0x9A, 0x14, 0xE0, 0x00, 0x30, 0xD1, 0xF3, 0xEE, 0xF2, 0x80, 0x8E, 0x19, 0xE7, 0xFC, 0xDF, 0x56, 0xDC, 0xD9, 0x06, 0x24 } }; +/* sqrt(-1) */ +static const fe25519 ge25519_sqrtm1 = { { 0xB0, 0xA0, 0x0E, 0x4A, 0x27, 0x1B, 0xEE, 0xC4, 0x78, 0xE4, 0x2F, 0xAD, 0x06, 0x18, 0x43, 0x2F, 0xA7, 0xD7, 0xFB, 0x3D, 0x99, 0x00, 0x4D, 0x2B, 0x0B, 0xDF, 0xC1, 0x4F, 0x80, 0x24, 0x83, 0x2B } }; + +/* Packed coordinates of the base point */ +static const ge25519 ge25519_base = { { { 0x1A, 0xD5, 0x25, 0x8F, 0x60, 0x2D, 0x56, 0xC9, 0xB2, 0xA7, 0x25, 0x95, 0x60, 0xC7, 0x2C, 0x69, 0x5C, 0xDC, 0xD6, 0xFD, 0x31, 0xE2, 0xA4, 0xC0, 0xFE, 0x53, 0x6E, 0xCD, 0xD3, 0x36, 0x69, 0x21 } }, + { { 0x58, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0xA3, 0xDD, 0xB7, 0xA5, 0xB3, 0x8A, 0xDE, 0x6D, 0xF5, 0x52, 0x51, 0x77, 0x80, 0x9F, 0xF0, 0x20, 0x7D, 0xE3, 0xAB, 0x64, 0x8E, 0x4E, 0xEA, 0x66, 0x65, 0x76, 0x8B, 0xD7, 0x0F, 0x5F, 0x87, 0x67 } } }; + +/* Multiples of the base point in affine representation */ +static const ge25519_aff ge25519_base_multiples_affine[425] = { + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0x1a, 0xd5, 0x25, 0x8f, 0x60, 0x2d, 0x56, 0xc9, 0xb2, 0xa7, 0x25, 0x95, 0x60, 0xc7, 0x2c, 0x69, 0x5c, 0xdc, 0xd6, 0xfd, 0x31, 0xe2, 0xa4, 0xc0, 0xfe, 0x53, 0x6e, 0xcd, 0xd3, 0x36, 0x69, 0x21 } }, + { { 0x58, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66 } } }, + { { { 0x0e, 0xce, 0x43, 0x28, 0x4e, 0xa1, 0xc5, 0x83, 0x5f, 0xa4, 0xd7, 0x15, 0x45, 0x8e, 0x0d, 0x08, 0xac, 0xe7, 0x33, 0x18, 0x7d, 0x3b, 0x04, 0x3d, 0x6c, 0x04, 0x5a, 0x9f, 0x4c, 0x38, 0xab, 0x36 } }, + { { 0xc9, 0xa3, 0xf8, 0x6a, 0xae, 0x46, 0x5f, 0x0e, 0x56, 0x51, 0x38, 0x64, 0x51, 0x0f, 0x39, 0x97, 0x56, 0x1f, 0xa2, 0xc9, 0xe8, 0x5e, 0xa2, 0x1d, 0xc2, 0x29, 0x23, 0x09, 0xf3, 0xcd, 0x60, 0x22 } } }, + { { { 0x5c, 0xe2, 0xf8, 0xd3, 0x5f, 0x48, 0x62, 0xac, 0x86, 0x48, 0x62, 0x81, 0x19, 0x98, 0x43, 0x63, 0x3a, 0xc8, 0xda, 0x3e, 0x74, 0xae, 0xf4, 0x1f, 0x49, 0x8f, 0x92, 0x22, 0x4a, 0x9c, 0xae, 0x67 } }, + { { 0xd4, 0xb4, 0xf5, 0x78, 0x48, 0x68, 0xc3, 0x02, 0x04, 0x03, 0x24, 0x67, 0x17, 0xec, 0x16, 0x9f, 0xf7, 0x9e, 0x26, 0x60, 0x8e, 0xa1, 0x26, 0xa1, 0xab, 0x69, 0xee, 0x77, 0xd1, 0xb1, 0x67, 0x12 } } }, + { { { 0x70, 0xf8, 0xc9, 0xc4, 0x57, 0xa6, 0x3a, 0x49, 0x47, 0x15, 0xce, 0x93, 0xc1, 0x9e, 0x73, 0x1a, 0xf9, 0x20, 0x35, 0x7a, 0xb8, 0xd4, 0x25, 0x83, 0x46, 0xf1, 0xcf, 0x56, 0xdb, 0xa8, 0x3d, 0x20 } }, + { { 0x2f, 0x11, 0x32, 0xca, 0x61, 0xab, 0x38, 0xdf, 0xf0, 0x0f, 0x2f, 0xea, 0x32, 0x28, 0xf2, 0x4c, 0x6c, 0x71, 0xd5, 0x80, 0x85, 0xb8, 0x0e, 0x47, 0xe1, 0x95, 0x15, 0xcb, 0x27, 0xe8, 0xd0, 0x47 } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0xc8, 0x84, 0xa5, 0x08, 0xbc, 0xfd, 0x87, 0x3b, 0x99, 0x8b, 0x69, 0x80, 0x7b, 0xc6, 0x3a, 0xeb, 0x93, 0xcf, 0x4e, 0xf8, 0x5c, 0x2d, 0x86, 0x42, 0xb6, 0x71, 0xd7, 0x97, 0x5f, 0xe1, 0x42, 0x67 } }, + { { 0xb4, 0xb9, 0x37, 0xfc, 0xa9, 0x5b, 0x2f, 0x1e, 0x93, 0xe4, 0x1e, 0x62, 0xfc, 0x3c, 0x78, 0x81, 0x8f, 0xf3, 0x8a, 0x66, 0x09, 0x6f, 0xad, 0x6e, 0x79, 0x73, 0xe5, 0xc9, 0x00, 0x06, 0xd3, 0x21 } } }, + { { { 0xf8, 0xf9, 0x28, 0x6c, 0x6d, 0x59, 0xb2, 0x59, 0x74, 0x23, 0xbf, 0xe7, 0x33, 0x8d, 0x57, 0x09, 0x91, 0x9c, 0x24, 0x08, 0x15, 0x2b, 0xe2, 0xb8, 0xee, 0x3a, 0xe5, 0x27, 0x06, 0x86, 0xa4, 0x23 } }, + { { 0xeb, 0x27, 0x67, 0xc1, 0x37, 0xab, 0x7a, 0xd8, 0x27, 0x9c, 0x07, 0x8e, 0xff, 0x11, 0x6a, 0xb0, 0x78, 0x6e, 0xad, 0x3a, 0x2e, 0x0f, 0x98, 0x9f, 0x72, 0xc3, 0x7f, 0x82, 0xf2, 0x96, 0x96, 0x70 } } }, + { { { 0x81, 0x6b, 0x88, 0xe8, 0x1e, 0xc7, 0x77, 0x96, 0x0e, 0xa1, 0xa9, 0x52, 0xe0, 0xd8, 0x0e, 0x61, 0x9e, 0x79, 0x2d, 0x95, 0x9c, 0x8d, 0x96, 0xe0, 0x06, 0x40, 0x5d, 0x87, 0x28, 0x5f, 0x98, 0x70 } }, + { { 0xf1, 0x79, 0x7b, 0xed, 0x4f, 0x44, 0xb2, 0xe7, 0x08, 0x0d, 0xc2, 0x08, 0x12, 0xd2, 0x9f, 0xdf, 0xcd, 0x93, 0x20, 0x8a, 0xcf, 0x33, 0xca, 0x6d, 0x89, 0xb9, 0x77, 0xc8, 0x93, 0x1b, 0x4e, 0x60 } } }, + { { { 0x26, 0x4f, 0x7e, 0x97, 0xf6, 0x40, 0xdd, 0x4f, 0xfc, 0x52, 0x78, 0xf9, 0x90, 0x31, 0x03, 0xe6, 0x7d, 0x56, 0x39, 0x0b, 0x1d, 0x56, 0x82, 0x85, 0xf9, 0x1a, 0x42, 0x17, 0x69, 0x6c, 0xcf, 0x39 } }, + { { 0x69, 0xd2, 0x06, 0x3a, 0x4f, 0x39, 0x2d, 0xf9, 0x38, 0x40, 0x8c, 0x4c, 0xe7, 0x05, 0x12, 0xb4, 0x78, 0x8b, 0xf8, 0xc0, 0xec, 0x93, 0xde, 0x7a, 0x6b, 0xce, 0x2c, 0xe1, 0x0e, 0xa9, 0x34, 0x44 } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0x0b, 0xa4, 0x3c, 0xb0, 0x0f, 0x7a, 0x51, 0xf1, 0x78, 0xd6, 0xd9, 0x6a, 0xfd, 0x46, 0xe8, 0xb8, 0xa8, 0x79, 0x1d, 0x87, 0xf9, 0x90, 0xf2, 0x9c, 0x13, 0x29, 0xf8, 0x0b, 0x20, 0x64, 0xfa, 0x05 } }, + { { 0x26, 0x09, 0xda, 0x17, 0xaf, 0x95, 0xd6, 0xfb, 0x6a, 0x19, 0x0d, 0x6e, 0x5e, 0x12, 0xf1, 0x99, 0x4c, 0xaa, 0xa8, 0x6f, 0x79, 0x86, 0xf4, 0x72, 0x28, 0x00, 0x26, 0xf9, 0xea, 0x9e, 0x19, 0x3d } } }, + { { { 0x87, 0xdd, 0xcf, 0xf0, 0x5b, 0x49, 0xa2, 0x5d, 0x40, 0x7a, 0x23, 0x26, 0xa4, 0x7a, 0x83, 0x8a, 0xb7, 0x8b, 0xd2, 0x1a, 0xbf, 0xea, 0x02, 0x24, 0x08, 0x5f, 0x7b, 0xa9, 0xb1, 0xbe, 0x9d, 0x37 } }, + { { 0xfc, 0x86, 0x4b, 0x08, 0xee, 0xe7, 0xa0, 0xfd, 0x21, 0x45, 0x09, 0x34, 0xc1, 0x61, 0x32, 0x23, 0xfc, 0x9b, 0x55, 0x48, 0x53, 0x99, 0xf7, 0x63, 0xd0, 0x99, 0xce, 0x01, 0xe0, 0x9f, 0xeb, 0x28 } } }, + { { { 0x47, 0xfc, 0xab, 0x5a, 0x17, 0xf0, 0x85, 0x56, 0x3a, 0x30, 0x86, 0x20, 0x28, 0x4b, 0x8e, 0x44, 0x74, 0x3a, 0x6e, 0x02, 0xf1, 0x32, 0x8f, 0x9f, 0x3f, 0x08, 0x35, 0xe9, 0xca, 0x16, 0x5f, 0x6e } }, + { { 0x1c, 0x59, 0x1c, 0x65, 0x5d, 0x34, 0xa4, 0x09, 0xcd, 0x13, 0x9c, 0x70, 0x7d, 0xb1, 0x2a, 0xc5, 0x88, 0xaf, 0x0b, 0x60, 0xc7, 0x9f, 0x34, 0x8d, 0xd6, 0xb7, 0x7f, 0xea, 0x78, 0x65, 0x8d, 0x77 } } }, + { { { 0x56, 0xa5, 0xc2, 0x0c, 0xdd, 0xbc, 0xb8, 0x20, 0x6d, 0x57, 0x61, 0xb5, 0xfb, 0x78, 0xb5, 0xd4, 0x49, 0x54, 0x90, 0x26, 0xc1, 0xcb, 0xe9, 0xe6, 0xbf, 0xec, 0x1d, 0x4e, 0xed, 0x07, 0x7e, 0x5e } }, + { { 0xc7, 0xf6, 0x6c, 0x56, 0x31, 0x20, 0x14, 0x0e, 0xa8, 0xd9, 0x27, 0xc1, 0x9a, 0x3d, 0x1b, 0x7d, 0x0e, 0x26, 0xd3, 0x81, 0xaa, 0xeb, 0xf5, 0x6b, 0x79, 0x02, 0xf1, 0x51, 0x5c, 0x75, 0x55, 0x0f } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0x0a, 0x34, 0xcd, 0x82, 0x3c, 0x33, 0x09, 0x54, 0xd2, 0x61, 0x39, 0x30, 0x9b, 0xfd, 0xef, 0x21, 0x26, 0xd4, 0x70, 0xfa, 0xee, 0xf9, 0x31, 0x33, 0x73, 0x84, 0xd0, 0xb3, 0x81, 0xbf, 0xec, 0x2e } }, + { { 0xe8, 0x93, 0x8b, 0x00, 0x64, 0xf7, 0x9c, 0xb8, 0x74, 0xe0, 0xe6, 0x49, 0x48, 0x4d, 0x4d, 0x48, 0xb6, 0x19, 0xa1, 0x40, 0xb7, 0xd9, 0x32, 0x41, 0x7c, 0x82, 0x37, 0xa1, 0x2d, 0xdc, 0xd2, 0x54 } } }, + { { { 0x68, 0x2b, 0x4a, 0x5b, 0xd5, 0xc7, 0x51, 0x91, 0x1d, 0xe1, 0x2a, 0x4b, 0xc4, 0x47, 0xf1, 0xbc, 0x7a, 0xb3, 0xcb, 0xc8, 0xb6, 0x7c, 0xac, 0x90, 0x05, 0xfd, 0xf3, 0xf9, 0x52, 0x3a, 0x11, 0x6b } }, + { { 0x3d, 0xc1, 0x27, 0xf3, 0x59, 0x43, 0x95, 0x90, 0xc5, 0x96, 0x79, 0xf5, 0xf4, 0x95, 0x65, 0x29, 0x06, 0x9c, 0x51, 0x05, 0x18, 0xda, 0xb8, 0x2e, 0x79, 0x7e, 0x69, 0x59, 0x71, 0x01, 0xeb, 0x1a } } }, + { { { 0x15, 0x06, 0x49, 0xb6, 0x8a, 0x3c, 0xea, 0x2f, 0x34, 0x20, 0x14, 0xc3, 0xaa, 0xd6, 0xaf, 0x2c, 0x3e, 0xbd, 0x65, 0x20, 0xe2, 0x4d, 0x4b, 0x3b, 0xeb, 0x9f, 0x4a, 0xc3, 0xad, 0xa4, 0x3b, 0x60 } }, + { { 0xbc, 0x58, 0xe6, 0xc0, 0x95, 0x2a, 0x2a, 0x81, 0x9a, 0x7a, 0xf3, 0xd2, 0x06, 0xbe, 0x48, 0xbc, 0x0c, 0xc5, 0x46, 0xe0, 0x6a, 0xd4, 0xac, 0x0f, 0xd9, 0xcc, 0x82, 0x34, 0x2c, 0xaf, 0xdb, 0x1f } } }, + { { { 0xf7, 0x17, 0x13, 0xbd, 0xfb, 0xbc, 0xd2, 0xec, 0x45, 0xb3, 0x15, 0x31, 0xe9, 0xaf, 0x82, 0x84, 0x3d, 0x28, 0xc6, 0xfc, 0x11, 0xf5, 0x41, 0xb5, 0x8b, 0xd3, 0x12, 0x76, 0x52, 0xe7, 0x1a, 0x3c } }, + { { 0x4e, 0x36, 0x11, 0x07, 0xa2, 0x15, 0x20, 0x51, 0xc4, 0x2a, 0xc3, 0x62, 0x8b, 0x5e, 0x7f, 0xa6, 0x0f, 0xf9, 0x45, 0x85, 0x6c, 0x11, 0x86, 0xb7, 0x7e, 0xe5, 0xd7, 0xf9, 0xc3, 0x91, 0x1c, 0x05 } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0xea, 0xd6, 0xde, 0x29, 0x3a, 0x00, 0xb9, 0x02, 0x59, 0xcb, 0x26, 0xc4, 0xba, 0x99, 0xb1, 0x97, 0x2f, 0x8e, 0x00, 0x92, 0x26, 0x4f, 0x52, 0xeb, 0x47, 0x1b, 0x89, 0x8b, 0x24, 0xc0, 0x13, 0x7d } }, + { { 0xd5, 0x20, 0x5b, 0x80, 0xa6, 0x80, 0x20, 0x95, 0xc3, 0xe9, 0x9f, 0x8e, 0x87, 0x9e, 0x1e, 0x9e, 0x7a, 0xc7, 0xcc, 0x75, 0x6c, 0xa5, 0xf1, 0x91, 0x1a, 0xa8, 0x01, 0x2c, 0xab, 0x76, 0xa9, 0x59 } } }, + { { { 0xde, 0xc9, 0xb1, 0x31, 0x10, 0x16, 0xaa, 0x35, 0x14, 0x6a, 0xd4, 0xb5, 0x34, 0x82, 0x71, 0xd2, 0x4a, 0x5d, 0x9a, 0x1f, 0x53, 0x26, 0x3c, 0xe5, 0x8e, 0x8d, 0x33, 0x7f, 0xff, 0xa9, 0xd5, 0x17 } }, + { { 0x89, 0xaf, 0xf6, 0xa4, 0x64, 0xd5, 0x10, 0xe0, 0x1d, 0xad, 0xef, 0x44, 0xbd, 0xda, 0x83, 0xac, 0x7a, 0xa8, 0xf0, 0x1c, 0x07, 0xf9, 0xc3, 0x43, 0x6c, 0x3f, 0xb7, 0xd3, 0x87, 0x22, 0x02, 0x73 } } }, + { { { 0x64, 0x1d, 0x49, 0x13, 0x2f, 0x71, 0xec, 0x69, 0x87, 0xd0, 0x42, 0xee, 0x13, 0xec, 0xe3, 0xed, 0x56, 0x7b, 0xbf, 0xbd, 0x8c, 0x2f, 0x7d, 0x7b, 0x9d, 0x28, 0xec, 0x8e, 0x76, 0x2f, 0x6f, 0x08 } }, + { { 0x22, 0xf5, 0x5f, 0x4d, 0x15, 0xef, 0xfc, 0x4e, 0x57, 0x03, 0x36, 0x89, 0xf0, 0xeb, 0x5b, 0x91, 0xd6, 0xe2, 0xca, 0x01, 0xa5, 0xee, 0x52, 0xec, 0xa0, 0x3c, 0x8f, 0x33, 0x90, 0x5a, 0x94, 0x72 } } }, + { { { 0x8a, 0x4b, 0xe7, 0x38, 0xbc, 0xda, 0xc2, 0xb0, 0x85, 0xe1, 0x4a, 0xfe, 0x2d, 0x44, 0x84, 0xcb, 0x20, 0x6b, 0x2d, 0xbf, 0x11, 0x9c, 0xd7, 0xbe, 0xd3, 0x3e, 0x5f, 0xbf, 0x68, 0xbc, 0xa8, 0x07 } }, + { { 0x01, 0x89, 0x28, 0x22, 0x6a, 0x78, 0xaa, 0x29, 0x03, 0xc8, 0x74, 0x95, 0x03, 0x3e, 0xdc, 0xbd, 0x07, 0x13, 0xa8, 0xa2, 0x20, 0x2d, 0xb3, 0x18, 0x70, 0x42, 0xfd, 0x7a, 0xc4, 0xd7, 0x49, 0x72 } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0x02, 0xff, 0x32, 0x2b, 0x5c, 0x93, 0x54, 0x32, 0xe8, 0x57, 0x54, 0x1a, 0x8b, 0x33, 0x60, 0x65, 0xd3, 0x67, 0xa4, 0xc1, 0x26, 0xc4, 0xa4, 0x34, 0x1f, 0x9b, 0xa7, 0xa9, 0xf4, 0xd9, 0x4f, 0x5b } }, + { { 0x46, 0x8d, 0xb0, 0x33, 0x54, 0x26, 0x5b, 0x68, 0xdf, 0xbb, 0xc5, 0xec, 0xc2, 0xf9, 0x3c, 0x5a, 0x37, 0xc1, 0x8e, 0x27, 0x47, 0xaa, 0x49, 0x5a, 0xf8, 0xfb, 0x68, 0x04, 0x23, 0xd1, 0xeb, 0x40 } } }, + { { { 0x65, 0xa5, 0x11, 0x84, 0x8a, 0x67, 0x9d, 0x9e, 0xd1, 0x44, 0x68, 0x7a, 0x34, 0xe1, 0x9f, 0xa3, 0x54, 0xcd, 0x07, 0xca, 0x79, 0x1f, 0x54, 0x2f, 0x13, 0x70, 0x4e, 0xee, 0xa2, 0xfa, 0xe7, 0x5d } }, + { { 0x36, 0xec, 0x54, 0xf8, 0xce, 0xe4, 0x85, 0xdf, 0xf6, 0x6f, 0x1d, 0x90, 0x08, 0xbc, 0xe8, 0xc0, 0x92, 0x2d, 0x43, 0x6b, 0x92, 0xa9, 0x8e, 0xab, 0x0a, 0x2e, 0x1c, 0x1e, 0x64, 0x23, 0x9f, 0x2c } } }, + { { { 0xa7, 0xd6, 0x2e, 0xd5, 0xcc, 0xd4, 0xcb, 0x5a, 0x3b, 0xa7, 0xf9, 0x46, 0x03, 0x1d, 0xad, 0x2b, 0x34, 0x31, 0x90, 0x00, 0x46, 0x08, 0x82, 0x14, 0xc4, 0xe0, 0x9c, 0xf0, 0xe3, 0x55, 0x43, 0x31 } }, + { { 0x60, 0xd6, 0xdd, 0x78, 0xe6, 0xd4, 0x22, 0x42, 0x1f, 0x00, 0xf9, 0xb1, 0x6a, 0x63, 0xe2, 0x92, 0x59, 0xd1, 0x1a, 0xb7, 0x00, 0x54, 0x29, 0xc9, 0xc1, 0xf6, 0x6f, 0x7a, 0xc5, 0x3c, 0x5f, 0x65 } } }, + { { { 0x27, 0x4f, 0xd0, 0x72, 0xb1, 0x11, 0x14, 0x27, 0x15, 0x94, 0x48, 0x81, 0x7e, 0x74, 0xd8, 0x32, 0xd5, 0xd1, 0x11, 0x28, 0x60, 0x63, 0x36, 0x32, 0x37, 0xb5, 0x13, 0x1c, 0xa0, 0x37, 0xe3, 0x74 } }, + { { 0xf1, 0x25, 0x4e, 0x11, 0x96, 0x67, 0xe6, 0x1c, 0xc2, 0xb2, 0x53, 0xe2, 0xda, 0x85, 0xee, 0xb2, 0x9f, 0x59, 0xf3, 0xba, 0xbd, 0xfa, 0xcf, 0x6e, 0xf9, 0xda, 0xa4, 0xb3, 0x02, 0x8f, 0x64, 0x08 } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0x34, 0x94, 0xf2, 0x64, 0x54, 0x47, 0x37, 0x07, 0x40, 0x8a, 0x20, 0xba, 0x4a, 0x55, 0xd7, 0x3f, 0x47, 0xba, 0x25, 0x23, 0x14, 0xb0, 0x2c, 0xe8, 0x55, 0xa8, 0xa6, 0xef, 0x51, 0xbd, 0x6f, 0x6a } }, + { { 0x71, 0xd6, 0x16, 0x76, 0xb2, 0x06, 0xea, 0x79, 0xf5, 0xc4, 0xc3, 0x52, 0x7e, 0x61, 0xd1, 0xe1, 0xad, 0x70, 0x78, 0x1d, 0x16, 0x11, 0xf8, 0x7c, 0x2b, 0xfc, 0x55, 0x9f, 0x52, 0xf8, 0xf5, 0x16 } } }, + { { { 0x34, 0x96, 0x9a, 0xf6, 0xc5, 0xe0, 0x14, 0x03, 0x24, 0x0e, 0x4c, 0xad, 0x9e, 0x9a, 0x70, 0x23, 0x96, 0xb2, 0xf1, 0x2e, 0x9d, 0xc3, 0x32, 0x9b, 0x54, 0xa5, 0x73, 0xde, 0x88, 0xb1, 0x3e, 0x24 } }, + { { 0xf6, 0xe2, 0x4c, 0x1f, 0x5b, 0xb2, 0xaf, 0x82, 0xa5, 0xcf, 0x81, 0x10, 0x04, 0xef, 0xdb, 0xa2, 0xcc, 0x24, 0xb2, 0x7e, 0x0b, 0x7a, 0xeb, 0x01, 0xd8, 0x52, 0xf4, 0x51, 0x89, 0x29, 0x79, 0x37 } } }, + { { { 0x74, 0xde, 0x12, 0xf3, 0x68, 0xb7, 0x66, 0xc3, 0xee, 0x68, 0xdc, 0x81, 0xb5, 0x55, 0x99, 0xab, 0xd9, 0x28, 0x63, 0x6d, 0x8b, 0x40, 0x69, 0x75, 0x6c, 0xcd, 0x5c, 0x2a, 0x7e, 0x32, 0x7b, 0x29 } }, + { { 0x02, 0xcc, 0x22, 0x74, 0x4d, 0x19, 0x07, 0xc0, 0xda, 0xb5, 0x76, 0x51, 0x2a, 0xaa, 0xa6, 0x0a, 0x5f, 0x26, 0xd4, 0xbc, 0xaf, 0x48, 0x88, 0x7f, 0x02, 0xbc, 0xf2, 0xe1, 0xcf, 0xe9, 0xdd, 0x15 } } }, + { { { 0xed, 0xb5, 0x9a, 0x8c, 0x9a, 0xdd, 0x27, 0xf4, 0x7f, 0x47, 0xd9, 0x52, 0xa7, 0xcd, 0x65, 0xa5, 0x31, 0x22, 0xed, 0xa6, 0x63, 0x5b, 0x80, 0x4a, 0xad, 0x4d, 0xed, 0xbf, 0xee, 0x49, 0xb3, 0x06 } }, + { { 0xf8, 0x64, 0x8b, 0x60, 0x90, 0xe9, 0xde, 0x44, 0x77, 0xb9, 0x07, 0x36, 0x32, 0xc2, 0x50, 0xf5, 0x65, 0xdf, 0x48, 0x4c, 0x37, 0xaa, 0x68, 0xab, 0x9a, 0x1f, 0x3e, 0xff, 0x89, 0x92, 0xa0, 0x07 } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0x7d, 0x4f, 0x9c, 0x19, 0xc0, 0x4a, 0x31, 0xec, 0xf9, 0xaa, 0xeb, 0xb2, 0x16, 0x9c, 0xa3, 0x66, 0x5f, 0xd1, 0xd4, 0xed, 0xb8, 0x92, 0x1c, 0xab, 0xda, 0xea, 0xd9, 0x57, 0xdf, 0x4c, 0x2a, 0x48 } }, + { { 0x4b, 0xb0, 0x4e, 0x6e, 0x11, 0x3b, 0x51, 0xbd, 0x6a, 0xfd, 0xe4, 0x25, 0xa5, 0x5f, 0x11, 0x3f, 0x98, 0x92, 0x51, 0x14, 0xc6, 0x5f, 0x3c, 0x0b, 0xa8, 0xf7, 0xc2, 0x81, 0x43, 0xde, 0x91, 0x73 } } }, + { { { 0x3c, 0x8f, 0x9f, 0x33, 0x2a, 0x1f, 0x43, 0x33, 0x8f, 0x68, 0xff, 0x1f, 0x3d, 0x73, 0x6b, 0xbf, 0x68, 0xcc, 0x7d, 0x13, 0x6c, 0x24, 0x4b, 0xcc, 0x4d, 0x24, 0x0d, 0xfe, 0xde, 0x86, 0xad, 0x3b } }, + { { 0x79, 0x51, 0x81, 0x01, 0xdc, 0x73, 0x53, 0xe0, 0x6e, 0x9b, 0xea, 0x68, 0x3f, 0x5c, 0x14, 0x84, 0x53, 0x8d, 0x4b, 0xc0, 0x9f, 0x9f, 0x89, 0x2b, 0x8c, 0xba, 0x86, 0xfa, 0xf2, 0xcd, 0xe3, 0x2d } } }, + { { { 0x06, 0xf9, 0x29, 0x5a, 0xdb, 0x3d, 0x84, 0x52, 0xab, 0xcc, 0x6b, 0x60, 0x9d, 0xb7, 0x4a, 0x0e, 0x36, 0x63, 0x91, 0xad, 0xa0, 0x95, 0xb0, 0x97, 0x89, 0x4e, 0xcf, 0x7d, 0x3c, 0xe5, 0x7c, 0x28 } }, + { { 0x2e, 0x69, 0x98, 0xfd, 0xc6, 0xbd, 0xcc, 0xca, 0xdf, 0x9a, 0x44, 0x7e, 0x9d, 0xca, 0x89, 0x6d, 0xbf, 0x27, 0xc2, 0xf8, 0xcd, 0x46, 0x00, 0x2b, 0xb5, 0x58, 0x4e, 0xb7, 0x89, 0x09, 0xe9, 0x2d } } }, + { { { 0x54, 0xbe, 0x75, 0xcb, 0x05, 0xb0, 0x54, 0xb7, 0xe7, 0x26, 0x86, 0x4a, 0xfc, 0x19, 0xcf, 0x27, 0x46, 0xd4, 0x22, 0x96, 0x5a, 0x11, 0xe8, 0xd5, 0x1b, 0xed, 0x71, 0xc5, 0x5d, 0xc8, 0xaf, 0x45 } }, + { { 0x40, 0x7b, 0x77, 0x57, 0x49, 0x9e, 0x80, 0x39, 0x23, 0xee, 0x81, 0x0b, 0x22, 0xcf, 0xdb, 0x7a, 0x2f, 0x14, 0xb8, 0x57, 0x8f, 0xa1, 0x39, 0x1e, 0x77, 0xfc, 0x0b, 0xa6, 0xbf, 0x8a, 0x0c, 0x6c } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0x77, 0x3a, 0xd4, 0xd8, 0x27, 0xcf, 0xe8, 0xa1, 0x72, 0x9d, 0xca, 0xdd, 0x0d, 0x96, 0xda, 0x79, 0xed, 0x56, 0x42, 0x15, 0x60, 0xc7, 0x1c, 0x6b, 0x26, 0x30, 0xf6, 0x6a, 0x95, 0x67, 0xf3, 0x0a } }, + { { 0xc5, 0x08, 0xa4, 0x2b, 0x2f, 0xbd, 0x31, 0x81, 0x2a, 0xa6, 0xb6, 0xe4, 0x00, 0x91, 0xda, 0x3d, 0xb2, 0xb0, 0x96, 0xce, 0x8a, 0xd2, 0x8d, 0x70, 0xb3, 0xd3, 0x34, 0x01, 0x90, 0x8d, 0x10, 0x21 } } }, + { { { 0x33, 0x0d, 0xe7, 0xba, 0x4f, 0x07, 0xdf, 0x8d, 0xea, 0x7d, 0xa0, 0xc5, 0xd6, 0xb1, 0xb0, 0xe5, 0x57, 0x1b, 0x5b, 0xf5, 0x45, 0x13, 0x14, 0x64, 0x5a, 0xeb, 0x5c, 0xfc, 0x54, 0x01, 0x76, 0x2b } }, + { { 0x02, 0x0c, 0xc2, 0xaf, 0x96, 0x36, 0xfe, 0x4a, 0xe2, 0x54, 0x20, 0x6a, 0xeb, 0xb2, 0x9f, 0x62, 0xd7, 0xce, 0xa2, 0x3f, 0x20, 0x11, 0x34, 0x37, 0xe0, 0x42, 0xed, 0x6f, 0xf9, 0x1a, 0xc8, 0x7d } } }, + { { { 0xd8, 0xb9, 0x11, 0xe8, 0x36, 0x3f, 0x42, 0xc1, 0xca, 0xdc, 0xd3, 0xf1, 0xc8, 0x23, 0x3d, 0x4f, 0x51, 0x7b, 0x9d, 0x8d, 0xd8, 0xe4, 0xa0, 0xaa, 0xf3, 0x04, 0xd6, 0x11, 0x93, 0xc8, 0x35, 0x45 } }, + { { 0x61, 0x36, 0xd6, 0x08, 0x90, 0xbf, 0xa7, 0x7a, 0x97, 0x6c, 0x0f, 0x84, 0xd5, 0x33, 0x2d, 0x37, 0xc9, 0x6a, 0x80, 0x90, 0x3d, 0x0a, 0xa2, 0xaa, 0xe1, 0xb8, 0x84, 0xba, 0x61, 0x36, 0xdd, 0x69 } } }, + { { { 0x6b, 0xdb, 0x5b, 0x9c, 0xc6, 0x92, 0xbc, 0x23, 0xaf, 0xc5, 0xb8, 0x75, 0xf8, 0x42, 0xfa, 0xd6, 0xb6, 0x84, 0x94, 0x63, 0x98, 0x93, 0x48, 0x78, 0x38, 0xcd, 0xbb, 0x18, 0x34, 0xc3, 0xdb, 0x67 } }, + { { 0x96, 0xf3, 0x3a, 0x09, 0x56, 0xb0, 0x6f, 0x7c, 0x51, 0x1e, 0x1b, 0x39, 0x48, 0xea, 0xc9, 0x0c, 0x25, 0xa2, 0x7a, 0xca, 0xe7, 0x92, 0xfc, 0x59, 0x30, 0xa3, 0x89, 0x85, 0xdf, 0x6f, 0x43, 0x38 } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0x79, 0x84, 0x44, 0x19, 0xbd, 0xe9, 0x54, 0xc4, 0xc0, 0x6e, 0x2a, 0xa8, 0xa8, 0x9b, 0x43, 0xd5, 0x71, 0x22, 0x5f, 0xdc, 0x01, 0xfa, 0xdf, 0xb3, 0xb8, 0x47, 0x4b, 0x0a, 0xa5, 0x44, 0xea, 0x29 } }, + { { 0x05, 0x90, 0x50, 0xaf, 0x63, 0x5f, 0x9d, 0x9e, 0xe1, 0x9d, 0x38, 0x97, 0x1f, 0x6c, 0xac, 0x30, 0x46, 0xb2, 0x6a, 0x19, 0xd1, 0x4b, 0xdb, 0xbb, 0x8c, 0xda, 0x2e, 0xab, 0xc8, 0x5a, 0x77, 0x6c } } }, + { { { 0x2b, 0xbe, 0xaf, 0xa1, 0x6d, 0x2f, 0x0b, 0xb1, 0x8f, 0xe3, 0xe0, 0x38, 0xcd, 0x0b, 0x41, 0x1b, 0x4a, 0x15, 0x07, 0xf3, 0x6f, 0xdc, 0xb8, 0xe9, 0xde, 0xb2, 0xa3, 0x40, 0x01, 0xa6, 0x45, 0x1e } }, + { { 0x76, 0x0a, 0xda, 0x8d, 0x2c, 0x07, 0x3f, 0x89, 0x7d, 0x04, 0xad, 0x43, 0x50, 0x6e, 0xd2, 0x47, 0xcb, 0x8a, 0xe6, 0x85, 0x1a, 0x24, 0xf3, 0xd2, 0x60, 0xfd, 0xdf, 0x73, 0xa4, 0x0d, 0x73, 0x0e } } }, + { { { 0xfd, 0x67, 0x6b, 0x71, 0x9b, 0x81, 0x53, 0x39, 0x39, 0xf4, 0xb8, 0xd5, 0xc3, 0x30, 0x9b, 0x3b, 0x7c, 0xa3, 0xf0, 0xd0, 0x84, 0x21, 0xd6, 0xbf, 0xb7, 0x4c, 0x87, 0x13, 0x45, 0x2d, 0xa7, 0x55 } }, + { { 0x5d, 0x04, 0xb3, 0x40, 0x28, 0x95, 0x2d, 0x30, 0x83, 0xec, 0x5e, 0xe4, 0xff, 0x75, 0xfe, 0x79, 0x26, 0x9d, 0x1d, 0x36, 0xcd, 0x0a, 0x15, 0xd2, 0x24, 0x14, 0x77, 0x71, 0xd7, 0x8a, 0x1b, 0x04 } } }, + { { { 0x5d, 0x93, 0xc9, 0xbe, 0xaa, 0x90, 0xcd, 0x9b, 0xfb, 0x73, 0x7e, 0xb0, 0x64, 0x98, 0x57, 0x44, 0x42, 0x41, 0xb1, 0xaf, 0xea, 0xc1, 0xc3, 0x22, 0xff, 0x60, 0x46, 0xcb, 0x61, 0x81, 0x70, 0x61 } }, + { { 0x0d, 0x82, 0xb9, 0xfe, 0x21, 0xcd, 0xc4, 0xf5, 0x98, 0x0c, 0x4e, 0x72, 0xee, 0x87, 0x49, 0xf8, 0xa1, 0x95, 0xdf, 0x8f, 0x2d, 0xbd, 0x21, 0x06, 0x7c, 0x15, 0xe8, 0x12, 0x6d, 0x93, 0xd6, 0x38 } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0x91, 0xf7, 0x51, 0xd9, 0xef, 0x7d, 0x42, 0x01, 0x13, 0xe9, 0xb8, 0x7f, 0xa6, 0x49, 0x17, 0x64, 0x21, 0x80, 0x83, 0x2c, 0x63, 0x4c, 0x60, 0x09, 0x59, 0x91, 0x92, 0x77, 0x39, 0x51, 0xf4, 0x48 } }, + { { 0x60, 0xd5, 0x22, 0x83, 0x08, 0x2f, 0xff, 0x99, 0x3e, 0x69, 0x6d, 0x88, 0xda, 0xe7, 0x5b, 0x52, 0x26, 0x31, 0x2a, 0xe5, 0x89, 0xde, 0x68, 0x90, 0xb6, 0x22, 0x5a, 0xbd, 0xd3, 0x85, 0x53, 0x31 } } }, + { { { 0xd8, 0xce, 0xdc, 0xf9, 0x3c, 0x4b, 0xa2, 0x1d, 0x2c, 0x2f, 0x36, 0xbe, 0x7a, 0xfc, 0xcd, 0xbc, 0xdc, 0xf9, 0x30, 0xbd, 0xff, 0x05, 0xc7, 0xe4, 0x8e, 0x17, 0x62, 0xf8, 0x4d, 0xa0, 0x56, 0x79 } }, + { { 0x82, 0xe7, 0xf6, 0xba, 0x53, 0x84, 0x0a, 0xa3, 0x34, 0xff, 0x3c, 0xa3, 0x6a, 0xa1, 0x37, 0xea, 0xdd, 0xb6, 0x95, 0xb3, 0x78, 0x19, 0x76, 0x1e, 0x55, 0x2f, 0x77, 0x2e, 0x7f, 0xc1, 0xea, 0x5e } } }, + { { { 0x83, 0xe1, 0x6e, 0xa9, 0x07, 0x33, 0x3e, 0x83, 0xff, 0xcb, 0x1c, 0x9f, 0xb1, 0xa3, 0xb4, 0xc9, 0xe1, 0x07, 0x97, 0xff, 0xf8, 0x23, 0x8f, 0xce, 0x40, 0xfd, 0x2e, 0x5e, 0xdb, 0x16, 0x43, 0x2d } }, + { { 0xba, 0x38, 0x02, 0xf7, 0x81, 0x43, 0x83, 0xa3, 0x20, 0x4f, 0x01, 0x3b, 0x8a, 0x04, 0x38, 0x31, 0xc6, 0x0f, 0xc8, 0xdf, 0xd7, 0xfa, 0x2f, 0x88, 0x3f, 0xfc, 0x0c, 0x76, 0xc4, 0xa6, 0x45, 0x72 } } }, + { { { 0xbb, 0x0c, 0xbc, 0x6a, 0xa4, 0x97, 0x17, 0x93, 0x2d, 0x6f, 0xde, 0x72, 0x10, 0x1c, 0x08, 0x2c, 0x0f, 0x80, 0x32, 0x68, 0x27, 0xd4, 0xab, 0xdd, 0xc5, 0x58, 0x61, 0x13, 0x6d, 0x11, 0x1e, 0x4d } }, + { { 0x1a, 0xb9, 0xc9, 0x10, 0xfb, 0x1e, 0x4e, 0xf4, 0x84, 0x4b, 0x8a, 0x5e, 0x7b, 0x4b, 0xe8, 0x43, 0x8c, 0x8f, 0x00, 0xb5, 0x54, 0x13, 0xc5, 0x5c, 0xb6, 0x35, 0x4e, 0x9d, 0xe4, 0x5b, 0x41, 0x6d } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0x15, 0x7d, 0x12, 0x48, 0x82, 0x14, 0x42, 0xcd, 0x32, 0xd4, 0x4b, 0xc1, 0x72, 0x61, 0x2a, 0x8c, 0xec, 0xe2, 0xf8, 0x24, 0x45, 0x94, 0xe3, 0xbe, 0xdd, 0x67, 0xa8, 0x77, 0x5a, 0xae, 0x5b, 0x4b } }, + { { 0xcb, 0x77, 0x9a, 0x20, 0xde, 0xb8, 0x23, 0xd9, 0xa0, 0x0f, 0x8c, 0x7b, 0xa5, 0xcb, 0xae, 0xb6, 0xec, 0x42, 0x67, 0x0e, 0x58, 0xa4, 0x75, 0x98, 0x21, 0x71, 0x84, 0xb3, 0xe0, 0x76, 0x94, 0x73 } } }, + { { { 0xdf, 0xfc, 0x69, 0x28, 0x23, 0x3f, 0x5b, 0xf8, 0x3b, 0x24, 0x37, 0xf3, 0x1d, 0xd5, 0x22, 0x6b, 0xd0, 0x98, 0xa8, 0x6c, 0xcf, 0xff, 0x06, 0xe1, 0x13, 0xdf, 0xb9, 0xc1, 0x0c, 0xa9, 0xbf, 0x33 } }, + { { 0xd9, 0x81, 0xda, 0xb2, 0x4f, 0x82, 0x9d, 0x43, 0x81, 0x09, 0xf1, 0xd2, 0x01, 0xef, 0xac, 0xf4, 0x2d, 0x7d, 0x01, 0x09, 0xf1, 0xff, 0xa5, 0x9f, 0xe5, 0xca, 0x27, 0x63, 0xdb, 0x20, 0xb1, 0x53 } } }, + { { { 0x67, 0x02, 0xe8, 0xad, 0xa9, 0x34, 0xd4, 0xf0, 0x15, 0x81, 0xaa, 0xc7, 0x4d, 0x87, 0x94, 0xea, 0x75, 0xe7, 0x4c, 0x94, 0x04, 0x0e, 0x69, 0x87, 0xe7, 0x51, 0x91, 0x10, 0x03, 0xc7, 0xbe, 0x56 } }, + { { 0x32, 0xfb, 0x86, 0xec, 0x33, 0x6b, 0x2e, 0x51, 0x2b, 0xc8, 0xfa, 0x6c, 0x70, 0x47, 0x7e, 0xce, 0x05, 0x0c, 0x71, 0xf3, 0xb4, 0x56, 0xa6, 0xdc, 0xcc, 0x78, 0x07, 0x75, 0xd0, 0xdd, 0xb2, 0x6a } } }, + { { { 0xc6, 0xef, 0xb9, 0xc0, 0x2b, 0x22, 0x08, 0x1e, 0x71, 0x70, 0xb3, 0x35, 0x9c, 0x7a, 0x01, 0x92, 0x44, 0x9a, 0xf6, 0xb0, 0x58, 0x95, 0xc1, 0x9b, 0x02, 0xed, 0x2d, 0x7c, 0x34, 0x29, 0x49, 0x44 } }, + { { 0x45, 0x62, 0x1d, 0x2e, 0xff, 0x2a, 0x1c, 0x21, 0xa4, 0x25, 0x7b, 0x0d, 0x8c, 0x15, 0x39, 0xfc, 0x8f, 0x7c, 0xa5, 0x7d, 0x1e, 0x25, 0xa3, 0x45, 0xd6, 0xab, 0xbd, 0xcb, 0xc5, 0x5e, 0x78, 0x77 } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0xd0, 0xd3, 0x42, 0xed, 0x1d, 0x00, 0x3c, 0x15, 0x2c, 0x9c, 0x77, 0x81, 0xd2, 0x73, 0xd1, 0x06, 0xd5, 0xc4, 0x7f, 0x94, 0xbb, 0x92, 0x2d, 0x2c, 0x4b, 0x45, 0x4b, 0xe9, 0x2a, 0x89, 0x6b, 0x2b } }, + { { 0xd2, 0x0c, 0x88, 0xc5, 0x48, 0x4d, 0xea, 0x0d, 0x4a, 0xc9, 0x52, 0x6a, 0x61, 0x79, 0xe9, 0x76, 0xf3, 0x85, 0x52, 0x5c, 0x1b, 0x2c, 0xe1, 0xd6, 0xc4, 0x0f, 0x18, 0x0e, 0x4e, 0xf6, 0x1c, 0x7f } } }, + { { { 0xb4, 0x04, 0x2e, 0x42, 0xcb, 0x1f, 0x2b, 0x11, 0x51, 0x7b, 0x08, 0xac, 0xaa, 0x3e, 0x9e, 0x52, 0x60, 0xb7, 0xc2, 0x61, 0x57, 0x8c, 0x84, 0xd5, 0x18, 0xa6, 0x19, 0xfc, 0xb7, 0x75, 0x91, 0x1b } }, + { { 0xe8, 0x68, 0xca, 0x44, 0xc8, 0x38, 0x38, 0xcc, 0x53, 0x0a, 0x32, 0x35, 0xcc, 0x52, 0xcb, 0x0e, 0xf7, 0xc5, 0xe7, 0xec, 0x3d, 0x85, 0xcc, 0x58, 0xe2, 0x17, 0x47, 0xff, 0x9f, 0xa5, 0x30, 0x17 } } }, + { { { 0xe3, 0xae, 0xc8, 0xc1, 0x71, 0x75, 0x31, 0x00, 0x37, 0x41, 0x5c, 0x0e, 0x39, 0xda, 0x73, 0xa0, 0xc7, 0x97, 0x36, 0x6c, 0x5b, 0xf2, 0xee, 0x64, 0x0a, 0x3d, 0x89, 0x1e, 0x1d, 0x49, 0x8c, 0x37 } }, + { { 0x4c, 0xe6, 0xb0, 0xc1, 0xa5, 0x2a, 0x82, 0x09, 0x08, 0xad, 0x79, 0x9c, 0x56, 0xf6, 0xf9, 0xc1, 0xd7, 0x7c, 0x39, 0x7f, 0x93, 0xca, 0x11, 0x55, 0xbf, 0x07, 0x1b, 0x82, 0x29, 0x69, 0x95, 0x5c } } }, + { { { 0x87, 0xee, 0xa6, 0x56, 0x9e, 0xc2, 0x9a, 0x56, 0x24, 0x42, 0x85, 0x4d, 0x98, 0x31, 0x1e, 0x60, 0x4d, 0x87, 0x85, 0x04, 0xae, 0x46, 0x12, 0xf9, 0x8e, 0x7f, 0xe4, 0x7f, 0xf6, 0x1c, 0x37, 0x01 } }, + { { 0x73, 0x4c, 0xb6, 0xc5, 0xc4, 0xe9, 0x6c, 0x85, 0x48, 0x4a, 0x5a, 0xac, 0xd9, 0x1f, 0x43, 0xf8, 0x62, 0x5b, 0xee, 0x98, 0x2a, 0x33, 0x8e, 0x79, 0xce, 0x61, 0x06, 0x35, 0xd8, 0xd7, 0xca, 0x71 } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0x72, 0xd3, 0xae, 0xa6, 0xca, 0x8f, 0xcd, 0xcc, 0x78, 0x8e, 0x19, 0x4d, 0xa7, 0xd2, 0x27, 0xe9, 0xa4, 0x3c, 0x16, 0x5b, 0x84, 0x80, 0xf9, 0xd0, 0xcc, 0x6a, 0x1e, 0xca, 0x1e, 0x67, 0xbd, 0x63 } }, + { { 0x7b, 0x6e, 0x2a, 0xd2, 0x87, 0x48, 0xff, 0xa1, 0xca, 0xe9, 0x15, 0x85, 0xdc, 0xdb, 0x2c, 0x39, 0x12, 0x91, 0xa9, 0x20, 0xaa, 0x4f, 0x29, 0xf4, 0x15, 0x7a, 0xd2, 0xf5, 0x32, 0xcc, 0x60, 0x04 } } }, + { { { 0xe5, 0x10, 0x47, 0x3b, 0xfa, 0x90, 0xfc, 0x30, 0xb5, 0xea, 0x6f, 0x56, 0x8f, 0xfb, 0x0e, 0xa7, 0x3b, 0xc8, 0xb2, 0xff, 0x02, 0x7a, 0x33, 0x94, 0x93, 0x2a, 0x03, 0xe0, 0x96, 0x3a, 0x6c, 0x0f } }, + { { 0x5a, 0x63, 0x67, 0xe1, 0x9b, 0x47, 0x78, 0x9f, 0x38, 0x79, 0xac, 0x97, 0x66, 0x1d, 0x5e, 0x51, 0xee, 0x24, 0x42, 0xe8, 0x58, 0x4b, 0x8a, 0x03, 0x75, 0x86, 0x37, 0x86, 0xe2, 0x97, 0x4e, 0x3d } } }, + { { { 0x3f, 0x75, 0x8e, 0xb4, 0xff, 0xd8, 0xdd, 0xd6, 0x37, 0x57, 0x9d, 0x6d, 0x3b, 0xbd, 0xd5, 0x60, 0x88, 0x65, 0x9a, 0xb9, 0x4a, 0x68, 0x84, 0xa2, 0x67, 0xdd, 0x17, 0x25, 0x97, 0x04, 0x8b, 0x5e } }, + { { 0xbb, 0x40, 0x5e, 0xbc, 0x16, 0x92, 0x05, 0xc4, 0xc0, 0x4e, 0x72, 0x90, 0x0e, 0xab, 0xcf, 0x8a, 0xed, 0xef, 0xb9, 0x2d, 0x3b, 0xf8, 0x43, 0x5b, 0xba, 0x2d, 0xeb, 0x2f, 0x52, 0xd2, 0xd1, 0x5a } } }, + { { { 0x40, 0xb4, 0xab, 0xe6, 0xad, 0x9f, 0x46, 0x69, 0x4a, 0xb3, 0x8e, 0xaa, 0xea, 0x9c, 0x8a, 0x20, 0x16, 0x5d, 0x8c, 0x13, 0xbd, 0xf6, 0x1d, 0xc5, 0x24, 0xbd, 0x90, 0x2a, 0x1c, 0xc7, 0x13, 0x3b } }, + { { 0x54, 0xdc, 0x16, 0x0d, 0x18, 0xbe, 0x35, 0x64, 0x61, 0x52, 0x02, 0x80, 0xaf, 0x05, 0xf7, 0xa6, 0x42, 0xd3, 0x8f, 0x2e, 0x79, 0x26, 0xa8, 0xbb, 0xb2, 0x17, 0x48, 0xb2, 0x7a, 0x0a, 0x89, 0x14 } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0x20, 0xa8, 0x88, 0xe3, 0x91, 0xc0, 0x6e, 0xbb, 0x8a, 0x27, 0x82, 0x51, 0x83, 0xb2, 0x28, 0xa9, 0x83, 0xeb, 0xa6, 0xa9, 0x4d, 0x17, 0x59, 0x22, 0x54, 0x00, 0x50, 0x45, 0xcb, 0x48, 0x4b, 0x18 } }, + { { 0x33, 0x7c, 0xe7, 0x26, 0xba, 0x4d, 0x32, 0xfe, 0x53, 0xf4, 0xfa, 0x83, 0xe3, 0xa5, 0x79, 0x66, 0x73, 0xef, 0x80, 0x23, 0x68, 0xc2, 0x60, 0xdd, 0xa9, 0x33, 0xdc, 0x03, 0x7a, 0xe0, 0xe0, 0x3e } } }, + { { { 0x34, 0x5c, 0x13, 0xfb, 0xc0, 0xe3, 0x78, 0x2b, 0x54, 0x58, 0x22, 0x9b, 0x76, 0x81, 0x7f, 0x93, 0x9c, 0x25, 0x3c, 0xd2, 0xe9, 0x96, 0x21, 0x26, 0x08, 0xf5, 0xed, 0x95, 0x11, 0xae, 0x04, 0x5a } }, + { { 0xb9, 0xe8, 0xc5, 0x12, 0x97, 0x1f, 0x83, 0xfe, 0x3e, 0x94, 0x99, 0xd4, 0x2d, 0xf9, 0x52, 0x59, 0x5c, 0x82, 0xa6, 0xf0, 0x75, 0x7e, 0xe8, 0xec, 0xcc, 0xac, 0x18, 0x21, 0x09, 0x67, 0x66, 0x67 } } }, + { { { 0xb3, 0x40, 0x29, 0xd1, 0xcb, 0x1b, 0x08, 0x9e, 0x9c, 0xb7, 0x53, 0xb9, 0x3b, 0x71, 0x08, 0x95, 0x12, 0x1a, 0x58, 0xaf, 0x7e, 0x82, 0x52, 0x43, 0x4f, 0x11, 0x39, 0xf4, 0x93, 0x1a, 0x26, 0x05 } }, + { { 0x6e, 0x44, 0xa3, 0xf9, 0x64, 0xaf, 0xe7, 0x6d, 0x7d, 0xdf, 0x1e, 0xac, 0x04, 0xea, 0x3b, 0x5f, 0x9b, 0xe8, 0x24, 0x9d, 0x0e, 0xe5, 0x2e, 0x3e, 0xdf, 0xa9, 0xf7, 0xd4, 0x50, 0x71, 0xf0, 0x78 } } }, + { { { 0x3e, 0xa8, 0x38, 0xc2, 0x57, 0x56, 0x42, 0x9a, 0xb1, 0xe2, 0xf8, 0x45, 0xaa, 0x11, 0x48, 0x5f, 0x17, 0xc4, 0x54, 0x27, 0xdc, 0x5d, 0xaa, 0xdd, 0x41, 0xbc, 0xdf, 0x81, 0xb9, 0x53, 0xee, 0x52 } }, + { { 0xc3, 0xf1, 0xa7, 0x6d, 0xb3, 0x5f, 0x92, 0x6f, 0xcc, 0x91, 0xb8, 0x95, 0x05, 0xdf, 0x3c, 0x64, 0x57, 0x39, 0x61, 0x51, 0xad, 0x8c, 0x38, 0x7b, 0xc8, 0xde, 0x00, 0x34, 0xbe, 0xa1, 0xb0, 0x7e } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0x25, 0x24, 0x1d, 0x8a, 0x67, 0x20, 0xee, 0x42, 0xeb, 0x38, 0xed, 0x0b, 0x8b, 0xcd, 0x46, 0x9d, 0x5e, 0x6b, 0x1e, 0x24, 0x9d, 0x12, 0x05, 0x1a, 0xcc, 0x05, 0x4e, 0x92, 0x38, 0xe1, 0x1f, 0x50 } }, + { { 0x4e, 0xee, 0x1c, 0x91, 0xe6, 0x11, 0xbd, 0x8e, 0x55, 0x1a, 0x18, 0x75, 0x66, 0xaf, 0x4d, 0x7b, 0x0f, 0xae, 0x6d, 0x85, 0xca, 0x82, 0x58, 0x21, 0x9c, 0x18, 0xe0, 0xed, 0xec, 0x22, 0x80, 0x2f } } }, + { { { 0x68, 0x3b, 0x0a, 0x39, 0x1d, 0x6a, 0x15, 0x57, 0xfc, 0xf0, 0x63, 0x54, 0xdb, 0x39, 0xdb, 0xe8, 0x5c, 0x64, 0xff, 0xa0, 0x09, 0x4f, 0x3b, 0xb7, 0x32, 0x60, 0x99, 0x94, 0xfd, 0x94, 0x82, 0x2d } }, + { { 0x24, 0xf6, 0x5a, 0x44, 0xf1, 0x55, 0x2c, 0xdb, 0xea, 0x7c, 0x84, 0x7c, 0x01, 0xac, 0xe3, 0xfd, 0xc9, 0x27, 0xc1, 0x5a, 0xb9, 0xde, 0x4f, 0x5a, 0x90, 0xdd, 0xc6, 0x67, 0xaa, 0x6f, 0x8a, 0x3a } } }, + { { { 0x78, 0x52, 0x87, 0xc9, 0x97, 0x63, 0xb1, 0xdd, 0x54, 0x5f, 0xc1, 0xf8, 0xf1, 0x06, 0xa6, 0xa8, 0xa3, 0x88, 0x82, 0xd4, 0xcb, 0xa6, 0x19, 0xdd, 0xd1, 0x11, 0x87, 0x08, 0x17, 0x4c, 0x37, 0x2a } }, + { { 0xa1, 0x0c, 0xf3, 0x08, 0x43, 0xd9, 0x24, 0x1e, 0x83, 0xa7, 0xdf, 0x91, 0xca, 0xbd, 0x69, 0x47, 0x8d, 0x1b, 0xe2, 0xb9, 0x4e, 0xb5, 0xe1, 0x76, 0xb3, 0x1c, 0x93, 0x03, 0xce, 0x5f, 0xb3, 0x5a } } }, + { { { 0x1d, 0xda, 0xe4, 0x61, 0x03, 0x50, 0xa9, 0x8b, 0x68, 0x18, 0xef, 0xb2, 0x1c, 0x84, 0x3b, 0xa2, 0x44, 0x95, 0xa3, 0x04, 0x3b, 0xd6, 0x99, 0x00, 0xaf, 0x76, 0x42, 0x67, 0x02, 0x7d, 0x85, 0x56 } }, + { { 0xce, 0x72, 0x0e, 0x29, 0x84, 0xb2, 0x7d, 0xd2, 0x45, 0xbe, 0x57, 0x06, 0xed, 0x7f, 0xcf, 0xed, 0xcd, 0xef, 0x19, 0xd6, 0xbc, 0x15, 0x79, 0x64, 0xd2, 0x18, 0xe3, 0x20, 0x67, 0x3a, 0x54, 0x0b } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0x52, 0xfd, 0x04, 0xc5, 0xfb, 0x99, 0xe7, 0xe8, 0xfb, 0x8c, 0xe1, 0x42, 0x03, 0xef, 0x9d, 0xd9, 0x9e, 0x4d, 0xf7, 0x80, 0xcf, 0x2e, 0xcc, 0x9b, 0x45, 0xc9, 0x7b, 0x7a, 0xbc, 0x37, 0xa8, 0x52 } }, + { { 0x96, 0x11, 0x41, 0x8a, 0x47, 0x91, 0xfe, 0xb6, 0xda, 0x7a, 0x54, 0x63, 0xd1, 0x14, 0x35, 0x05, 0x86, 0x8c, 0xa9, 0x36, 0x3f, 0xf2, 0x85, 0x54, 0x4e, 0x92, 0xd8, 0x85, 0x01, 0x46, 0xd6, 0x50 } } }, + { { { 0x53, 0xcd, 0xf3, 0x86, 0x40, 0xe6, 0x39, 0x42, 0x95, 0xd6, 0xcb, 0x45, 0x1a, 0x20, 0xc8, 0x45, 0x4b, 0x32, 0x69, 0x04, 0xb1, 0xaf, 0x20, 0x46, 0xc7, 0x6b, 0x23, 0x5b, 0x69, 0xee, 0x30, 0x3f } }, + { { 0x70, 0x83, 0x47, 0xc0, 0xdb, 0x55, 0x08, 0xa8, 0x7b, 0x18, 0x6d, 0xf5, 0x04, 0x5a, 0x20, 0x0c, 0x4a, 0x8c, 0x60, 0xae, 0xae, 0x0f, 0x64, 0x55, 0x55, 0x2e, 0xd5, 0x1d, 0x53, 0x31, 0x42, 0x41 } } }, + { { { 0xca, 0xfc, 0x88, 0x6b, 0x96, 0x78, 0x0a, 0x8b, 0x83, 0xdc, 0xbc, 0xaf, 0x40, 0xb6, 0x8d, 0x7f, 0xef, 0xb4, 0xd1, 0x3f, 0xcc, 0xa2, 0x74, 0xc9, 0xc2, 0x92, 0x55, 0x00, 0xab, 0xdb, 0xbf, 0x4f } }, + { { 0x93, 0x1c, 0x06, 0x2d, 0x66, 0x65, 0x02, 0xa4, 0x97, 0x18, 0xfd, 0x00, 0xe7, 0xab, 0x03, 0xec, 0xce, 0xc1, 0xbf, 0x37, 0xf8, 0x13, 0x53, 0xa5, 0xe5, 0x0c, 0x3a, 0xa8, 0x55, 0xb9, 0xff, 0x68 } } }, + { { { 0xe4, 0xe6, 0x6d, 0x30, 0x7d, 0x30, 0x35, 0xc2, 0x78, 0x87, 0xf9, 0xfc, 0x6b, 0x5a, 0xc3, 0xb7, 0x65, 0xd8, 0x2e, 0xc7, 0xa5, 0x0c, 0xc6, 0xdc, 0x12, 0xaa, 0xd6, 0x4f, 0xc5, 0x38, 0xbc, 0x0e } }, + { { 0xe2, 0x3c, 0x76, 0x86, 0x38, 0xf2, 0x7b, 0x2c, 0x16, 0x78, 0x8d, 0xf5, 0xa4, 0x15, 0xda, 0xdb, 0x26, 0x85, 0xa0, 0x56, 0xdd, 0x1d, 0xe3, 0xb3, 0xfd, 0x40, 0xef, 0xf2, 0xd9, 0xa1, 0xb3, 0x04 } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0xdb, 0x49, 0x0e, 0xe6, 0x58, 0x10, 0x7a, 0x52, 0xda, 0xb5, 0x7d, 0x37, 0x6a, 0x3e, 0xa1, 0x78, 0xce, 0xc7, 0x1c, 0x24, 0x23, 0xdb, 0x7d, 0xfb, 0x8c, 0x8d, 0xdc, 0x30, 0x67, 0x69, 0x75, 0x3b } }, + { { 0xa9, 0xea, 0x6d, 0x16, 0x16, 0x60, 0xf4, 0x60, 0x87, 0x19, 0x44, 0x8c, 0x4a, 0x8b, 0x3e, 0xfb, 0x16, 0x00, 0x00, 0x54, 0xa6, 0x9e, 0x9f, 0xef, 0xcf, 0xd9, 0xd2, 0x4c, 0x74, 0x31, 0xd0, 0x34 } } }, + { { { 0xa4, 0xeb, 0x04, 0xa4, 0x8c, 0x8f, 0x71, 0x27, 0x95, 0x85, 0x5d, 0x55, 0x4b, 0xb1, 0x26, 0x26, 0xc8, 0xae, 0x6a, 0x7d, 0xa2, 0x21, 0xca, 0xce, 0x38, 0xab, 0x0f, 0xd0, 0xd5, 0x2b, 0x6b, 0x00 } }, + { { 0xe5, 0x67, 0x0c, 0xf1, 0x3a, 0x9a, 0xea, 0x09, 0x39, 0xef, 0xd1, 0x30, 0xbc, 0x33, 0xba, 0xb1, 0x6a, 0xc5, 0x27, 0x08, 0x7f, 0x54, 0x80, 0x3d, 0xab, 0xf6, 0x15, 0x7a, 0xc2, 0x40, 0x73, 0x72 } } }, + { { { 0x84, 0x56, 0x82, 0xb6, 0x12, 0x70, 0x7f, 0xf7, 0xf0, 0xbd, 0x5b, 0xa9, 0xd5, 0xc5, 0x5f, 0x59, 0xbf, 0x7f, 0xb3, 0x55, 0x22, 0x02, 0xc9, 0x44, 0x55, 0x87, 0x8f, 0x96, 0x98, 0x64, 0x6d, 0x15 } }, + { { 0xb0, 0x8b, 0xaa, 0x1e, 0xec, 0xc7, 0xa5, 0x8f, 0x1f, 0x92, 0x04, 0xc6, 0x05, 0xf6, 0xdf, 0xa1, 0xcc, 0x1f, 0x81, 0xf5, 0x0e, 0x9c, 0x57, 0xdc, 0xe3, 0xbb, 0x06, 0x87, 0x1e, 0xfe, 0x23, 0x6c } } }, + { { { 0xd8, 0x2b, 0x5b, 0x16, 0xea, 0x20, 0xf1, 0xd3, 0x68, 0x8f, 0xae, 0x5b, 0xd0, 0xa9, 0x1a, 0x19, 0xa8, 0x36, 0xfb, 0x2b, 0x57, 0x88, 0x7d, 0x90, 0xd5, 0xa6, 0xf3, 0xdc, 0x38, 0x89, 0x4e, 0x1f } }, + { { 0xcc, 0x19, 0xda, 0x9b, 0x3b, 0x43, 0x48, 0x21, 0x2e, 0x23, 0x4d, 0x3d, 0xae, 0xf8, 0x8c, 0xfc, 0xdd, 0xa6, 0x74, 0x37, 0x65, 0xca, 0xee, 0x1a, 0x19, 0x8e, 0x9f, 0x64, 0x6f, 0x0c, 0x8b, 0x5a } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0x25, 0xb9, 0xc2, 0xf0, 0x72, 0xb8, 0x15, 0x16, 0xcc, 0x8d, 0x3c, 0x6f, 0x25, 0xed, 0xf4, 0x46, 0x2e, 0x0c, 0x60, 0x0f, 0xe2, 0x84, 0x34, 0x55, 0x89, 0x59, 0x34, 0x1b, 0xf5, 0x8d, 0xfe, 0x08 } }, + { { 0xf8, 0xab, 0x93, 0xbc, 0x44, 0xba, 0x1b, 0x75, 0x4b, 0x49, 0x6f, 0xd0, 0x54, 0x2e, 0x63, 0xba, 0xb5, 0xea, 0xed, 0x32, 0x14, 0xc9, 0x94, 0xd8, 0xc5, 0xce, 0xf4, 0x10, 0x68, 0xe0, 0x38, 0x27 } } }, + { { { 0x74, 0x1c, 0x14, 0x9b, 0xd4, 0x64, 0x61, 0x71, 0x5a, 0xb6, 0x21, 0x33, 0x4f, 0xf7, 0x8e, 0xba, 0xa5, 0x48, 0x9a, 0xc7, 0xfa, 0x9a, 0xf0, 0xb4, 0x62, 0xad, 0xf2, 0x5e, 0xcc, 0x03, 0x24, 0x1a } }, + { { 0xf5, 0x76, 0xfd, 0xe4, 0xaf, 0xb9, 0x03, 0x59, 0xce, 0x63, 0xd2, 0x3b, 0x1f, 0xcd, 0x21, 0x0c, 0xad, 0x44, 0xa5, 0x97, 0xac, 0x80, 0x11, 0x02, 0x9b, 0x0c, 0xe5, 0x8b, 0xcd, 0xfb, 0x79, 0x77 } } }, + { { { 0x15, 0xbe, 0x9a, 0x0d, 0xba, 0x38, 0x72, 0x20, 0x8a, 0xf5, 0xbe, 0x59, 0x93, 0x79, 0xb7, 0xf6, 0x6a, 0x0c, 0x38, 0x27, 0x1a, 0x60, 0xf4, 0x86, 0x3b, 0xab, 0x5a, 0x00, 0xa0, 0xce, 0x21, 0x7d } }, + { { 0x6c, 0xba, 0x14, 0xc5, 0xea, 0x12, 0x9e, 0x2e, 0x82, 0x63, 0xce, 0x9b, 0x4a, 0xe7, 0x1d, 0xec, 0xf1, 0x2e, 0x51, 0x1c, 0xf4, 0xd0, 0x69, 0x15, 0x42, 0x9d, 0xa3, 0x3f, 0x0e, 0xbf, 0xe9, 0x5c } } }, + { { { 0xe4, 0x0d, 0xf4, 0xbd, 0xee, 0x31, 0x10, 0xed, 0xcb, 0x12, 0x86, 0xad, 0xd4, 0x2f, 0x90, 0x37, 0x32, 0xc3, 0x0b, 0x73, 0xec, 0x97, 0x85, 0xa4, 0x01, 0x1c, 0x76, 0x35, 0xfe, 0x75, 0xdd, 0x71 } }, + { { 0x11, 0xa4, 0x88, 0x9f, 0x3e, 0x53, 0x69, 0x3b, 0x1b, 0xe0, 0xf7, 0xba, 0x9b, 0xad, 0x4e, 0x81, 0x5f, 0xb5, 0x5c, 0xae, 0xbe, 0x67, 0x86, 0x37, 0x34, 0x8e, 0x07, 0x32, 0x45, 0x4a, 0x67, 0x39 } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0x90, 0x70, 0x58, 0x20, 0x03, 0x1e, 0x67, 0xb2, 0xc8, 0x9b, 0x58, 0xc5, 0xb1, 0xeb, 0x2d, 0x4a, 0xde, 0x82, 0x8c, 0xf2, 0xd2, 0x14, 0xb8, 0x70, 0x61, 0x4e, 0x73, 0xd6, 0x0b, 0x6b, 0x0d, 0x30 } }, + { { 0x81, 0xfc, 0x55, 0x5c, 0xbf, 0xa7, 0xc4, 0xbd, 0xe2, 0xf0, 0x4b, 0x8f, 0xe9, 0x7d, 0x99, 0xfa, 0xd3, 0xab, 0xbc, 0xc7, 0x83, 0x2b, 0x04, 0x7f, 0x0c, 0x19, 0x43, 0x03, 0x3d, 0x07, 0xca, 0x40 } } }, + { { { 0xf9, 0xc8, 0xbe, 0x8c, 0x16, 0x81, 0x39, 0x96, 0xf6, 0x17, 0x58, 0xc8, 0x30, 0x58, 0xfb, 0xc2, 0x03, 0x45, 0xd2, 0x52, 0x76, 0xe0, 0x6a, 0x26, 0x28, 0x5c, 0x88, 0x59, 0x6a, 0x5a, 0x54, 0x42 } }, + { { 0x07, 0xb5, 0x2e, 0x2c, 0x67, 0x15, 0x9b, 0xfb, 0x83, 0x69, 0x1e, 0x0f, 0xda, 0xd6, 0x29, 0xb1, 0x60, 0xe0, 0xb2, 0xba, 0x69, 0xa2, 0x9e, 0xbd, 0xbd, 0xe0, 0x1c, 0xbd, 0xcd, 0x06, 0x64, 0x70 } } }, + { { { 0x41, 0xfa, 0x8c, 0xe1, 0x89, 0x8f, 0x27, 0xc8, 0x25, 0x8f, 0x6f, 0x5f, 0x55, 0xf8, 0xde, 0x95, 0x6d, 0x2f, 0x75, 0x16, 0x2b, 0x4e, 0x44, 0xfd, 0x86, 0x6e, 0xe9, 0x70, 0x39, 0x76, 0x97, 0x7e } }, + { { 0x17, 0x62, 0x6b, 0x14, 0xa1, 0x7c, 0xd0, 0x79, 0x6e, 0xd8, 0x8a, 0xa5, 0x6d, 0x8c, 0x93, 0xd2, 0x3f, 0xec, 0x44, 0x8d, 0x6e, 0x91, 0x01, 0x8c, 0x8f, 0xee, 0x01, 0x8f, 0xc0, 0xb4, 0x85, 0x0e } } }, + { { { 0x02, 0x3a, 0x70, 0x41, 0xe4, 0x11, 0x57, 0x23, 0xac, 0xe6, 0xfc, 0x54, 0x7e, 0xcd, 0xd7, 0x22, 0xcb, 0x76, 0x9f, 0x20, 0xce, 0xa0, 0x73, 0x76, 0x51, 0x3b, 0xa4, 0xf8, 0xe3, 0x62, 0x12, 0x6c } }, + { { 0x7f, 0x00, 0x9c, 0x26, 0x0d, 0x6f, 0x48, 0x7f, 0x3a, 0x01, 0xed, 0xc5, 0x96, 0xb0, 0x1f, 0x4f, 0xa8, 0x02, 0x62, 0x27, 0x8a, 0x50, 0x8d, 0x9a, 0x8b, 0x52, 0x0f, 0x1e, 0xcf, 0x41, 0x38, 0x19 } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0xf5, 0x6c, 0xd4, 0x2f, 0x0f, 0x69, 0x0f, 0x87, 0x3f, 0x61, 0x65, 0x1e, 0x35, 0x34, 0x85, 0xba, 0x02, 0x30, 0xac, 0x25, 0x3d, 0xe2, 0x62, 0xf1, 0xcc, 0xe9, 0x1b, 0xc2, 0xef, 0x6a, 0x42, 0x57 } }, + { { 0x34, 0x1f, 0x2e, 0xac, 0xd1, 0xc7, 0x04, 0x52, 0x32, 0x66, 0xb2, 0x33, 0x73, 0x21, 0x34, 0x54, 0xf7, 0x71, 0xed, 0x06, 0xb0, 0xff, 0xa6, 0x59, 0x6f, 0x8a, 0x4e, 0xfb, 0x02, 0xb0, 0x45, 0x6b } } }, + { { { 0xf5, 0x48, 0x0b, 0x03, 0xc5, 0x22, 0x7d, 0x80, 0x08, 0x53, 0xfe, 0x32, 0xb1, 0xa1, 0x8a, 0x74, 0x6f, 0xbd, 0x3f, 0x85, 0xf4, 0xcf, 0xf5, 0x60, 0xaf, 0x41, 0x7e, 0x3e, 0x46, 0xa3, 0x5a, 0x20 } }, + { { 0xaa, 0x35, 0x87, 0x44, 0x63, 0x66, 0x97, 0xf8, 0x6e, 0x55, 0x0c, 0x04, 0x3e, 0x35, 0x50, 0xbf, 0x93, 0x69, 0xd2, 0x8b, 0x05, 0x55, 0x99, 0xbe, 0xe2, 0x53, 0x61, 0xec, 0xe8, 0x08, 0x0b, 0x32 } } }, + { { { 0xb3, 0x10, 0x45, 0x02, 0x69, 0x59, 0x2e, 0x97, 0xd9, 0x64, 0xf8, 0xdb, 0x25, 0x80, 0xdc, 0xc4, 0xd5, 0x62, 0x3c, 0xed, 0x65, 0x91, 0xad, 0xd1, 0x57, 0x81, 0x94, 0xaa, 0xa1, 0x29, 0xfc, 0x68 } }, + { { 0xdd, 0xb5, 0x7d, 0xab, 0x5a, 0x21, 0x41, 0x53, 0xbb, 0x17, 0x79, 0x0d, 0xd1, 0xa8, 0x0c, 0x0c, 0x20, 0x88, 0x09, 0xe9, 0x84, 0xe8, 0x25, 0x11, 0x67, 0x7a, 0x8b, 0x1a, 0xe4, 0x5d, 0xe1, 0x5d } } }, + { { { 0x37, 0xea, 0xfe, 0x65, 0x3b, 0x25, 0xe8, 0xe1, 0xc2, 0xc5, 0x02, 0xa4, 0xbe, 0x98, 0x0a, 0x2b, 0x61, 0xc1, 0x9b, 0xe2, 0xd5, 0x92, 0xe6, 0x9e, 0x7d, 0x1f, 0xca, 0x43, 0x88, 0x8b, 0x2c, 0x59 } }, + { { 0xe0, 0xb5, 0x00, 0x1d, 0x2a, 0x6f, 0xaf, 0x79, 0x86, 0x2f, 0xa6, 0x5a, 0x93, 0xd1, 0xfe, 0xae, 0x3a, 0xee, 0xdb, 0x7c, 0x61, 0xbe, 0x7c, 0x01, 0xf9, 0xfe, 0x52, 0xdc, 0xd8, 0x52, 0xa3, 0x42 } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0x22, 0xaf, 0x13, 0x37, 0xbd, 0x37, 0x71, 0xac, 0x04, 0x46, 0x63, 0xac, 0xa4, 0x77, 0xed, 0x25, 0x38, 0xe0, 0x15, 0xa8, 0x64, 0x00, 0x0d, 0xce, 0x51, 0x01, 0xa9, 0xbc, 0x0f, 0x03, 0x1c, 0x04 } }, + { { 0x89, 0xf9, 0x80, 0x07, 0xcf, 0x3f, 0xb3, 0xe9, 0xe7, 0x45, 0x44, 0x3d, 0x2a, 0x7c, 0xe9, 0xe4, 0x16, 0x5c, 0x5e, 0x65, 0x1c, 0xc7, 0x7d, 0xc6, 0x7a, 0xfb, 0x43, 0xee, 0x25, 0x76, 0x46, 0x72 } } }, + { { { 0x02, 0xa2, 0xed, 0xf4, 0x8f, 0x6b, 0x0b, 0x3e, 0xeb, 0x35, 0x1a, 0xd5, 0x7e, 0xdb, 0x78, 0x00, 0x96, 0x8a, 0xa0, 0xb4, 0xcf, 0x60, 0x4b, 0xd4, 0xd5, 0xf9, 0x2d, 0xbf, 0x88, 0xbd, 0x22, 0x62 } }, + { { 0x13, 0x53, 0xe4, 0x82, 0x57, 0xfa, 0x1e, 0x8f, 0x06, 0x2b, 0x90, 0xba, 0x08, 0xb6, 0x10, 0x54, 0x4f, 0x7c, 0x1b, 0x26, 0xed, 0xda, 0x6b, 0xdd, 0x25, 0xd0, 0x4e, 0xea, 0x42, 0xbb, 0x25, 0x03 } } }, + { { { 0x51, 0x16, 0x50, 0x7c, 0xd5, 0x5d, 0xf6, 0x99, 0xe8, 0x77, 0x72, 0x4e, 0xfa, 0x62, 0xcb, 0x76, 0x75, 0x0c, 0xe2, 0x71, 0x98, 0x92, 0xd5, 0xfa, 0x45, 0xdf, 0x5c, 0x6f, 0x1e, 0x9e, 0x28, 0x69 } }, + { { 0x0d, 0xac, 0x66, 0x6d, 0xc3, 0x8b, 0xba, 0x16, 0xb5, 0xe2, 0xa0, 0x0d, 0x0c, 0xbd, 0xa4, 0x8e, 0x18, 0x6c, 0xf2, 0xdc, 0xf9, 0xdc, 0x4a, 0x86, 0x25, 0x95, 0x14, 0xcb, 0xd8, 0x1a, 0x04, 0x0f } } }, + { { { 0x97, 0xa5, 0xdb, 0x8b, 0x2d, 0xaa, 0x42, 0x11, 0x09, 0xf2, 0x93, 0xbb, 0xd9, 0x06, 0x84, 0x4e, 0x11, 0xa8, 0xa0, 0x25, 0x2b, 0xa6, 0x5f, 0xae, 0xc4, 0xb4, 0x4c, 0xc8, 0xab, 0xc7, 0x3b, 0x02 } }, + { { 0xee, 0xc9, 0x29, 0x0f, 0xdf, 0x11, 0x85, 0xed, 0xce, 0x0d, 0x62, 0x2c, 0x8f, 0x4b, 0xf9, 0x04, 0xe9, 0x06, 0x72, 0x1d, 0x37, 0x20, 0x50, 0xc9, 0x14, 0xeb, 0xec, 0x39, 0xa7, 0x97, 0x2b, 0x4d } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0x69, 0xd1, 0x39, 0xbd, 0xfb, 0x33, 0xbe, 0xc4, 0xf0, 0x5c, 0xef, 0xf0, 0x56, 0x68, 0xfc, 0x97, 0x47, 0xc8, 0x72, 0xb6, 0x53, 0xa4, 0x0a, 0x98, 0xa5, 0xb4, 0x37, 0x71, 0xcf, 0x66, 0x50, 0x6d } }, + { { 0x17, 0xa4, 0x19, 0x52, 0x11, 0x47, 0xb3, 0x5c, 0x5b, 0xa9, 0x2e, 0x22, 0xb4, 0x00, 0x52, 0xf9, 0x57, 0x18, 0xb8, 0xbe, 0x5a, 0xe3, 0xab, 0x83, 0xc8, 0x87, 0x0a, 0x2a, 0xd8, 0x8c, 0xbb, 0x54 } } }, + { { { 0xa9, 0x62, 0x93, 0x85, 0xbe, 0xe8, 0x73, 0x4a, 0x0e, 0xb0, 0xb5, 0x2d, 0x94, 0x50, 0xaa, 0xd3, 0xb2, 0xea, 0x9d, 0x62, 0x76, 0x3b, 0x07, 0x34, 0x4e, 0x2d, 0x70, 0xc8, 0x9a, 0x15, 0x66, 0x6b } }, + { { 0xc5, 0x96, 0xca, 0xc8, 0x22, 0x1a, 0xee, 0x5f, 0xe7, 0x31, 0x60, 0x22, 0x83, 0x08, 0x63, 0xce, 0xb9, 0x32, 0x44, 0x58, 0x5d, 0x3a, 0x9b, 0xe4, 0x04, 0xd5, 0xef, 0x38, 0xef, 0x4b, 0xdd, 0x19 } } }, + { { { 0x4d, 0xc2, 0x17, 0x75, 0xa1, 0x68, 0xcd, 0xc3, 0xc6, 0x03, 0x44, 0xe3, 0x78, 0x09, 0x91, 0x47, 0x3f, 0x0f, 0xe4, 0x92, 0x58, 0xfa, 0x7d, 0x1f, 0x20, 0x94, 0x58, 0x5e, 0xbc, 0x19, 0x02, 0x6f } }, + { { 0x20, 0xd6, 0xd8, 0x91, 0x54, 0xa7, 0xf3, 0x20, 0x4b, 0x34, 0x06, 0xfa, 0x30, 0xc8, 0x6f, 0x14, 0x10, 0x65, 0x74, 0x13, 0x4e, 0xf0, 0x69, 0x26, 0xce, 0xcf, 0x90, 0xf4, 0xd0, 0xc5, 0xc8, 0x64 } } }, + { { { 0x26, 0xa2, 0x50, 0x02, 0x24, 0x72, 0xf1, 0xf0, 0x4e, 0x2d, 0x93, 0xd5, 0x08, 0xe7, 0xae, 0x38, 0xf7, 0x18, 0xa5, 0x32, 0x34, 0xc2, 0xf0, 0xa6, 0xec, 0xb9, 0x61, 0x7b, 0x64, 0x99, 0xac, 0x71 } }, + { { 0x25, 0xcf, 0x74, 0x55, 0x1b, 0xaa, 0xa9, 0x38, 0x41, 0x40, 0xd5, 0x95, 0x95, 0xab, 0x1c, 0x5e, 0xbc, 0x41, 0x7e, 0x14, 0x30, 0xbe, 0x13, 0x89, 0xf4, 0xe5, 0xeb, 0x28, 0xc0, 0xc2, 0x96, 0x3a } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0x2b, 0x77, 0x45, 0xec, 0x67, 0x76, 0x32, 0x4c, 0xb9, 0xdf, 0x25, 0x32, 0x6b, 0xcb, 0xe7, 0x14, 0x61, 0x43, 0xee, 0xba, 0x9b, 0x71, 0xef, 0xd2, 0x48, 0x65, 0xbb, 0x1b, 0x8a, 0x13, 0x1b, 0x22 } }, + { { 0x84, 0xad, 0x0c, 0x18, 0x38, 0x5a, 0xba, 0xd0, 0x98, 0x59, 0xbf, 0x37, 0xb0, 0x4f, 0x97, 0x60, 0x20, 0xb3, 0x9b, 0x97, 0xf6, 0x08, 0x6c, 0xa4, 0xff, 0xfb, 0xb7, 0xfa, 0x95, 0xb2, 0x51, 0x79 } } }, + { { { 0x28, 0x5c, 0x3f, 0xdb, 0x6b, 0x18, 0x3b, 0x5c, 0xd1, 0x04, 0x28, 0xde, 0x85, 0x52, 0x31, 0xb5, 0xbb, 0xf6, 0xa9, 0xed, 0xbe, 0x28, 0x4f, 0xb3, 0x7e, 0x05, 0x6a, 0xdb, 0x95, 0x0d, 0x1b, 0x1c } }, + { { 0xd5, 0xc5, 0xc3, 0x9a, 0x0a, 0xd0, 0x31, 0x3e, 0x07, 0x36, 0x8e, 0xc0, 0x8a, 0x62, 0xb1, 0xca, 0xd6, 0x0e, 0x1e, 0x9d, 0xef, 0xab, 0x98, 0x4d, 0xbb, 0x6c, 0x05, 0xe0, 0xe4, 0x5d, 0xbd, 0x57 } } }, + { { { 0xcc, 0x21, 0x27, 0xce, 0xfd, 0xa9, 0x94, 0x8e, 0xe1, 0xab, 0x49, 0xe0, 0x46, 0x26, 0xa1, 0xa8, 0x8c, 0xa1, 0x99, 0x1d, 0xb4, 0x27, 0x6d, 0x2d, 0xc8, 0x39, 0x30, 0x5e, 0x37, 0x52, 0xc4, 0x6e } }, + { { 0xa9, 0x85, 0xf4, 0xe7, 0xb0, 0x15, 0x33, 0x84, 0x1b, 0x14, 0x1a, 0x02, 0xd9, 0x3b, 0xad, 0x0f, 0x43, 0x6c, 0xea, 0x3e, 0x0f, 0x7e, 0xda, 0xdd, 0x6b, 0x4c, 0x7f, 0x6e, 0xd4, 0x6b, 0xbf, 0x0f } } }, + { { { 0x47, 0x9f, 0x7c, 0x56, 0x7c, 0x43, 0x91, 0x1c, 0xbb, 0x4e, 0x72, 0x3e, 0x64, 0xab, 0xa0, 0xa0, 0xdf, 0xb4, 0xd8, 0x87, 0x3a, 0xbd, 0xa8, 0x48, 0xc9, 0xb8, 0xef, 0x2e, 0xad, 0x6f, 0x84, 0x4f } }, + { { 0x2d, 0x2d, 0xf0, 0x1b, 0x7e, 0x2a, 0x6c, 0xf8, 0xa9, 0x6a, 0xe1, 0xf0, 0x99, 0xa1, 0x67, 0x9a, 0xd4, 0x13, 0xca, 0xca, 0xba, 0x27, 0x92, 0xaa, 0xa1, 0x5d, 0x50, 0xde, 0xcc, 0x40, 0x26, 0x0a } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0x9f, 0x3e, 0xf2, 0xb2, 0x90, 0xce, 0xdb, 0x64, 0x3e, 0x03, 0xdd, 0x37, 0x36, 0x54, 0x70, 0x76, 0x24, 0xb5, 0x69, 0x03, 0xfc, 0xa0, 0x2b, 0x74, 0xb2, 0x05, 0x0e, 0xcc, 0xd8, 0x1f, 0x6a, 0x1f } }, + { { 0x19, 0x5e, 0x60, 0x69, 0x58, 0x86, 0xa0, 0x31, 0xbd, 0x32, 0xe9, 0x2c, 0x5c, 0xd2, 0x85, 0xba, 0x40, 0x64, 0xa8, 0x74, 0xf8, 0x0e, 0x1c, 0xb3, 0xa9, 0x69, 0xe8, 0x1e, 0x40, 0x64, 0x99, 0x77 } } }, + { { { 0x6c, 0x32, 0x4f, 0xfd, 0xbb, 0x5c, 0xbb, 0x8d, 0x64, 0x66, 0x4a, 0x71, 0x1f, 0x79, 0xa3, 0xad, 0x8d, 0xf9, 0xd4, 0xec, 0xcf, 0x67, 0x70, 0xfa, 0x05, 0x4a, 0x0f, 0x6e, 0xaf, 0x87, 0x0a, 0x6f } }, + { { 0xc6, 0x36, 0x6e, 0x6c, 0x8c, 0x24, 0x09, 0x60, 0xbe, 0x26, 0xd2, 0x4c, 0x5e, 0x17, 0xca, 0x5f, 0x1d, 0xcc, 0x87, 0xe8, 0x42, 0x6a, 0xcb, 0xcb, 0x7d, 0x92, 0x05, 0x35, 0x81, 0x13, 0x60, 0x6b } } }, + { { { 0xf4, 0x15, 0xcd, 0x0f, 0x0a, 0xaf, 0x4e, 0x6b, 0x51, 0xfd, 0x14, 0xc4, 0x2e, 0x13, 0x86, 0x74, 0x44, 0xcb, 0x66, 0x6b, 0xb6, 0x9d, 0x74, 0x56, 0x32, 0xac, 0x8d, 0x8e, 0x8c, 0x8c, 0x8c, 0x39 } }, + { { 0xca, 0x59, 0x74, 0x1a, 0x11, 0xef, 0x6d, 0xf7, 0x39, 0x5c, 0x3b, 0x1f, 0xfa, 0xe3, 0x40, 0x41, 0x23, 0x9e, 0xf6, 0xd1, 0x21, 0xa2, 0xbf, 0xad, 0x65, 0x42, 0x6b, 0x59, 0x8a, 0xe8, 0xc5, 0x7f } } }, + { { { 0x64, 0x05, 0x7a, 0x84, 0x4a, 0x13, 0xc3, 0xf6, 0xb0, 0x6e, 0x9a, 0x6b, 0x53, 0x6b, 0x32, 0xda, 0xd9, 0x74, 0x75, 0xc4, 0xba, 0x64, 0x3d, 0x3b, 0x08, 0xdd, 0x10, 0x46, 0xef, 0xc7, 0x90, 0x1f } }, + { { 0x7b, 0x2f, 0x3a, 0xce, 0xc8, 0xa1, 0x79, 0x3c, 0x30, 0x12, 0x44, 0x28, 0xf6, 0xbc, 0xff, 0xfd, 0xf4, 0xc0, 0x97, 0xb0, 0xcc, 0xc3, 0x13, 0x7a, 0xb9, 0x9a, 0x16, 0xe4, 0xcb, 0x4c, 0x34, 0x63 } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0x07, 0x4e, 0xd3, 0x2d, 0x09, 0x33, 0x0e, 0xd2, 0x0d, 0xbe, 0x3e, 0xe7, 0xe4, 0xaa, 0xb7, 0x00, 0x8b, 0xe8, 0xad, 0xaa, 0x7a, 0x8d, 0x34, 0x28, 0xa9, 0x81, 0x94, 0xc5, 0xe7, 0x42, 0xac, 0x47 } }, + { { 0x24, 0x89, 0x7a, 0x8f, 0xb5, 0x9b, 0xf0, 0xc2, 0x03, 0x64, 0xd0, 0x1e, 0xf5, 0xa4, 0xb2, 0xf3, 0x74, 0xe9, 0x1a, 0x16, 0xfd, 0xcb, 0x15, 0xea, 0xeb, 0x10, 0x6c, 0x35, 0xd1, 0xc1, 0xa6, 0x28 } } }, + { { { 0xcc, 0xd5, 0x39, 0xfc, 0xa5, 0xa4, 0xad, 0x32, 0x15, 0xce, 0x19, 0xe8, 0x34, 0x2b, 0x1c, 0x60, 0x91, 0xfc, 0x05, 0xa9, 0xb3, 0xdc, 0x80, 0x29, 0xc4, 0x20, 0x79, 0x06, 0x39, 0xc0, 0xe2, 0x22 } }, + { { 0xbb, 0xa8, 0xe1, 0x89, 0x70, 0x57, 0x18, 0x54, 0x3c, 0xf6, 0x0d, 0x82, 0x12, 0x05, 0x87, 0x96, 0x06, 0x39, 0xe3, 0xf8, 0xb3, 0x95, 0xe5, 0xd7, 0x26, 0xbf, 0x09, 0x5a, 0x94, 0xf9, 0x1c, 0x63 } } }, + { { { 0x2b, 0x8c, 0x2d, 0x9a, 0x8b, 0x84, 0xf2, 0x56, 0xfb, 0xad, 0x2e, 0x7f, 0xb7, 0xfc, 0x30, 0xe1, 0x35, 0x89, 0xba, 0x4d, 0xa8, 0x6d, 0xce, 0x8c, 0x8b, 0x30, 0xe0, 0xda, 0x29, 0x18, 0x11, 0x17 } }, + { { 0x19, 0xa6, 0x5a, 0x65, 0x93, 0xc3, 0xb5, 0x31, 0x22, 0x4f, 0xf3, 0xf6, 0x0f, 0xeb, 0x28, 0xc3, 0x7c, 0xeb, 0xce, 0x86, 0xec, 0x67, 0x76, 0x6e, 0x35, 0x45, 0x7b, 0xd8, 0x6b, 0x92, 0x01, 0x65 } } }, + { { { 0x3d, 0xd5, 0x9a, 0x64, 0x73, 0x36, 0xb1, 0xd6, 0x86, 0x98, 0x42, 0x3f, 0x8a, 0xf1, 0xc7, 0xf5, 0x42, 0xa8, 0x9c, 0x52, 0xa8, 0xdc, 0xf9, 0x24, 0x3f, 0x4a, 0xa1, 0xa4, 0x5b, 0xe8, 0x62, 0x1a } }, + { { 0xc5, 0xbd, 0xc8, 0x14, 0xd5, 0x0d, 0xeb, 0xe1, 0xa5, 0xe6, 0x83, 0x11, 0x09, 0x00, 0x1d, 0x55, 0x83, 0x51, 0x7e, 0x75, 0x00, 0x81, 0xb9, 0xcb, 0xd8, 0xc5, 0xe5, 0xa1, 0xd9, 0x17, 0x6d, 0x1f } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0xea, 0xf9, 0xe4, 0xe9, 0xe1, 0x52, 0x3f, 0x51, 0x19, 0x0d, 0xdd, 0xd9, 0x9d, 0x93, 0x31, 0x87, 0x23, 0x09, 0xd5, 0x83, 0xeb, 0x92, 0x09, 0x76, 0x6e, 0xe3, 0xf8, 0xc0, 0xa2, 0x66, 0xb5, 0x36 } }, + { { 0x3a, 0xbb, 0x39, 0xed, 0x32, 0x02, 0xe7, 0x43, 0x7a, 0x38, 0x14, 0x84, 0xe3, 0x44, 0xd2, 0x5e, 0x94, 0xdd, 0x78, 0x89, 0x55, 0x4c, 0x73, 0x9e, 0xe1, 0xe4, 0x3e, 0x43, 0xd0, 0x4a, 0xde, 0x1b } } }, + { { { 0xb2, 0xe7, 0x8f, 0xe3, 0xa3, 0xc5, 0xcb, 0x72, 0xee, 0x79, 0x41, 0xf8, 0xdf, 0xee, 0x65, 0xc5, 0x45, 0x77, 0x27, 0x3c, 0xbd, 0x58, 0xd3, 0x75, 0xe2, 0x04, 0x4b, 0xbb, 0x65, 0xf3, 0xc8, 0x0f } }, + { { 0x24, 0x7b, 0x93, 0x34, 0xb5, 0xe2, 0x74, 0x48, 0xcd, 0xa0, 0x0b, 0x92, 0x97, 0x66, 0x39, 0xf4, 0xb0, 0xe2, 0x5d, 0x39, 0x6a, 0x5b, 0x45, 0x17, 0x78, 0x1e, 0xdb, 0x91, 0x81, 0x1c, 0xf9, 0x16 } } }, + { { { 0x16, 0xdf, 0xd1, 0x5a, 0xd5, 0xe9, 0x4e, 0x58, 0x95, 0x93, 0x5f, 0x51, 0x09, 0xc3, 0x2a, 0xc9, 0xd4, 0x55, 0x48, 0x79, 0xa4, 0xa3, 0xb2, 0xc3, 0x62, 0xaa, 0x8c, 0xe8, 0xad, 0x47, 0x39, 0x1b } }, + { { 0x46, 0xda, 0x9e, 0x51, 0x3a, 0xe6, 0xd1, 0xa6, 0xbb, 0x4d, 0x7b, 0x08, 0xbe, 0x8c, 0xd5, 0xf3, 0x3f, 0xfd, 0xf7, 0x44, 0x80, 0x2d, 0x53, 0x4b, 0xd0, 0x87, 0x68, 0xc1, 0xb5, 0xd8, 0xf7, 0x07 } } }, + { { { 0xf4, 0x10, 0x46, 0xbe, 0xb7, 0xd2, 0xd1, 0xce, 0x5e, 0x76, 0xa2, 0xd7, 0x03, 0xdc, 0xe4, 0x81, 0x5a, 0xf6, 0x3c, 0xde, 0xae, 0x7a, 0x9d, 0x21, 0x34, 0xa5, 0xf6, 0xa9, 0x73, 0xe2, 0x8d, 0x60 } }, + { { 0xfa, 0x44, 0x71, 0xf6, 0x41, 0xd8, 0xc6, 0x58, 0x13, 0x37, 0xeb, 0x84, 0x0f, 0x96, 0xc7, 0xdc, 0xc8, 0xa9, 0x7a, 0x83, 0xb2, 0x2f, 0x31, 0xb1, 0x1a, 0xd8, 0x98, 0x3f, 0x11, 0xd0, 0x31, 0x3b } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0x81, 0xd5, 0x34, 0x16, 0x01, 0xa3, 0x93, 0xea, 0x52, 0x94, 0xec, 0x93, 0xb7, 0x81, 0x11, 0x2d, 0x58, 0xf9, 0xb5, 0x0a, 0xaa, 0x4f, 0xf6, 0x2e, 0x3f, 0x36, 0xbf, 0x33, 0x5a, 0xe7, 0xd1, 0x08 } }, + { { 0x1a, 0xcf, 0x42, 0xae, 0xcc, 0xb5, 0x77, 0x39, 0xc4, 0x5b, 0x5b, 0xd0, 0x26, 0x59, 0x27, 0xd0, 0x55, 0x71, 0x12, 0x9d, 0x88, 0x3d, 0x9c, 0xea, 0x41, 0x6a, 0xf0, 0x50, 0x93, 0x93, 0xdd, 0x47 } } }, + { { { 0x6f, 0xc9, 0x51, 0x6d, 0x1c, 0xaa, 0xf5, 0xa5, 0x90, 0x3f, 0x14, 0xe2, 0x6e, 0x8e, 0x64, 0xfd, 0xac, 0xe0, 0x4e, 0x22, 0xe5, 0xc1, 0xbc, 0x29, 0x0a, 0x6a, 0x9e, 0xa1, 0x60, 0xcb, 0x2f, 0x0b } }, + { { 0xdc, 0x39, 0x32, 0xf3, 0xa1, 0x44, 0xe9, 0xc5, 0xc3, 0x78, 0xfb, 0x95, 0x47, 0x34, 0x35, 0x34, 0xe8, 0x25, 0xde, 0x93, 0xc6, 0xb4, 0x76, 0x6d, 0x86, 0x13, 0xc6, 0xe9, 0x68, 0xb5, 0x01, 0x63 } } }, + { { { 0x1f, 0x9a, 0x52, 0x64, 0x97, 0xd9, 0x1c, 0x08, 0x51, 0x6f, 0x26, 0x9d, 0xaa, 0x93, 0x33, 0x43, 0xfa, 0x77, 0xe9, 0x62, 0x9b, 0x5d, 0x18, 0x75, 0xeb, 0x78, 0xf7, 0x87, 0x8f, 0x41, 0xb4, 0x4d } }, + { { 0x13, 0xa8, 0x82, 0x3e, 0xe9, 0x13, 0xad, 0xeb, 0x01, 0xca, 0xcf, 0xda, 0xcd, 0xf7, 0x6c, 0xc7, 0x7a, 0xdc, 0x1e, 0x6e, 0xc8, 0x4e, 0x55, 0x62, 0x80, 0xea, 0x78, 0x0c, 0x86, 0xb9, 0x40, 0x51 } } }, + { { { 0x27, 0xae, 0xd3, 0x0d, 0x4c, 0x8f, 0x34, 0xea, 0x7d, 0x3c, 0xe5, 0x8a, 0xcf, 0x5b, 0x92, 0xd8, 0x30, 0x16, 0xb4, 0xa3, 0x75, 0xff, 0xeb, 0x27, 0xc8, 0x5c, 0x6c, 0xc2, 0xee, 0x6c, 0x21, 0x0b } }, + { { 0xc3, 0xba, 0x12, 0x53, 0x2a, 0xaa, 0x77, 0xad, 0x19, 0x78, 0x55, 0x8a, 0x2e, 0x60, 0x87, 0xc2, 0x6e, 0x91, 0x38, 0x91, 0x3f, 0x7a, 0xc5, 0x24, 0x8f, 0x51, 0xc5, 0xde, 0xb0, 0x53, 0x30, 0x56 } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0x02, 0xfe, 0x54, 0x12, 0x18, 0xca, 0x7d, 0xa5, 0x68, 0x43, 0xa3, 0x6d, 0x14, 0x2a, 0x6a, 0xa5, 0x8e, 0x32, 0xe7, 0x63, 0x4f, 0xe3, 0xc6, 0x44, 0x3e, 0xab, 0x63, 0xca, 0x17, 0x86, 0x74, 0x3f } }, + { { 0x1e, 0x64, 0xc1, 0x7d, 0x52, 0xdc, 0x13, 0x5a, 0xa1, 0x9c, 0x4e, 0xee, 0x99, 0x28, 0xbb, 0x4c, 0xee, 0xac, 0xa9, 0x1b, 0x89, 0xa2, 0x38, 0x39, 0x7b, 0xc4, 0x0f, 0x42, 0xe6, 0x89, 0xed, 0x0f } } }, + { { { 0xf3, 0x3c, 0x8c, 0x80, 0x83, 0x10, 0x8a, 0x37, 0x50, 0x9c, 0xb4, 0xdf, 0x3f, 0x8c, 0xf7, 0x23, 0x07, 0xd6, 0xff, 0xa0, 0x82, 0x6c, 0x75, 0x3b, 0xe4, 0xb5, 0xbb, 0xe4, 0xe6, 0x50, 0xf0, 0x08 } }, + { { 0x62, 0xee, 0x75, 0x48, 0x92, 0x33, 0xf2, 0xf4, 0xad, 0x15, 0x7a, 0xa1, 0x01, 0x46, 0xa9, 0x32, 0x06, 0x88, 0xb6, 0x36, 0x47, 0x35, 0xb9, 0xb4, 0x42, 0x85, 0x76, 0xf0, 0x48, 0x00, 0x90, 0x38 } } }, + { { { 0x51, 0x15, 0x9d, 0xc3, 0x95, 0xd1, 0x39, 0xbb, 0x64, 0x9d, 0x15, 0x81, 0xc1, 0x68, 0xd0, 0xb6, 0xa4, 0x2c, 0x7d, 0x5e, 0x02, 0x39, 0x00, 0xe0, 0x3b, 0xa4, 0xcc, 0xca, 0x1d, 0x81, 0x24, 0x10 } }, + { { 0xe7, 0x29, 0xf9, 0x37, 0xd9, 0x46, 0x5a, 0xcd, 0x70, 0xfe, 0x4d, 0x5b, 0xbf, 0xa5, 0xcf, 0x91, 0xf4, 0xef, 0xee, 0x8a, 0x29, 0xd0, 0xe7, 0xc4, 0x25, 0x92, 0x8a, 0xff, 0x36, 0xfc, 0xe4, 0x49 } } }, + { { { 0xbd, 0x00, 0xb9, 0x04, 0x7d, 0x35, 0xfc, 0xeb, 0xd0, 0x0b, 0x05, 0x32, 0x52, 0x7a, 0x89, 0x24, 0x75, 0x50, 0xe1, 0x63, 0x02, 0x82, 0x8e, 0xe7, 0x85, 0x0c, 0xf2, 0x56, 0x44, 0x37, 0x83, 0x25 } }, + { { 0x8f, 0xa1, 0xce, 0xcb, 0x60, 0xda, 0x12, 0x02, 0x1e, 0x29, 0x39, 0x2a, 0x03, 0xb7, 0xeb, 0x77, 0x40, 0xea, 0xc9, 0x2b, 0x2c, 0xd5, 0x7d, 0x7e, 0x2c, 0xc7, 0x5a, 0xfd, 0xff, 0xc4, 0xd1, 0x62 } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0x1d, 0x88, 0x98, 0x5b, 0x4e, 0xfc, 0x41, 0x24, 0x05, 0xe6, 0x50, 0x2b, 0xae, 0x96, 0x51, 0xd9, 0x6b, 0x72, 0xb2, 0x33, 0x42, 0x98, 0x68, 0xbb, 0x10, 0x5a, 0x7a, 0x8c, 0x9d, 0x07, 0xb4, 0x05 } }, + { { 0x2f, 0x61, 0x9f, 0xd7, 0xa8, 0x3f, 0x83, 0x8c, 0x10, 0x69, 0x90, 0xe6, 0xcf, 0xd2, 0x63, 0xa3, 0xe4, 0x54, 0x7e, 0xe5, 0x69, 0x13, 0x1c, 0x90, 0x57, 0xaa, 0xe9, 0x53, 0x22, 0x43, 0x29, 0x23 } } }, + { { { 0xe5, 0x1c, 0xf8, 0x0a, 0xfd, 0x2d, 0x7e, 0xf5, 0xf5, 0x70, 0x7d, 0x41, 0x6b, 0x11, 0xfe, 0xbe, 0x99, 0xd1, 0x55, 0x29, 0x31, 0xbf, 0xc0, 0x97, 0x6c, 0xd5, 0x35, 0xcc, 0x5e, 0x8b, 0xd9, 0x69 } }, + { { 0x8e, 0x4e, 0x9f, 0x25, 0xf8, 0x81, 0x54, 0x2d, 0x0e, 0xd5, 0x54, 0x81, 0x9b, 0xa6, 0x92, 0xce, 0x4b, 0xe9, 0x8f, 0x24, 0x3b, 0xca, 0xe0, 0x44, 0xab, 0x36, 0xfe, 0xfb, 0x87, 0xd4, 0x26, 0x3e } } }, + { { { 0x0f, 0x93, 0x9c, 0x11, 0xe7, 0xdb, 0xf1, 0xf0, 0x85, 0x43, 0x28, 0x15, 0x37, 0xdd, 0xde, 0x27, 0xdf, 0xad, 0x3e, 0x49, 0x4f, 0xe0, 0x5b, 0xf6, 0x80, 0x59, 0x15, 0x3c, 0x85, 0xb7, 0x3e, 0x12 } }, + { { 0xf5, 0xff, 0xcc, 0xf0, 0xb4, 0x12, 0x03, 0x5f, 0xc9, 0x84, 0xcb, 0x1d, 0x17, 0xe0, 0xbc, 0xcc, 0x03, 0x62, 0xa9, 0x8b, 0x94, 0xa6, 0xaa, 0x18, 0xcb, 0x27, 0x8d, 0x49, 0xa6, 0x17, 0x15, 0x07 } } }, + { { { 0xd9, 0xb6, 0xd4, 0x9d, 0xd4, 0x6a, 0xaf, 0x70, 0x07, 0x2c, 0x10, 0x9e, 0xbd, 0x11, 0xad, 0xe4, 0x26, 0x33, 0x70, 0x92, 0x78, 0x1c, 0x74, 0x9f, 0x75, 0x60, 0x56, 0xf4, 0x39, 0xa8, 0xa8, 0x62 } }, + { { 0x3b, 0xbf, 0x55, 0x35, 0x61, 0x8b, 0x44, 0x97, 0xe8, 0x3a, 0x55, 0xc1, 0xc8, 0x3b, 0xfd, 0x95, 0x29, 0x11, 0x60, 0x96, 0x1e, 0xcb, 0x11, 0x9d, 0xc2, 0x03, 0x8a, 0x1b, 0xc6, 0xd6, 0x45, 0x3d } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0x7e, 0x0e, 0x50, 0xb2, 0xcc, 0x0d, 0x6b, 0xa6, 0x71, 0x5b, 0x42, 0xed, 0xbd, 0xaf, 0xac, 0xf0, 0xfc, 0x12, 0xa2, 0x3f, 0x4e, 0xda, 0xe8, 0x11, 0xf3, 0x23, 0xe1, 0x04, 0x62, 0x03, 0x1c, 0x4e } }, + { { 0xc8, 0xb1, 0x1b, 0x6f, 0x73, 0x61, 0x3d, 0x27, 0x0d, 0x7d, 0x7a, 0x25, 0x5f, 0x73, 0x0e, 0x2f, 0x93, 0xf6, 0x24, 0xd8, 0x4f, 0x90, 0xac, 0xa2, 0x62, 0x0a, 0xf0, 0x61, 0xd9, 0x08, 0x59, 0x6a } } }, + { { { 0x6f, 0x2d, 0x55, 0xf8, 0x2f, 0x8e, 0xf0, 0x18, 0x3b, 0xea, 0xdd, 0x26, 0x72, 0xd1, 0xf5, 0xfe, 0xe5, 0xb8, 0xe6, 0xd3, 0x10, 0x48, 0x46, 0x49, 0x3a, 0x9f, 0x5e, 0x45, 0x6b, 0x90, 0xe8, 0x7f } }, + { { 0xd3, 0x76, 0x69, 0x33, 0x7b, 0xb9, 0x40, 0x70, 0xee, 0xa6, 0x29, 0x6b, 0xdd, 0xd0, 0x5d, 0x8d, 0xc1, 0x3e, 0x4a, 0xea, 0x37, 0xb1, 0x03, 0x02, 0x03, 0x35, 0xf1, 0x28, 0x9d, 0xff, 0x00, 0x13 } } }, + { { { 0x7a, 0xdb, 0x12, 0xd2, 0x8a, 0x82, 0x03, 0x1b, 0x1e, 0xaf, 0xf9, 0x4b, 0x9c, 0xbe, 0xae, 0x7c, 0xe4, 0x94, 0x2a, 0x23, 0xb3, 0x62, 0x86, 0xe7, 0xfd, 0x23, 0xaa, 0x99, 0xbd, 0x2b, 0x11, 0x6c } }, + { { 0x8d, 0xa6, 0xd5, 0xac, 0x9d, 0xcc, 0x68, 0x75, 0x7f, 0xc3, 0x4d, 0x4b, 0xdd, 0x6c, 0xbb, 0x11, 0x5a, 0x60, 0xe5, 0xbd, 0x7d, 0x27, 0x8b, 0xda, 0xb4, 0x95, 0xf6, 0x03, 0x27, 0xa4, 0x92, 0x3f } } }, + { { { 0x22, 0xd6, 0xb5, 0x17, 0x84, 0xbf, 0x12, 0xcc, 0x23, 0x14, 0x4a, 0xdf, 0x14, 0x31, 0xbc, 0xa1, 0xac, 0x6e, 0xab, 0xfa, 0x57, 0x11, 0x53, 0xb3, 0x27, 0xe6, 0xf9, 0x47, 0x33, 0x44, 0x34, 0x1e } }, + { { 0x79, 0xfc, 0xa6, 0xb4, 0x0b, 0x35, 0x20, 0xc9, 0x4d, 0x22, 0x84, 0xc4, 0xa9, 0x20, 0xec, 0x89, 0x94, 0xba, 0x66, 0x56, 0x48, 0xb9, 0x87, 0x7f, 0xca, 0x1e, 0x06, 0xed, 0xa5, 0x55, 0x59, 0x29 } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0x56, 0xe1, 0xf5, 0xf1, 0xd5, 0xab, 0xa8, 0x2b, 0xae, 0x89, 0xf3, 0xcf, 0x56, 0x9f, 0xf2, 0x4b, 0x31, 0xbc, 0x18, 0xa9, 0x06, 0x5b, 0xbe, 0xb4, 0x61, 0xf8, 0xb2, 0x06, 0x9c, 0x81, 0xab, 0x4c } }, + { { 0x1f, 0x68, 0x76, 0x01, 0x16, 0x38, 0x2b, 0x0f, 0x77, 0x97, 0x92, 0x67, 0x4e, 0x86, 0x6a, 0x8b, 0xe5, 0xe8, 0x0c, 0xf7, 0x36, 0x39, 0xb5, 0x33, 0xe6, 0xcf, 0x5e, 0xbd, 0x18, 0xfb, 0x10, 0x1f } } }, + { { { 0x83, 0xf0, 0x0d, 0x63, 0xef, 0x53, 0x6b, 0xb5, 0x6b, 0xf9, 0x83, 0xcf, 0xde, 0x04, 0x22, 0x9b, 0x2c, 0x0a, 0xe0, 0xa5, 0xd8, 0xc7, 0x9c, 0xa5, 0xa3, 0xf6, 0x6f, 0xcf, 0x90, 0x6b, 0x68, 0x7c } }, + { { 0x33, 0x15, 0xd7, 0x7f, 0x1a, 0xd5, 0x21, 0x58, 0xc4, 0x18, 0xa5, 0xf0, 0xcc, 0x73, 0xa8, 0xfd, 0xfa, 0x18, 0xd1, 0x03, 0x91, 0x8d, 0x52, 0xd2, 0xa3, 0xa4, 0xd3, 0xb1, 0xea, 0x1d, 0x0f, 0x00 } } }, + { { { 0xcc, 0x48, 0x83, 0x90, 0xe5, 0xfd, 0x3f, 0x84, 0xaa, 0xf9, 0x8b, 0x82, 0x59, 0x24, 0x34, 0x68, 0x4f, 0x1c, 0x23, 0xd9, 0xcc, 0x71, 0xe1, 0x7f, 0x8c, 0xaf, 0xf1, 0xee, 0x00, 0xb6, 0xa0, 0x77 } }, + { { 0xf5, 0x1a, 0x61, 0xf7, 0x37, 0x9d, 0x00, 0xf4, 0xf2, 0x69, 0x6f, 0x4b, 0x01, 0x85, 0x19, 0x45, 0x4d, 0x7f, 0x02, 0x7c, 0x6a, 0x05, 0x47, 0x6c, 0x1f, 0x81, 0x20, 0xd4, 0xe8, 0x50, 0x27, 0x72 } } }, + { { { 0x2c, 0x3a, 0xe5, 0xad, 0xf4, 0xdd, 0x2d, 0xf7, 0x5c, 0x44, 0xb5, 0x5b, 0x21, 0xa3, 0x89, 0x5f, 0x96, 0x45, 0xca, 0x4d, 0xa4, 0x21, 0x99, 0x70, 0xda, 0xc4, 0xc4, 0xa0, 0xe5, 0xf4, 0xec, 0x0a } }, + { { 0x07, 0x68, 0x21, 0x65, 0xe9, 0x08, 0xa0, 0x0b, 0x6a, 0x4a, 0xba, 0xb5, 0x80, 0xaf, 0xd0, 0x1b, 0xc5, 0xf5, 0x4b, 0x73, 0x50, 0x60, 0x2d, 0x71, 0x69, 0x61, 0x0e, 0xc0, 0x20, 0x40, 0x30, 0x19 } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0xd0, 0x75, 0x57, 0x3b, 0xeb, 0x5c, 0x14, 0x56, 0x50, 0xc9, 0x4f, 0xb8, 0xb8, 0x1e, 0xa3, 0xf4, 0xab, 0xf5, 0xa9, 0x20, 0x15, 0x94, 0x82, 0xda, 0x96, 0x1c, 0x9b, 0x59, 0x8c, 0xff, 0xf4, 0x51 } }, + { { 0xc1, 0x3a, 0x86, 0xd7, 0xb0, 0x06, 0x84, 0x7f, 0x1b, 0xbd, 0xd4, 0x07, 0x78, 0x80, 0x2e, 0xb1, 0xb4, 0xee, 0x52, 0x38, 0xee, 0x9a, 0xf9, 0xf6, 0xf3, 0x41, 0x6e, 0xd4, 0x88, 0x95, 0xac, 0x35 } } }, + { { { 0x41, 0x97, 0xbf, 0x71, 0x6a, 0x9b, 0x72, 0xec, 0xf3, 0xf8, 0x6b, 0xe6, 0x0e, 0x6c, 0x69, 0xa5, 0x2f, 0x68, 0x52, 0xd8, 0x61, 0x81, 0xc0, 0x63, 0x3f, 0xa6, 0x3c, 0x13, 0x90, 0xe6, 0x8d, 0x56 } }, + { { 0xe8, 0x39, 0x30, 0x77, 0x23, 0xb1, 0xfd, 0x1b, 0x3d, 0x3e, 0x74, 0x4d, 0x7f, 0xae, 0x5b, 0x3a, 0xb4, 0x65, 0x0e, 0x3a, 0x43, 0xdc, 0xdc, 0x41, 0x47, 0xe6, 0xe8, 0x92, 0x09, 0x22, 0x48, 0x4c } } }, + { { { 0x85, 0x57, 0x9f, 0xb5, 0xc8, 0x06, 0xb2, 0x9f, 0x47, 0x3f, 0xf0, 0xfa, 0xe6, 0xa9, 0xb1, 0x9b, 0x6f, 0x96, 0x7d, 0xf9, 0xa4, 0x65, 0x09, 0x75, 0x32, 0xa6, 0x6c, 0x7f, 0x47, 0x4b, 0x2f, 0x4f } }, + { { 0x34, 0xe9, 0x59, 0x93, 0x9d, 0x26, 0x80, 0x54, 0xf2, 0xcc, 0x3c, 0xc2, 0x25, 0x85, 0xe3, 0x6a, 0xc1, 0x62, 0x04, 0xa7, 0x08, 0x32, 0x6d, 0xa1, 0x39, 0x84, 0x8a, 0x3b, 0x87, 0x5f, 0x11, 0x13 } } }, + { { { 0xda, 0x03, 0x34, 0x66, 0xc4, 0x0c, 0x73, 0x6e, 0xbc, 0x24, 0xb5, 0xf9, 0x70, 0x81, 0x52, 0xe9, 0xf4, 0x7c, 0x23, 0xdd, 0x9f, 0xb8, 0x46, 0xef, 0x1d, 0x22, 0x55, 0x7d, 0x71, 0xc4, 0x42, 0x33 } }, + { { 0xc5, 0x37, 0x69, 0x5b, 0xa8, 0xc6, 0x9d, 0xa4, 0xfc, 0x61, 0x6e, 0x68, 0x46, 0xea, 0xd7, 0x1c, 0x67, 0xd2, 0x7d, 0xfa, 0xf1, 0xcc, 0x54, 0x8d, 0x36, 0x35, 0xc9, 0x00, 0xdf, 0x6c, 0x67, 0x50 } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0x9a, 0x4d, 0x42, 0x29, 0x5d, 0xa4, 0x6b, 0x6f, 0xa8, 0x8a, 0x4d, 0x91, 0x7b, 0xd2, 0xdf, 0x36, 0xef, 0x01, 0x22, 0xc5, 0xcc, 0x8d, 0xeb, 0x58, 0x3d, 0xb3, 0x50, 0xfc, 0x8b, 0x97, 0x96, 0x33 } }, + { { 0x93, 0x33, 0x07, 0xc8, 0x4a, 0xca, 0xd0, 0xb1, 0xab, 0xbd, 0xdd, 0xa7, 0x7c, 0xac, 0x3e, 0x45, 0xcb, 0xcc, 0x07, 0x91, 0xbf, 0x35, 0x9d, 0xcb, 0x7d, 0x12, 0x3c, 0x11, 0x59, 0x13, 0xcf, 0x5c } } }, + { { { 0x45, 0xb8, 0x41, 0xd7, 0xab, 0x07, 0x15, 0x00, 0x8e, 0xce, 0xdf, 0xb2, 0x43, 0x5c, 0x01, 0xdc, 0xf4, 0x01, 0x51, 0x95, 0x10, 0x5a, 0xf6, 0x24, 0x24, 0xa0, 0x19, 0x3a, 0x09, 0x2a, 0xaa, 0x3f } }, + { { 0xdc, 0x8e, 0xeb, 0xc6, 0xbf, 0xdd, 0x11, 0x7b, 0xe7, 0x47, 0xe6, 0xce, 0xe7, 0xb6, 0xc5, 0xe8, 0x8a, 0xdc, 0x4b, 0x57, 0x15, 0x3b, 0x66, 0xca, 0x89, 0xa3, 0xfd, 0xac, 0x0d, 0xe1, 0x1d, 0x7a } } }, + { { { 0x89, 0xef, 0xbf, 0x03, 0x75, 0xd0, 0x29, 0x50, 0xcb, 0x7d, 0xd6, 0xbe, 0xad, 0x5f, 0x7b, 0x00, 0x32, 0xaa, 0x98, 0xed, 0x3f, 0x8f, 0x92, 0xcb, 0x81, 0x56, 0x01, 0x63, 0x64, 0xa3, 0x38, 0x39 } }, + { { 0x8b, 0xa4, 0xd6, 0x50, 0xb4, 0xaa, 0x5d, 0x64, 0x64, 0x76, 0x2e, 0xa1, 0xa6, 0xb3, 0xb8, 0x7c, 0x7a, 0x56, 0xf5, 0x5c, 0x4e, 0x84, 0x5c, 0xfb, 0xdd, 0xca, 0x48, 0x8b, 0x48, 0xb9, 0xba, 0x34 } } }, + { { { 0xc5, 0xe3, 0xe8, 0xae, 0x17, 0x27, 0xe3, 0x64, 0x60, 0x71, 0x47, 0x29, 0x02, 0x0f, 0x92, 0x5d, 0x10, 0x93, 0xc8, 0x0e, 0xa1, 0xed, 0xba, 0xa9, 0x96, 0x1c, 0xc5, 0x76, 0x30, 0xcd, 0xf9, 0x30 } }, + { { 0x95, 0xb0, 0xbd, 0x8c, 0xbc, 0xa7, 0x4f, 0x7e, 0xfd, 0x4e, 0x3a, 0xbf, 0x5f, 0x04, 0x79, 0x80, 0x2b, 0x5a, 0x9f, 0x4f, 0x68, 0x21, 0x19, 0x71, 0xc6, 0x20, 0x01, 0x42, 0xaa, 0xdf, 0xae, 0x2c } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0x90, 0x6e, 0x7e, 0x4b, 0x71, 0x93, 0xc0, 0x72, 0xed, 0xeb, 0x71, 0x24, 0x97, 0x26, 0x9c, 0xfe, 0xcb, 0x3e, 0x59, 0x19, 0xa8, 0x0f, 0x75, 0x7d, 0xbe, 0x18, 0xe6, 0x96, 0x1e, 0x95, 0x70, 0x60 } }, + { { 0x89, 0x66, 0x3e, 0x1d, 0x4c, 0x5f, 0xfe, 0xc0, 0x04, 0x43, 0xd6, 0x44, 0x19, 0xb5, 0xad, 0xc7, 0x22, 0xdc, 0x71, 0x28, 0x64, 0xde, 0x41, 0x38, 0x27, 0x8f, 0x2c, 0x6b, 0x08, 0xb8, 0xb8, 0x7b } } }, + { { { 0x3d, 0x70, 0x27, 0x9d, 0xd9, 0xaf, 0xb1, 0x27, 0xaf, 0xe3, 0x5d, 0x1e, 0x3a, 0x30, 0x54, 0x61, 0x60, 0xe8, 0xc3, 0x26, 0x3a, 0xbc, 0x7e, 0xf5, 0x81, 0xdd, 0x64, 0x01, 0x04, 0xeb, 0xc0, 0x1e } }, + { { 0xda, 0x2c, 0xa4, 0xd1, 0xa1, 0xc3, 0x5c, 0x6e, 0x32, 0x07, 0x1f, 0xb8, 0x0e, 0x19, 0x9e, 0x99, 0x29, 0x33, 0x9a, 0xae, 0x7a, 0xed, 0x68, 0x42, 0x69, 0x7c, 0x07, 0xb3, 0x38, 0x2c, 0xf6, 0x3d } } }, + { { { 0x64, 0xaa, 0xb5, 0x88, 0x79, 0x65, 0x38, 0x8c, 0x94, 0xd6, 0x62, 0x37, 0x7d, 0x64, 0xcd, 0x3a, 0xeb, 0xff, 0xe8, 0x81, 0x09, 0xc7, 0x6a, 0x50, 0x09, 0x0d, 0x28, 0x03, 0x0d, 0x9a, 0x93, 0x0a } }, + { { 0x42, 0xa3, 0xf1, 0xc5, 0xb4, 0x0f, 0xd8, 0xc8, 0x8d, 0x15, 0x31, 0xbd, 0xf8, 0x07, 0x8b, 0xcd, 0x08, 0x8a, 0xfb, 0x18, 0x07, 0xfe, 0x8e, 0x52, 0x86, 0xef, 0xbe, 0xec, 0x49, 0x52, 0x99, 0x08 } } }, + { { { 0x0f, 0xa9, 0xd5, 0x01, 0xaa, 0x48, 0x4f, 0x28, 0x66, 0x32, 0x1a, 0xba, 0x7c, 0xea, 0x11, 0x80, 0x17, 0x18, 0x9b, 0x56, 0x88, 0x25, 0x06, 0x69, 0x12, 0x2c, 0xea, 0x56, 0x69, 0x41, 0x24, 0x19 } }, + { { 0xde, 0x21, 0xf0, 0xda, 0x8a, 0xfb, 0xb1, 0xb8, 0xcd, 0xc8, 0x6a, 0x82, 0x19, 0x73, 0xdb, 0xc7, 0xcf, 0x88, 0xeb, 0x96, 0xee, 0x6f, 0xfb, 0x06, 0xd2, 0xcd, 0x7d, 0x7b, 0x12, 0x28, 0x8e, 0x0c } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0x93, 0x44, 0x97, 0xce, 0x28, 0xff, 0x3a, 0x40, 0xc4, 0xf5, 0xf6, 0x9b, 0xf4, 0x6b, 0x07, 0x84, 0xfb, 0x98, 0xd8, 0xec, 0x8c, 0x03, 0x57, 0xec, 0x49, 0xed, 0x63, 0xb6, 0xaa, 0xff, 0x98, 0x28 } }, + { { 0x3d, 0x16, 0x35, 0xf3, 0x46, 0xbc, 0xb3, 0xf4, 0xc6, 0xb6, 0x4f, 0xfa, 0xf4, 0xa0, 0x13, 0xe6, 0x57, 0x45, 0x93, 0xb9, 0xbc, 0xd6, 0x59, 0xe7, 0x77, 0x94, 0x6c, 0xab, 0x96, 0x3b, 0x4f, 0x09 } } }, + { { { 0x5a, 0xf7, 0x6b, 0x01, 0x12, 0x4f, 0x51, 0xc1, 0x70, 0x84, 0x94, 0x47, 0xb2, 0x01, 0x6c, 0x71, 0xd7, 0xcc, 0x17, 0x66, 0x0f, 0x59, 0x5d, 0x5d, 0x10, 0x01, 0x57, 0x11, 0xf5, 0xdd, 0xe2, 0x34 } }, + { { 0x26, 0xd9, 0x1f, 0x5c, 0x58, 0xac, 0x8b, 0x03, 0xd2, 0xc3, 0x85, 0x0f, 0x3a, 0xc3, 0x7f, 0x6d, 0x8e, 0x86, 0xcd, 0x52, 0x74, 0x8f, 0x55, 0x77, 0x17, 0xb7, 0x8e, 0xb7, 0x88, 0xea, 0xda, 0x1b } } }, + { { { 0xb6, 0xea, 0x0e, 0x40, 0x93, 0x20, 0x79, 0x35, 0x6a, 0x61, 0x84, 0x5a, 0x07, 0x6d, 0xf9, 0x77, 0x6f, 0xed, 0x69, 0x1c, 0x0d, 0x25, 0x76, 0xcc, 0xf0, 0xdb, 0xbb, 0xc5, 0xad, 0xe2, 0x26, 0x57 } }, + { { 0xcf, 0xe8, 0x0e, 0x6b, 0x96, 0x7d, 0xed, 0x27, 0xd1, 0x3c, 0xa9, 0xd9, 0x50, 0xa9, 0x98, 0x84, 0x5e, 0x86, 0xef, 0xd6, 0xf0, 0xf8, 0x0e, 0x89, 0x05, 0x2f, 0xd9, 0x5f, 0x15, 0x5f, 0x73, 0x79 } } }, + { { { 0xc8, 0x5c, 0x16, 0xfe, 0xed, 0x9f, 0x26, 0x56, 0xf6, 0x4b, 0x9f, 0xa7, 0x0a, 0x85, 0xfe, 0xa5, 0x8c, 0x87, 0xdd, 0x98, 0xce, 0x4e, 0xc3, 0x58, 0x55, 0xb2, 0x7b, 0x3d, 0xd8, 0x6b, 0xb5, 0x4c } }, + { { 0x65, 0x38, 0xa0, 0x15, 0xfa, 0xa7, 0xb4, 0x8f, 0xeb, 0xc4, 0x86, 0x9b, 0x30, 0xa5, 0x5e, 0x4d, 0xea, 0x8a, 0x9a, 0x9f, 0x1a, 0xd8, 0x5b, 0x53, 0x14, 0x19, 0x25, 0x63, 0xb4, 0x6f, 0x1f, 0x5d } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0xac, 0x8f, 0xbc, 0x1e, 0x7d, 0x8b, 0x5a, 0x0b, 0x8d, 0xaf, 0x76, 0x2e, 0x71, 0xe3, 0x3b, 0x6f, 0x53, 0x2f, 0x3e, 0x90, 0x95, 0xd4, 0x35, 0x14, 0x4f, 0x8c, 0x3c, 0xce, 0x57, 0x1c, 0x76, 0x49 } }, + { { 0xa8, 0x50, 0xe1, 0x61, 0x6b, 0x57, 0x35, 0xeb, 0x44, 0x0b, 0x0c, 0x6e, 0xf9, 0x25, 0x80, 0x74, 0xf2, 0x8f, 0x6f, 0x7a, 0x3e, 0x7f, 0x2d, 0xf3, 0x4e, 0x09, 0x65, 0x10, 0x5e, 0x03, 0x25, 0x32 } } }, + { { { 0xa9, 0x60, 0xdc, 0x0f, 0x64, 0xe5, 0x1d, 0xe2, 0x8d, 0x4f, 0x79, 0x2f, 0x0e, 0x24, 0x02, 0x00, 0x05, 0x77, 0x43, 0x25, 0x3d, 0x6a, 0xc7, 0xb7, 0xbf, 0x04, 0x08, 0x65, 0xf4, 0x39, 0x4b, 0x65 } }, + { { 0x96, 0x19, 0x12, 0x6b, 0x6a, 0xb7, 0xe3, 0xdc, 0x45, 0x9b, 0xdb, 0xb4, 0xa8, 0xae, 0xdc, 0xa8, 0x14, 0x44, 0x65, 0x62, 0xce, 0x34, 0x9a, 0x84, 0x18, 0x12, 0x01, 0xf1, 0xe2, 0x7b, 0xce, 0x50 } } }, + { { { 0x41, 0x21, 0x30, 0x53, 0x1b, 0x47, 0x01, 0xb7, 0x18, 0xd8, 0x82, 0x57, 0xbd, 0xa3, 0x60, 0xf0, 0x32, 0xf6, 0x5b, 0xf0, 0x30, 0x88, 0x91, 0x59, 0xfd, 0x90, 0xa2, 0xb9, 0x55, 0x93, 0x21, 0x34 } }, + { { 0x97, 0x67, 0x9e, 0xeb, 0x6a, 0xf9, 0x6e, 0xd6, 0x73, 0xe8, 0x6b, 0x29, 0xec, 0x63, 0x82, 0x00, 0xa8, 0x99, 0x1c, 0x1d, 0x30, 0xc8, 0x90, 0x52, 0x90, 0xb6, 0x6a, 0x80, 0x4e, 0xff, 0x4b, 0x51 } } }, + { { { 0x0f, 0x7d, 0x63, 0x8c, 0x6e, 0x5c, 0xde, 0x30, 0xdf, 0x65, 0xfa, 0x2e, 0xb0, 0xa3, 0x25, 0x05, 0x54, 0xbd, 0x25, 0xba, 0x06, 0xae, 0xdf, 0x8b, 0xd9, 0x1b, 0xea, 0x38, 0xb3, 0x05, 0x16, 0x09 } }, + { { 0xc7, 0x8c, 0xbf, 0x64, 0x28, 0xad, 0xf8, 0xa5, 0x5a, 0x6f, 0xc9, 0xba, 0xd5, 0x7f, 0xd5, 0xd6, 0xbd, 0x66, 0x2f, 0x3d, 0xaa, 0x54, 0xf6, 0xba, 0x32, 0x22, 0x9a, 0x1e, 0x52, 0x05, 0xf4, 0x1d } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0xaa, 0x1f, 0xbb, 0xeb, 0xfe, 0xe4, 0x87, 0xfc, 0xb1, 0x2c, 0xb7, 0x88, 0xf4, 0xc6, 0xb9, 0xf5, 0x24, 0x46, 0xf2, 0xa5, 0x9f, 0x8f, 0x8a, 0x93, 0x70, 0x69, 0xd4, 0x56, 0xec, 0xfd, 0x06, 0x46 } }, + { { 0x4e, 0x66, 0xcf, 0x4e, 0x34, 0xce, 0x0c, 0xd9, 0xa6, 0x50, 0xd6, 0x5e, 0x95, 0xaf, 0xe9, 0x58, 0xfa, 0xee, 0x9b, 0xb8, 0xa5, 0x0f, 0x35, 0xe0, 0x43, 0x82, 0x6d, 0x65, 0xe6, 0xd9, 0x00, 0x0f } } }, + { { { 0x7b, 0x75, 0x3a, 0xfc, 0x64, 0xd3, 0x29, 0x7e, 0xdd, 0x49, 0x9a, 0x59, 0x53, 0xbf, 0xb4, 0xa7, 0x52, 0xb3, 0x05, 0xab, 0xc3, 0xaf, 0x16, 0x1a, 0x85, 0x42, 0x32, 0xa2, 0x86, 0xfa, 0x39, 0x43 } }, + { { 0x0e, 0x4b, 0xa3, 0x63, 0x8a, 0xfe, 0xa5, 0x58, 0xf1, 0x13, 0xbd, 0x9d, 0xaa, 0x7f, 0x76, 0x40, 0x70, 0x81, 0x10, 0x75, 0x99, 0xbb, 0xbe, 0x0b, 0x16, 0xe9, 0xba, 0x62, 0x34, 0xcc, 0x07, 0x6d } } }, + { { { 0xc3, 0xf1, 0xc6, 0x93, 0x65, 0xee, 0x0b, 0xbc, 0xea, 0x14, 0xf0, 0xc1, 0xf8, 0x84, 0x89, 0xc2, 0xc9, 0xd7, 0xea, 0x34, 0xca, 0xa7, 0xc4, 0x99, 0xd5, 0x50, 0x69, 0xcb, 0xd6, 0x21, 0x63, 0x7c } }, + { { 0x99, 0xeb, 0x7c, 0x31, 0x73, 0x64, 0x67, 0x7f, 0x0c, 0x66, 0xaa, 0x8c, 0x69, 0x91, 0xe2, 0x26, 0xd3, 0x23, 0xe2, 0x76, 0x5d, 0x32, 0x52, 0xdf, 0x5d, 0xc5, 0x8f, 0xb7, 0x7c, 0x84, 0xb3, 0x70 } } }, + { { { 0xeb, 0x01, 0xc7, 0x36, 0x97, 0x4e, 0xb6, 0xab, 0x5f, 0x0d, 0x2c, 0xba, 0x67, 0x64, 0x55, 0xde, 0xbc, 0xff, 0xa6, 0xec, 0x04, 0xd3, 0x8d, 0x39, 0x56, 0x5e, 0xee, 0xf8, 0xe4, 0x2e, 0x33, 0x62 } }, + { { 0x65, 0xef, 0xb8, 0x9f, 0xc8, 0x4b, 0xa7, 0xfd, 0x21, 0x49, 0x9b, 0x92, 0x35, 0x82, 0xd6, 0x0a, 0x9b, 0xf2, 0x79, 0xf1, 0x47, 0x2f, 0x6a, 0x7e, 0x9f, 0xcf, 0x18, 0x02, 0x3c, 0xfb, 0x1b, 0x3e } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0x2f, 0x8b, 0xc8, 0x40, 0x51, 0xd1, 0xac, 0x1a, 0x0b, 0xe4, 0xa9, 0xa2, 0x42, 0x21, 0x19, 0x2f, 0x7b, 0x97, 0xbf, 0xf7, 0x57, 0x6d, 0x3f, 0x3d, 0x4f, 0x0f, 0xe2, 0xb2, 0x81, 0x00, 0x9e, 0x7b } }, + { { 0x8c, 0x85, 0x2b, 0xc4, 0xfc, 0xf1, 0xab, 0xe8, 0x79, 0x22, 0xc4, 0x84, 0x17, 0x3a, 0xfa, 0x86, 0xa6, 0x7d, 0xf9, 0xf3, 0x6f, 0x03, 0x57, 0x20, 0x4d, 0x79, 0xf9, 0x6e, 0x71, 0x54, 0x38, 0x09 } } }, + { { { 0x40, 0x29, 0x74, 0xa8, 0x2f, 0x5e, 0xf9, 0x79, 0xa4, 0xf3, 0x3e, 0xb9, 0xfd, 0x33, 0x31, 0xac, 0x9a, 0x69, 0x88, 0x1e, 0x77, 0x21, 0x2d, 0xf3, 0x91, 0x52, 0x26, 0x15, 0xb2, 0xa6, 0xcf, 0x7e } }, + { { 0xc6, 0x20, 0x47, 0x6c, 0xa4, 0x7d, 0xcb, 0x63, 0xea, 0x5b, 0x03, 0xdf, 0x3e, 0x88, 0x81, 0x6d, 0xce, 0x07, 0x42, 0x18, 0x60, 0x7e, 0x7b, 0x55, 0xfe, 0x6a, 0xf3, 0xda, 0x5c, 0x8b, 0x95, 0x10 } } }, + { { { 0x62, 0xe4, 0x0d, 0x03, 0xb4, 0xd7, 0xcd, 0xfa, 0xbd, 0x46, 0xdf, 0x93, 0x71, 0x10, 0x2c, 0xa8, 0x3b, 0xb6, 0x09, 0x05, 0x70, 0x84, 0x43, 0x29, 0xa8, 0x59, 0xf5, 0x8e, 0x10, 0xe4, 0xd7, 0x20 } }, + { { 0x57, 0x82, 0x1c, 0xab, 0xbf, 0x62, 0x70, 0xe8, 0xc4, 0xcf, 0xf0, 0x28, 0x6e, 0x16, 0x3c, 0x08, 0x78, 0x89, 0x85, 0x46, 0x0f, 0xf6, 0x7f, 0xcf, 0xcb, 0x7e, 0xb8, 0x25, 0xe9, 0x5a, 0xfa, 0x03 } } }, + { { { 0xfb, 0x95, 0x92, 0x63, 0x50, 0xfc, 0x62, 0xf0, 0xa4, 0x5e, 0x8c, 0x18, 0xc2, 0x17, 0x24, 0xb7, 0x78, 0xc2, 0xa9, 0xe7, 0x6a, 0x32, 0xd6, 0x29, 0x85, 0xaf, 0xcb, 0x8d, 0x91, 0x13, 0xda, 0x6b } }, + { { 0x36, 0x0a, 0xc2, 0xb6, 0x4b, 0xa5, 0x5d, 0x07, 0x17, 0x41, 0x31, 0x5f, 0x62, 0x46, 0xf8, 0x92, 0xf9, 0x66, 0x48, 0x73, 0xa6, 0x97, 0x0d, 0x7d, 0x88, 0xee, 0x62, 0xb1, 0x03, 0xa8, 0x3f, 0x2c } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0x4a, 0xb1, 0x70, 0x8a, 0xa9, 0xe8, 0x63, 0x79, 0x00, 0xe2, 0x25, 0x16, 0xca, 0x4b, 0x0f, 0xa4, 0x66, 0xad, 0x19, 0x9f, 0x88, 0x67, 0x0c, 0x8b, 0xc2, 0x4a, 0x5b, 0x2b, 0x6d, 0x95, 0xaf, 0x19 } }, + { { 0x8b, 0x9d, 0xb6, 0xcc, 0x60, 0xb4, 0x72, 0x4f, 0x17, 0x69, 0x5a, 0x4a, 0x68, 0x34, 0xab, 0xa1, 0x45, 0x32, 0x3c, 0x83, 0x87, 0x72, 0x30, 0x54, 0x77, 0x68, 0xae, 0xfb, 0xb5, 0x8b, 0x22, 0x5e } } }, + { { { 0xf1, 0xb9, 0x87, 0x35, 0xc5, 0xbb, 0xb9, 0xcf, 0xf5, 0xd6, 0xcd, 0xd5, 0x0c, 0x7c, 0x0e, 0xe6, 0x90, 0x34, 0xfb, 0x51, 0x42, 0x1e, 0x6d, 0xac, 0x9a, 0x46, 0xc4, 0x97, 0x29, 0x32, 0xbf, 0x45 } }, + { { 0x66, 0x9e, 0xc6, 0x24, 0xc0, 0xed, 0xa5, 0x5d, 0x88, 0xd4, 0xf0, 0x73, 0x97, 0x7b, 0xea, 0x7f, 0x42, 0xff, 0x21, 0xa0, 0x9b, 0x2f, 0x9a, 0xfd, 0x53, 0x57, 0x07, 0x84, 0x48, 0x88, 0x9d, 0x52 } } }, + { { { 0xc6, 0x96, 0x48, 0x34, 0x2a, 0x06, 0xaf, 0x94, 0x3d, 0xf4, 0x1a, 0xcf, 0xf2, 0xc0, 0x21, 0xc2, 0x42, 0x5e, 0xc8, 0x2f, 0x35, 0xa2, 0x3e, 0x29, 0xfa, 0x0c, 0x84, 0xe5, 0x89, 0x72, 0x7c, 0x06 } }, + { { 0x32, 0x65, 0x03, 0xe5, 0x89, 0xa6, 0x6e, 0xb3, 0x5b, 0x8e, 0xca, 0xeb, 0xfe, 0x22, 0x56, 0x8b, 0x5d, 0x14, 0x4b, 0x4d, 0xf9, 0xbe, 0xb5, 0xf5, 0xe6, 0x5c, 0x7b, 0x8b, 0xf4, 0x13, 0x11, 0x34 } } }, + { { { 0x07, 0xc6, 0x22, 0x15, 0xe2, 0x9c, 0x60, 0xa2, 0x19, 0xd9, 0x27, 0xae, 0x37, 0x4e, 0xa6, 0xc9, 0x80, 0xa6, 0x91, 0x8f, 0x12, 0x49, 0xe5, 0x00, 0x18, 0x47, 0xd1, 0xd7, 0x28, 0x22, 0x63, 0x39 } }, + { { 0xe8, 0xe2, 0x00, 0x7e, 0xf2, 0x9e, 0x1e, 0x99, 0x39, 0x95, 0x04, 0xbd, 0x1e, 0x67, 0x7b, 0xb2, 0x26, 0xac, 0xe6, 0xaa, 0xe2, 0x46, 0xd5, 0xe4, 0xe8, 0x86, 0xbd, 0xab, 0x7c, 0x55, 0x59, 0x6f } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0x24, 0x64, 0x6e, 0x9b, 0x35, 0x71, 0x78, 0xce, 0x33, 0x03, 0x21, 0x33, 0x36, 0xf1, 0x73, 0x9b, 0xb9, 0x15, 0x8b, 0x2c, 0x69, 0xcf, 0x4d, 0xed, 0x4f, 0x4d, 0x57, 0x14, 0x13, 0x82, 0xa4, 0x4d } }, + { { 0x65, 0x6e, 0x0a, 0xa4, 0x59, 0x07, 0x17, 0xf2, 0x6b, 0x4a, 0x1f, 0x6e, 0xf6, 0xb5, 0xbc, 0x62, 0xe4, 0xb6, 0xda, 0xa2, 0x93, 0xbc, 0x29, 0x05, 0xd2, 0xd2, 0x73, 0x46, 0x03, 0x16, 0x40, 0x31 } } }, + { { { 0x4c, 0x73, 0x6d, 0x15, 0xbd, 0xa1, 0x4d, 0x5c, 0x13, 0x0b, 0x24, 0x06, 0x98, 0x78, 0x1c, 0x5b, 0xeb, 0x1f, 0x18, 0x54, 0x43, 0xd9, 0x55, 0x66, 0xda, 0x29, 0x21, 0xe8, 0xb8, 0x3c, 0x42, 0x22 } }, + { { 0xb4, 0xcd, 0x08, 0x6f, 0x15, 0x23, 0x1a, 0x0b, 0x22, 0xed, 0xd1, 0xf1, 0xa7, 0xc7, 0x73, 0x45, 0xf3, 0x9e, 0xce, 0x76, 0xb7, 0xf6, 0x39, 0xb6, 0x8e, 0x79, 0xbe, 0xe9, 0x9b, 0xcf, 0x7d, 0x62 } } }, + { { { 0x92, 0x5b, 0xfc, 0x72, 0xfd, 0xba, 0xf1, 0xfd, 0xa6, 0x7c, 0x95, 0xe3, 0x61, 0x3f, 0xe9, 0x03, 0xd4, 0x2b, 0xd4, 0x20, 0xd9, 0xdb, 0x4d, 0x32, 0x3e, 0xf5, 0x11, 0x64, 0xe3, 0xb4, 0xbe, 0x32 } }, + { { 0x86, 0x17, 0x90, 0xe7, 0xc9, 0x1f, 0x10, 0xa5, 0x6a, 0x2d, 0x39, 0xd0, 0x3b, 0xc4, 0xa6, 0xe9, 0x59, 0x13, 0xda, 0x1a, 0xe6, 0xa0, 0xb9, 0x3c, 0x50, 0xb8, 0x40, 0x7c, 0x15, 0x36, 0x5a, 0x42 } } }, + { { { 0xb4, 0x0b, 0x32, 0xab, 0xdc, 0x04, 0x51, 0x55, 0x21, 0x1e, 0x0b, 0x75, 0x99, 0x89, 0x73, 0x35, 0x3a, 0x91, 0x2b, 0xfe, 0xe7, 0x49, 0xea, 0x76, 0xc1, 0xf9, 0x46, 0xb9, 0x53, 0x02, 0x23, 0x04 } }, + { { 0xfc, 0x5a, 0x1e, 0x1d, 0x74, 0x58, 0x95, 0xa6, 0x8f, 0x7b, 0x97, 0x3e, 0x17, 0x3b, 0x79, 0x2d, 0xa6, 0x57, 0xef, 0x45, 0x02, 0x0b, 0x4d, 0x6e, 0x9e, 0x93, 0x8d, 0x2f, 0xd9, 0x9d, 0xdb, 0x04 } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0xc0, 0xd7, 0x56, 0x97, 0x58, 0x91, 0xde, 0x09, 0x4f, 0x9f, 0xbe, 0x63, 0xb0, 0x83, 0x86, 0x43, 0x5d, 0xbc, 0xe0, 0xf3, 0xc0, 0x75, 0xbf, 0x8b, 0x8e, 0xaa, 0xf7, 0x8b, 0x64, 0x6e, 0xb0, 0x63 } }, + { { 0x16, 0xae, 0x8b, 0xe0, 0x9b, 0x24, 0x68, 0x5c, 0x44, 0xc2, 0xd0, 0x08, 0xb7, 0x7b, 0x62, 0xfd, 0x7f, 0xd8, 0xd4, 0xb7, 0x50, 0xfd, 0x2c, 0x1b, 0xbf, 0x41, 0x95, 0xd9, 0x8e, 0xd8, 0x17, 0x1b } } }, + { { { 0x86, 0x55, 0x37, 0x8e, 0xc3, 0x38, 0x48, 0x14, 0xb5, 0x97, 0xd2, 0xa7, 0x54, 0x45, 0xf1, 0x35, 0x44, 0x38, 0x9e, 0xf1, 0x1b, 0xb6, 0x34, 0x00, 0x3c, 0x96, 0xee, 0x29, 0x00, 0xea, 0x2c, 0x0b } }, + { { 0xea, 0xda, 0x99, 0x9e, 0x19, 0x83, 0x66, 0x6d, 0xe9, 0x76, 0x87, 0x50, 0xd1, 0xfd, 0x3c, 0x60, 0x87, 0xc6, 0x41, 0xd9, 0x8e, 0xdb, 0x5e, 0xde, 0xaa, 0x9a, 0xd3, 0x28, 0xda, 0x95, 0xea, 0x47 } } }, + { { { 0xd0, 0x80, 0xba, 0x19, 0xae, 0x1d, 0xa9, 0x79, 0xf6, 0x3f, 0xac, 0x5d, 0x6f, 0x96, 0x1f, 0x2a, 0xce, 0x29, 0xb2, 0xff, 0x37, 0xf1, 0x94, 0x8f, 0x0c, 0xb5, 0x28, 0xba, 0x9a, 0x21, 0xf6, 0x66 } }, + { { 0x02, 0xfb, 0x54, 0xb8, 0x05, 0xf3, 0x81, 0x52, 0x69, 0x34, 0x46, 0x9d, 0x86, 0x76, 0x8f, 0xd7, 0xf8, 0x6a, 0x66, 0xff, 0xe6, 0xa7, 0x90, 0xf7, 0x5e, 0xcd, 0x6a, 0x9b, 0x55, 0xfc, 0x9d, 0x48 } } }, + { { { 0xbd, 0xaa, 0x13, 0xe6, 0xcd, 0x45, 0x4a, 0xa4, 0x59, 0x0a, 0x64, 0xb1, 0x98, 0xd6, 0x34, 0x13, 0x04, 0xe6, 0x97, 0x94, 0x06, 0xcb, 0xd4, 0x4e, 0xbb, 0x96, 0xcd, 0xd1, 0x57, 0xd1, 0xe3, 0x06 } }, + { { 0x7a, 0x6c, 0x45, 0x27, 0xc4, 0x93, 0x7f, 0x7d, 0x7c, 0x62, 0x50, 0x38, 0x3a, 0x6b, 0xb5, 0x88, 0xc6, 0xd9, 0xf1, 0x78, 0x19, 0xb9, 0x39, 0x93, 0x3d, 0xc9, 0xe0, 0x9c, 0x3c, 0xce, 0xf5, 0x72 } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0x24, 0xea, 0x23, 0x7d, 0x56, 0x2c, 0xe2, 0x59, 0x0e, 0x85, 0x60, 0x04, 0x88, 0x5a, 0x74, 0x1e, 0x4b, 0xef, 0x13, 0xda, 0x4c, 0xff, 0x83, 0x45, 0x85, 0x3f, 0x08, 0x95, 0x2c, 0x20, 0x13, 0x1f } }, + { { 0x48, 0x5f, 0x27, 0x90, 0x5c, 0x02, 0x42, 0xad, 0x78, 0x47, 0x5c, 0xb5, 0x7e, 0x08, 0x85, 0x00, 0xfa, 0x7f, 0xfd, 0xfd, 0xe7, 0x09, 0x11, 0xf2, 0x7e, 0x1b, 0x38, 0x6c, 0x35, 0x6d, 0x33, 0x66 } } }, + { { { 0x93, 0x03, 0x36, 0x81, 0xac, 0xe4, 0x20, 0x09, 0x35, 0x4c, 0x45, 0xb2, 0x1e, 0x4c, 0x14, 0x21, 0xe6, 0xe9, 0x8a, 0x7b, 0x8d, 0xfe, 0x1e, 0xc6, 0x3e, 0xc1, 0x35, 0xfa, 0xe7, 0x70, 0x4e, 0x1d } }, + { { 0x61, 0x2e, 0xc2, 0xdd, 0x95, 0x57, 0xd1, 0xab, 0x80, 0xe8, 0x63, 0x17, 0xb5, 0x48, 0xe4, 0x8a, 0x11, 0x9e, 0x72, 0xbe, 0x85, 0x8d, 0x51, 0x0a, 0xf2, 0x9f, 0xe0, 0x1c, 0xa9, 0x07, 0x28, 0x7b } } }, + { { { 0xbb, 0x71, 0x14, 0x5e, 0x26, 0x8c, 0x3d, 0xc8, 0xe9, 0x7c, 0xd3, 0xd6, 0xd1, 0x2f, 0x07, 0x6d, 0xe6, 0xdf, 0xfb, 0x79, 0xd6, 0x99, 0x59, 0x96, 0x48, 0x40, 0x0f, 0x3a, 0x7b, 0xb2, 0xa0, 0x72 } }, + { { 0x4e, 0x3b, 0x69, 0xc8, 0x43, 0x75, 0x51, 0x6c, 0x79, 0x56, 0xe4, 0xcb, 0xf7, 0xa6, 0x51, 0xc2, 0x2c, 0x42, 0x0b, 0xd4, 0x82, 0x20, 0x1c, 0x01, 0x08, 0x66, 0xd7, 0xbf, 0x04, 0x56, 0xfc, 0x02 } } }, + { { { 0x24, 0xe8, 0xb7, 0x60, 0xae, 0x47, 0x80, 0xfc, 0xe5, 0x23, 0xe7, 0xc2, 0xc9, 0x85, 0xe6, 0x98, 0xa0, 0x29, 0x4e, 0xe1, 0x84, 0x39, 0x2d, 0x95, 0x2c, 0xf3, 0x45, 0x3c, 0xff, 0xaf, 0x27, 0x4c } }, + { { 0x6b, 0xa6, 0xf5, 0x4b, 0x11, 0xbd, 0xba, 0x5b, 0x9e, 0xc4, 0xa4, 0x51, 0x1e, 0xbe, 0xd0, 0x90, 0x3a, 0x9c, 0xc2, 0x26, 0xb6, 0x1e, 0xf1, 0x95, 0x7d, 0xc8, 0x6d, 0x52, 0xe6, 0x99, 0x2c, 0x5f } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0x85, 0xe0, 0x24, 0x32, 0xb4, 0xd1, 0xef, 0xfc, 0x69, 0xa2, 0xbf, 0x8f, 0x72, 0x2c, 0x95, 0xf6, 0xe4, 0x6e, 0x7d, 0x90, 0xf7, 0x57, 0x81, 0xa0, 0xf7, 0xda, 0xef, 0x33, 0x07, 0xe3, 0x6b, 0x78 } }, + { { 0x36, 0x27, 0x3e, 0xc6, 0x12, 0x07, 0xab, 0x4e, 0xbe, 0x69, 0x9d, 0xb3, 0xbe, 0x08, 0x7c, 0x2a, 0x47, 0x08, 0xfd, 0xd4, 0xcd, 0x0e, 0x27, 0x34, 0x5b, 0x98, 0x34, 0x2f, 0x77, 0x5f, 0x3a, 0x65 } } }, + { { { 0x13, 0xaa, 0x2e, 0x4c, 0xf0, 0x22, 0xb8, 0x6c, 0xb3, 0x19, 0x4d, 0xeb, 0x6b, 0xd0, 0xa4, 0xc6, 0x9c, 0xdd, 0xc8, 0x5b, 0x81, 0x57, 0x89, 0xdf, 0x33, 0xa9, 0x68, 0x49, 0x80, 0xe4, 0xfe, 0x21 } }, + { { 0x00, 0x17, 0x90, 0x30, 0xe9, 0xd3, 0x60, 0x30, 0x31, 0xc2, 0x72, 0x89, 0x7a, 0x36, 0xa5, 0xbd, 0x39, 0x83, 0x85, 0x50, 0xa1, 0x5d, 0x6c, 0x41, 0x1d, 0xb5, 0x2c, 0x07, 0x40, 0x77, 0x0b, 0x50 } } }, + { { { 0x64, 0x34, 0xec, 0xc0, 0x9e, 0x44, 0x41, 0xaf, 0xa0, 0x36, 0x05, 0x6d, 0xea, 0x30, 0x25, 0x46, 0x35, 0x24, 0x9d, 0x86, 0xbd, 0x95, 0xf1, 0x6a, 0x46, 0xd7, 0x94, 0x54, 0xf9, 0x3b, 0xbd, 0x5d } }, + { { 0x77, 0x5b, 0xe2, 0x37, 0xc7, 0xe1, 0x7c, 0x13, 0x8c, 0x9f, 0x7b, 0x7b, 0x2a, 0xce, 0x42, 0xa3, 0xb9, 0x2a, 0x99, 0xa8, 0xc0, 0xd8, 0x3c, 0x86, 0xb0, 0xfb, 0xe9, 0x76, 0x77, 0xf7, 0xf5, 0x56 } } }, + { { { 0xdf, 0xb3, 0x46, 0x11, 0x6e, 0x13, 0xb7, 0x28, 0x4e, 0x56, 0xdd, 0xf1, 0xac, 0xad, 0x58, 0xc3, 0xf8, 0x88, 0x94, 0x5e, 0x06, 0x98, 0xa1, 0xe4, 0x6a, 0xfb, 0x0a, 0x49, 0x5d, 0x8a, 0xfe, 0x77 } }, + { { 0x46, 0x02, 0xf5, 0xa5, 0xaf, 0xc5, 0x75, 0x6d, 0xba, 0x45, 0x35, 0x0a, 0xfe, 0xc9, 0xac, 0x22, 0x91, 0x8d, 0x21, 0x95, 0x33, 0x03, 0xc0, 0x8a, 0x16, 0xf3, 0x39, 0xe0, 0x01, 0x0f, 0x53, 0x3c } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0x34, 0x75, 0x37, 0x1f, 0x34, 0x4e, 0xa9, 0x1d, 0x68, 0x67, 0xf8, 0x49, 0x98, 0x96, 0xfc, 0x4c, 0x65, 0x97, 0xf7, 0x02, 0x4a, 0x52, 0x6c, 0x01, 0xbd, 0x48, 0xbb, 0x1b, 0xed, 0xa4, 0xe2, 0x53 } }, + { { 0x59, 0xd5, 0x9b, 0x5a, 0xa2, 0x90, 0xd3, 0xb8, 0x37, 0x4c, 0x55, 0x82, 0x28, 0x08, 0x0f, 0x7f, 0xaa, 0x81, 0x65, 0xe0, 0x0c, 0x52, 0xc9, 0xa3, 0x32, 0x27, 0x64, 0xda, 0xfd, 0x34, 0x23, 0x5a } } }, + { { { 0xb5, 0xb0, 0x0c, 0x4d, 0xb3, 0x7b, 0x23, 0xc8, 0x1f, 0x8a, 0x39, 0x66, 0xe6, 0xba, 0x4c, 0x10, 0x37, 0xca, 0x9c, 0x7c, 0x05, 0x9e, 0xff, 0xc0, 0xf8, 0x8e, 0xb1, 0x8f, 0x6f, 0x67, 0x18, 0x26 } }, + { { 0x4b, 0x41, 0x13, 0x54, 0x23, 0x1a, 0xa4, 0x4e, 0xa9, 0x8b, 0x1e, 0x4b, 0xfc, 0x15, 0x24, 0xbb, 0x7e, 0xcb, 0xb6, 0x1e, 0x1b, 0xf5, 0xf2, 0xc8, 0x56, 0xec, 0x32, 0xa2, 0x60, 0x5b, 0xa0, 0x2a } } }, + { { { 0xa4, 0x29, 0x47, 0x86, 0x2e, 0x92, 0x4f, 0x11, 0x4f, 0xf3, 0xb2, 0x5c, 0xd5, 0x3e, 0xa6, 0xb9, 0xc8, 0xe2, 0x33, 0x11, 0x1f, 0x01, 0x8f, 0xb0, 0x9b, 0xc7, 0xa5, 0xff, 0x83, 0x0f, 0x1e, 0x28 } }, + { { 0x1d, 0x29, 0x7a, 0xa1, 0xec, 0x8e, 0xb5, 0xad, 0xea, 0x02, 0x68, 0x60, 0x74, 0x29, 0x1c, 0xa5, 0xcf, 0xc8, 0x3b, 0x7d, 0x8b, 0x2b, 0x7c, 0xad, 0xa4, 0x40, 0x17, 0x51, 0x59, 0x7c, 0x2e, 0x5d } } }, + { { { 0x0a, 0x6c, 0x4f, 0xbc, 0x3e, 0x32, 0xe7, 0x4a, 0x1a, 0x13, 0xc1, 0x49, 0x38, 0xbf, 0xf7, 0xc2, 0xd3, 0x8f, 0x6b, 0xad, 0x52, 0xf7, 0xcf, 0xbc, 0x27, 0xcb, 0x40, 0x67, 0x76, 0xcd, 0x6d, 0x56 } }, + { { 0xe5, 0xb0, 0x27, 0xad, 0xbe, 0x9b, 0xf2, 0xb5, 0x63, 0xde, 0x3a, 0x23, 0x95, 0xb7, 0x0a, 0x7e, 0xf3, 0x9e, 0x45, 0x6f, 0x19, 0x39, 0x75, 0x8f, 0x39, 0x3d, 0x0f, 0xc0, 0x9f, 0xf1, 0xe9, 0x51 } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0x88, 0xaa, 0x14, 0x24, 0x86, 0x94, 0x11, 0x12, 0x3e, 0x1a, 0xb5, 0xcc, 0xbb, 0xe0, 0x9c, 0xd5, 0x9c, 0x6d, 0xba, 0x58, 0x72, 0x8d, 0xfb, 0x22, 0x7b, 0x9f, 0x7c, 0x94, 0x30, 0xb3, 0x51, 0x21 } }, + { { 0xf6, 0x74, 0x3d, 0xf2, 0xaf, 0xd0, 0x1e, 0x03, 0x7c, 0x23, 0x6b, 0xc9, 0xfc, 0x25, 0x70, 0x90, 0xdc, 0x9a, 0xa4, 0xfb, 0x49, 0xfc, 0x3d, 0x0a, 0x35, 0x38, 0x6f, 0xe4, 0x7e, 0x50, 0x01, 0x2a } } }, + { { { 0xd6, 0xe3, 0x96, 0x61, 0x3a, 0xfd, 0xef, 0x9b, 0x1f, 0x90, 0xa4, 0x24, 0x14, 0x5b, 0xc8, 0xde, 0x50, 0xb1, 0x1d, 0xaf, 0xe8, 0x55, 0x8a, 0x87, 0x0d, 0xfe, 0xaa, 0x3b, 0x82, 0x2c, 0x8d, 0x7b } }, + { { 0x85, 0x0c, 0xaf, 0xf8, 0x83, 0x44, 0x49, 0xd9, 0x45, 0xcf, 0xf7, 0x48, 0xd9, 0x53, 0xb4, 0xf1, 0x65, 0xa0, 0xe1, 0xc3, 0xb3, 0x15, 0xed, 0x89, 0x9b, 0x4f, 0x62, 0xb3, 0x57, 0xa5, 0x45, 0x1c } } }, + { { { 0x8f, 0x12, 0xea, 0xaf, 0xd1, 0x1f, 0x79, 0x10, 0x0b, 0xf6, 0xa3, 0x7b, 0xea, 0xac, 0x8b, 0x57, 0x32, 0x62, 0xe7, 0x06, 0x12, 0x51, 0xa0, 0x3b, 0x43, 0x5e, 0xa4, 0x20, 0x78, 0x31, 0xce, 0x0d } }, + { { 0x84, 0x7c, 0xc2, 0xa6, 0x91, 0x23, 0xce, 0xbd, 0xdc, 0xf9, 0xce, 0xd5, 0x75, 0x30, 0x22, 0xe6, 0xf9, 0x43, 0x62, 0x0d, 0xf7, 0x75, 0x9d, 0x7f, 0x8c, 0xff, 0x7d, 0xe4, 0x72, 0xac, 0x9f, 0x1c } } }, + { { { 0x88, 0xc1, 0x99, 0xd0, 0x3c, 0x1c, 0x5d, 0xb4, 0xef, 0x13, 0x0f, 0x90, 0xb9, 0x36, 0x2f, 0x95, 0x95, 0xc6, 0xdc, 0xde, 0x0a, 0x51, 0xe2, 0x8d, 0xf3, 0xbc, 0x51, 0xec, 0xdf, 0xb1, 0xa2, 0x5f } }, + { { 0x2e, 0x68, 0xa1, 0x23, 0x7d, 0x9b, 0x40, 0x69, 0x85, 0x7b, 0x42, 0xbf, 0x90, 0x4b, 0xd6, 0x40, 0x2f, 0xd7, 0x52, 0x52, 0xb2, 0x21, 0xde, 0x64, 0xbd, 0x88, 0xc3, 0x6d, 0xa5, 0xfa, 0x81, 0x3f } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0xfb, 0xfd, 0x47, 0x7b, 0x8a, 0x66, 0x9e, 0x79, 0x2e, 0x64, 0x82, 0xef, 0xf7, 0x21, 0xec, 0xf6, 0xd8, 0x86, 0x09, 0x31, 0x7c, 0xdd, 0x03, 0x6a, 0x58, 0xa0, 0x77, 0xb7, 0x9b, 0x8c, 0x87, 0x1f } }, + { { 0x55, 0x47, 0xe4, 0xa8, 0x3d, 0x55, 0x21, 0x34, 0xab, 0x1d, 0xae, 0xe0, 0xf4, 0xea, 0xdb, 0xc5, 0xb9, 0x58, 0xbf, 0xc4, 0x2a, 0x89, 0x31, 0x1a, 0xf4, 0x2d, 0xe1, 0xca, 0x37, 0x99, 0x47, 0x59 } } }, + { { { 0xc7, 0xca, 0x63, 0xc1, 0x49, 0xa9, 0x35, 0x45, 0x55, 0x7e, 0xda, 0x64, 0x32, 0x07, 0x50, 0xf7, 0x32, 0xac, 0xde, 0x75, 0x58, 0x9b, 0x11, 0xb2, 0x3a, 0x1f, 0xf5, 0xf7, 0x79, 0x04, 0xe6, 0x08 } }, + { { 0x46, 0xfa, 0x22, 0x4b, 0xfa, 0xe1, 0xfe, 0x96, 0xfc, 0x67, 0xba, 0x67, 0x97, 0xc4, 0xe7, 0x1b, 0x86, 0x90, 0x5f, 0xee, 0xf4, 0x5b, 0x11, 0xb2, 0xcd, 0xad, 0xee, 0xc2, 0x48, 0x6c, 0x2b, 0x1b } } }, + { { { 0xe3, 0x39, 0x62, 0xb4, 0x4f, 0x31, 0x04, 0xc9, 0xda, 0xd5, 0x73, 0x51, 0x57, 0xc5, 0xb8, 0xf3, 0xa3, 0x43, 0x70, 0xe4, 0x61, 0x81, 0x84, 0xe2, 0xbb, 0xbf, 0x4f, 0x9e, 0xa4, 0x5e, 0x74, 0x06 } }, + { { 0x29, 0xac, 0xff, 0x27, 0xe0, 0x59, 0xbe, 0x39, 0x9c, 0x0d, 0x83, 0xd7, 0x10, 0x0b, 0x15, 0xb7, 0xe1, 0xc2, 0x2c, 0x30, 0x73, 0x80, 0x3a, 0x7d, 0x5d, 0xab, 0x58, 0x6b, 0xc1, 0xf0, 0xf4, 0x22 } } }, + { { { 0xfe, 0x7f, 0xfb, 0x35, 0x7d, 0xc6, 0x01, 0x23, 0x28, 0xc4, 0x02, 0xac, 0x1f, 0x42, 0xb4, 0x9d, 0xfc, 0x00, 0x94, 0xa5, 0xee, 0xca, 0xda, 0x97, 0x09, 0x41, 0x77, 0x87, 0x5d, 0x7b, 0x87, 0x78 } }, + { { 0xf5, 0xfb, 0x90, 0x2d, 0x81, 0x19, 0x9e, 0x2f, 0x6d, 0x85, 0x88, 0x8c, 0x40, 0x5c, 0x77, 0x41, 0x4d, 0x01, 0x19, 0x76, 0x60, 0xe8, 0x4c, 0x48, 0xe4, 0x33, 0x83, 0x32, 0x6c, 0xb4, 0x41, 0x03 } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0xff, 0x10, 0xc2, 0x09, 0x4f, 0x6e, 0xf4, 0xd2, 0xdf, 0x7e, 0xca, 0x7b, 0x1c, 0x1d, 0xba, 0xa3, 0xb6, 0xda, 0x67, 0x33, 0xd4, 0x87, 0x36, 0x4b, 0x11, 0x20, 0x05, 0xa6, 0x29, 0xc1, 0x87, 0x17 } }, + { { 0xf6, 0x96, 0xca, 0x2f, 0xda, 0x38, 0xa7, 0x1b, 0xfc, 0xca, 0x7d, 0xfe, 0x08, 0x89, 0xe2, 0x47, 0x2b, 0x6a, 0x5d, 0x4b, 0xfa, 0xa1, 0xb4, 0xde, 0xb6, 0xc2, 0x31, 0x51, 0xf5, 0xe0, 0xa4, 0x0b } } }, + { { { 0x5c, 0xe5, 0xc6, 0x04, 0x8e, 0x2b, 0x57, 0xbe, 0x38, 0x85, 0x23, 0xcb, 0xb7, 0xbe, 0x4f, 0xa9, 0xd3, 0x6e, 0x12, 0xaa, 0xd5, 0xb2, 0x2e, 0x93, 0x29, 0x9a, 0x4a, 0x88, 0x18, 0x43, 0xf5, 0x01 } }, + { { 0x50, 0xfc, 0xdb, 0xa2, 0x59, 0x21, 0x8d, 0xbd, 0x7e, 0x33, 0xae, 0x2f, 0x87, 0x1a, 0xd0, 0x97, 0xc7, 0x0d, 0x4d, 0x63, 0x01, 0xef, 0x05, 0x84, 0xec, 0x40, 0xdd, 0xa8, 0x0a, 0x4f, 0x70, 0x0b } } }, + { { { 0x41, 0x69, 0x01, 0x67, 0x5c, 0xd3, 0x8a, 0xc5, 0xcf, 0x3f, 0xd1, 0x57, 0xd1, 0x67, 0x3e, 0x01, 0x39, 0xb5, 0xcb, 0x81, 0x56, 0x96, 0x26, 0xb6, 0xc2, 0xe7, 0x5c, 0xfb, 0x63, 0x97, 0x58, 0x06 } }, + { { 0x0c, 0x0e, 0xf3, 0xba, 0xf0, 0xe5, 0xba, 0xb2, 0x57, 0x77, 0xc6, 0x20, 0x9b, 0x89, 0x24, 0xbe, 0xf2, 0x9c, 0x8a, 0xba, 0x69, 0xc1, 0xf1, 0xb0, 0x4f, 0x2a, 0x05, 0x9a, 0xee, 0x10, 0x7e, 0x36 } } }, + { { { 0x3f, 0x26, 0xe9, 0x40, 0xe9, 0x03, 0xad, 0x06, 0x69, 0x91, 0xe0, 0xd1, 0x89, 0x60, 0x84, 0x79, 0xde, 0x27, 0x6d, 0xe6, 0x76, 0xbd, 0xea, 0xe6, 0xae, 0x48, 0xc3, 0x67, 0xc0, 0x57, 0xcd, 0x2f } }, + { { 0x7f, 0xc1, 0xdc, 0xb9, 0xc7, 0xbc, 0x86, 0x3d, 0x55, 0x4b, 0x28, 0x7a, 0xfb, 0x4d, 0xc7, 0xf8, 0xbc, 0x67, 0x2a, 0x60, 0x4d, 0x8f, 0x07, 0x0b, 0x1a, 0x17, 0xbf, 0xfa, 0xac, 0xa7, 0x3d, 0x1a } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0x91, 0x3f, 0xed, 0x5e, 0x18, 0x78, 0x3f, 0x23, 0x2c, 0x0d, 0x8c, 0x44, 0x00, 0xe8, 0xfb, 0xe9, 0x8e, 0xd6, 0xd1, 0x36, 0x58, 0x57, 0x9e, 0xae, 0x4b, 0x5c, 0x0b, 0x07, 0xbc, 0x6b, 0x55, 0x2b } }, + { { 0x6f, 0x4d, 0x17, 0xd7, 0xe1, 0x84, 0xd9, 0x78, 0xb1, 0x90, 0xfd, 0x2e, 0xb3, 0xb5, 0x19, 0x3f, 0x1b, 0xfa, 0xc0, 0x68, 0xb3, 0xdd, 0x00, 0x2e, 0x89, 0xbd, 0x7e, 0x80, 0x32, 0x13, 0xa0, 0x7b } } }, + { { { 0x1a, 0x6f, 0x40, 0xaf, 0x44, 0x44, 0xb0, 0x43, 0x8f, 0x0d, 0xd0, 0x1e, 0xc4, 0x0b, 0x19, 0x5d, 0x8e, 0xfe, 0xc1, 0xf3, 0xc5, 0x5c, 0x91, 0xf8, 0x04, 0x4e, 0xbe, 0x90, 0xb4, 0x47, 0x5c, 0x3f } }, + { { 0xb0, 0x3b, 0x2c, 0xf3, 0xfe, 0x32, 0x71, 0x07, 0x3f, 0xaa, 0xba, 0x45, 0x60, 0xa8, 0x8d, 0xea, 0x54, 0xcb, 0x39, 0x10, 0xb4, 0xf2, 0x8b, 0xd2, 0x14, 0x82, 0x42, 0x07, 0x8e, 0xe9, 0x7c, 0x53 } } }, + { { { 0xb0, 0xae, 0xc1, 0x8d, 0xc9, 0x8f, 0xb9, 0x7a, 0x77, 0xef, 0xba, 0x79, 0xa0, 0x3c, 0xa8, 0xf5, 0x6a, 0xe2, 0x3f, 0x5d, 0x00, 0xe3, 0x4b, 0x45, 0x24, 0x7b, 0x43, 0x78, 0x55, 0x1d, 0x2b, 0x1e } }, + { { 0x01, 0xb8, 0xd6, 0x16, 0x67, 0xa0, 0x15, 0xb9, 0xe1, 0x58, 0xa4, 0xa7, 0x31, 0x37, 0x77, 0x2f, 0x8b, 0x12, 0x9f, 0xf4, 0x3f, 0xc7, 0x36, 0x66, 0xd2, 0xa8, 0x56, 0xf7, 0x7f, 0x74, 0xc6, 0x41 } } }, + { { { 0x5d, 0xf8, 0xb4, 0xa8, 0x30, 0xdd, 0xcc, 0x38, 0xa5, 0xd3, 0xca, 0xd8, 0xd1, 0xf8, 0xb2, 0x31, 0x91, 0xd4, 0x72, 0x05, 0x57, 0x4a, 0x3b, 0x82, 0x4a, 0xc6, 0x68, 0x20, 0xe2, 0x18, 0x41, 0x61 } }, + { { 0x19, 0xd4, 0x8d, 0x47, 0x29, 0x12, 0x65, 0xb0, 0x11, 0x78, 0x47, 0xb5, 0xcb, 0xa3, 0xa5, 0xfa, 0x05, 0x85, 0x54, 0xa9, 0x33, 0x97, 0x8d, 0x2b, 0xc2, 0xfe, 0x99, 0x35, 0x28, 0xe5, 0xeb, 0x63 } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0xb1, 0x3f, 0x3f, 0xef, 0xd8, 0xf4, 0xfc, 0xb3, 0xa0, 0x60, 0x50, 0x06, 0x2b, 0x29, 0x52, 0x70, 0x15, 0x0b, 0x24, 0x24, 0xf8, 0x5f, 0x79, 0x18, 0xcc, 0xff, 0x89, 0x99, 0x84, 0xa1, 0xae, 0x13 } }, + { { 0x44, 0x1f, 0xb8, 0xc2, 0x01, 0xc1, 0x30, 0x19, 0x55, 0x05, 0x60, 0x10, 0xa4, 0x6c, 0x2d, 0x67, 0x70, 0xe5, 0x25, 0x1b, 0xf2, 0xbf, 0xdd, 0xfb, 0x70, 0x2b, 0xa1, 0x8c, 0x9c, 0x94, 0x84, 0x08 } } }, + { { { 0xe7, 0xc4, 0x43, 0x4d, 0xc9, 0x2b, 0x69, 0x5d, 0x1d, 0x3c, 0xaf, 0xbb, 0x43, 0x38, 0x4e, 0x98, 0x3d, 0xed, 0x0d, 0x21, 0x03, 0xfd, 0xf0, 0x99, 0x47, 0x04, 0xb0, 0x98, 0x69, 0x55, 0x72, 0x0f } }, + { { 0x5e, 0xdf, 0x15, 0x53, 0x3b, 0x86, 0x80, 0xb0, 0xf1, 0x70, 0x68, 0x8f, 0x66, 0x7c, 0x0e, 0x49, 0x1a, 0xd8, 0x6b, 0xfe, 0x4e, 0xef, 0xca, 0x47, 0xd4, 0x03, 0xc1, 0x37, 0x50, 0x9c, 0xc1, 0x16 } } }, + { { { 0xcd, 0x24, 0xc6, 0x3e, 0x0c, 0x82, 0x9b, 0x91, 0x2b, 0x61, 0x4a, 0xb2, 0x0f, 0x88, 0x55, 0x5f, 0x5a, 0x57, 0xff, 0xe5, 0x74, 0x0b, 0x13, 0x43, 0x00, 0xd8, 0x6b, 0xcf, 0xd2, 0x15, 0x03, 0x2c } }, + { { 0xdc, 0xff, 0x15, 0x61, 0x2f, 0x4a, 0x2f, 0x62, 0xf2, 0x04, 0x2f, 0xb5, 0x0c, 0xb7, 0x1e, 0x3f, 0x74, 0x1a, 0x0f, 0xd7, 0xea, 0xcd, 0xd9, 0x7d, 0xf6, 0x12, 0x0e, 0x2f, 0xdb, 0x5a, 0x3b, 0x16 } } }, + { { { 0x1b, 0x37, 0x47, 0xe3, 0xf5, 0x9e, 0xea, 0x2c, 0x2a, 0xe7, 0x82, 0x36, 0xf4, 0x1f, 0x81, 0x47, 0x92, 0x4b, 0x69, 0x0e, 0x11, 0x8c, 0x5d, 0x53, 0x5b, 0x81, 0x27, 0x08, 0xbc, 0xa0, 0xae, 0x25 } }, + { { 0x69, 0x32, 0xa1, 0x05, 0x11, 0x42, 0x00, 0xd2, 0x59, 0xac, 0x4d, 0x62, 0x8b, 0x13, 0xe2, 0x50, 0x5d, 0xa0, 0x9d, 0x9b, 0xfd, 0xbb, 0x12, 0x41, 0x75, 0x41, 0x9e, 0xcc, 0xdc, 0xc7, 0xdc, 0x5d } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0xd9, 0xe3, 0x38, 0x06, 0x46, 0x70, 0x82, 0x5e, 0x28, 0x49, 0x79, 0xff, 0x25, 0xd2, 0x4e, 0x29, 0x8d, 0x06, 0xb0, 0x23, 0xae, 0x9b, 0x66, 0xe4, 0x7d, 0xc0, 0x70, 0x91, 0xa3, 0xfc, 0xec, 0x4e } }, + { { 0x62, 0x12, 0x37, 0x6a, 0x30, 0xf6, 0x1e, 0xfb, 0x14, 0x5c, 0x0d, 0x0e, 0xb7, 0x81, 0x6a, 0xe7, 0x08, 0x05, 0xac, 0xaa, 0x38, 0x46, 0xe2, 0x73, 0xea, 0x4b, 0x07, 0x81, 0x43, 0x7c, 0x9e, 0x5e } } }, + { { { 0xfc, 0xf9, 0x21, 0x4f, 0x2e, 0x76, 0x9b, 0x1f, 0x28, 0x60, 0x77, 0x43, 0x32, 0x9d, 0xbe, 0x17, 0x30, 0x2a, 0xc6, 0x18, 0x92, 0x66, 0x62, 0x30, 0x98, 0x40, 0x11, 0xa6, 0x7f, 0x18, 0x84, 0x28 } }, + { { 0x3f, 0xab, 0xd3, 0xf4, 0x8a, 0x76, 0xa1, 0x3c, 0xca, 0x2d, 0x49, 0xc3, 0xea, 0x08, 0x0b, 0x85, 0x17, 0x2a, 0xc3, 0x6c, 0x08, 0xfd, 0x57, 0x9f, 0x3d, 0x5f, 0xdf, 0x67, 0x68, 0x42, 0x00, 0x32 } } }, + { { { 0x51, 0x60, 0x1b, 0x06, 0x4f, 0x8a, 0x21, 0xba, 0x38, 0xa8, 0xba, 0xd6, 0x40, 0xf6, 0xe9, 0x9b, 0x76, 0x4d, 0x56, 0x21, 0x5b, 0x0a, 0x9b, 0x2e, 0x4f, 0x3d, 0x81, 0x32, 0x08, 0x9f, 0x97, 0x5b } }, + { { 0xe5, 0x44, 0xec, 0x06, 0x9d, 0x90, 0x79, 0x9f, 0xd3, 0xe0, 0x79, 0xaf, 0x8f, 0x10, 0xfd, 0xdd, 0x04, 0xae, 0x27, 0x97, 0x46, 0x33, 0x79, 0xea, 0xb8, 0x4e, 0xca, 0x5a, 0x59, 0x57, 0xe1, 0x0e } } }, + { { { 0x1a, 0xda, 0xf3, 0xa5, 0x41, 0x43, 0x28, 0xfc, 0x7e, 0xe7, 0x71, 0xea, 0xc6, 0x3b, 0x59, 0xcc, 0x2e, 0xd3, 0x40, 0xec, 0xb3, 0x13, 0x6f, 0x44, 0xcd, 0x13, 0xb2, 0x37, 0xf2, 0x6e, 0xd9, 0x1c } }, + { { 0xe3, 0xdb, 0x60, 0xcd, 0x5c, 0x4a, 0x18, 0x0f, 0xef, 0x73, 0x36, 0x71, 0x8c, 0xf6, 0x11, 0xb4, 0xd8, 0xce, 0x17, 0x5e, 0x4f, 0x26, 0x77, 0x97, 0x5f, 0xcb, 0xef, 0x91, 0xeb, 0x6a, 0x62, 0x7a } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0x18, 0x4a, 0xa2, 0x97, 0x08, 0x81, 0x2d, 0x83, 0xc4, 0xcc, 0xf0, 0x83, 0x7e, 0xec, 0x0d, 0x95, 0x4c, 0x5b, 0xfb, 0xfa, 0x98, 0x80, 0x4a, 0x66, 0x56, 0x0c, 0x51, 0xb3, 0xf2, 0x04, 0x5d, 0x27 } }, + { { 0x3b, 0xb9, 0xb8, 0x06, 0x5a, 0x2e, 0xfe, 0xc3, 0x82, 0x37, 0x9c, 0xa3, 0x11, 0x1f, 0x9c, 0xa6, 0xda, 0x63, 0x48, 0x9b, 0xad, 0xde, 0x2d, 0xa6, 0xbc, 0x6e, 0x32, 0xda, 0x27, 0x65, 0xdd, 0x57 } } }, + { { { 0x84, 0x4f, 0x37, 0x31, 0x7d, 0x2e, 0xbc, 0xad, 0x87, 0x07, 0x2a, 0x6b, 0x37, 0xfc, 0x5f, 0xeb, 0x4e, 0x75, 0x35, 0xa6, 0xde, 0xab, 0x0a, 0x19, 0x3a, 0xb7, 0xb1, 0xef, 0x92, 0x6a, 0x3b, 0x3c } }, + { { 0x3b, 0xb2, 0x94, 0x6d, 0x39, 0x60, 0xac, 0xee, 0xe7, 0x81, 0x1a, 0x3b, 0x76, 0x87, 0x5c, 0x05, 0x94, 0x2a, 0x45, 0xb9, 0x80, 0xe9, 0x22, 0xb1, 0x07, 0xcb, 0x40, 0x9e, 0x70, 0x49, 0x6d, 0x12 } } }, + { { { 0xfd, 0x18, 0x78, 0x84, 0xa8, 0x4c, 0x7d, 0x6e, 0x59, 0xa6, 0xe5, 0x74, 0xf1, 0x19, 0xa6, 0x84, 0x2e, 0x51, 0xc1, 0x29, 0x13, 0xf2, 0x14, 0x6b, 0x5d, 0x53, 0x51, 0xf7, 0xef, 0xbf, 0x01, 0x22 } }, + { { 0xa4, 0x4b, 0x62, 0x4c, 0xe6, 0xfd, 0x72, 0x07, 0xf2, 0x81, 0xfc, 0xf2, 0xbd, 0x12, 0x7c, 0x68, 0x76, 0x2a, 0xba, 0xf5, 0x65, 0xb1, 0x1f, 0x17, 0x0a, 0x38, 0xb0, 0xbf, 0xc0, 0xf8, 0xf4, 0x2a } } }, + { { { 0x55, 0x60, 0x55, 0x5b, 0xe4, 0x1d, 0x71, 0x4c, 0x9d, 0x5b, 0x9f, 0x70, 0xa6, 0x85, 0x9a, 0x2c, 0xa0, 0xe2, 0x32, 0x48, 0xce, 0x9e, 0x2a, 0xa5, 0x07, 0x3b, 0xc7, 0x6c, 0x86, 0x77, 0xde, 0x3c } }, + { { 0xf7, 0x18, 0x7a, 0x96, 0x7e, 0x43, 0x57, 0xa9, 0x55, 0xfc, 0x4e, 0xb6, 0x72, 0x00, 0xf2, 0xe4, 0xd7, 0x52, 0xd3, 0xd3, 0xb6, 0x85, 0xf6, 0x71, 0xc7, 0x44, 0x3f, 0x7f, 0xd7, 0xb3, 0xf2, 0x79 } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0x46, 0xca, 0xa7, 0x55, 0x7b, 0x79, 0xf3, 0xca, 0x5a, 0x65, 0xf6, 0xed, 0x50, 0x14, 0x7b, 0xe4, 0xc4, 0x2a, 0x65, 0x9e, 0xe2, 0xf9, 0xca, 0xa7, 0x22, 0x26, 0x53, 0xcb, 0x21, 0x5b, 0xa7, 0x31 } }, + { { 0x90, 0xd7, 0xc5, 0x26, 0x08, 0xbd, 0xb0, 0x53, 0x63, 0x58, 0xc3, 0x31, 0x5e, 0x75, 0x46, 0x15, 0x91, 0xa6, 0xf8, 0x2f, 0x1a, 0x08, 0x65, 0x88, 0x2f, 0x98, 0x04, 0xf1, 0x7c, 0x6e, 0x00, 0x77 } } }, + { { { 0x81, 0x21, 0x61, 0x09, 0xf6, 0x4e, 0xf1, 0x92, 0xee, 0x63, 0x61, 0x73, 0x87, 0xc7, 0x54, 0x0e, 0x42, 0x4b, 0xc9, 0x47, 0xd1, 0xb8, 0x7e, 0x91, 0x75, 0x37, 0x99, 0x28, 0xb8, 0xdd, 0x7f, 0x50 } }, + { { 0x89, 0x8f, 0xc0, 0xbe, 0x5d, 0xd6, 0x9f, 0xa0, 0xf0, 0x9d, 0x81, 0xce, 0x3a, 0x7b, 0x98, 0x58, 0xbb, 0xd7, 0x78, 0xc8, 0x3f, 0x13, 0xf1, 0x74, 0x19, 0xdf, 0xf8, 0x98, 0x89, 0x5d, 0xfa, 0x5f } } }, + { { { 0x9e, 0x35, 0x85, 0x94, 0x47, 0x1f, 0x90, 0x15, 0x26, 0xd0, 0x84, 0xed, 0x8a, 0x80, 0xf7, 0x63, 0x42, 0x86, 0x27, 0xd7, 0xf4, 0x75, 0x58, 0xdc, 0x9c, 0xc0, 0x22, 0x7e, 0x20, 0x35, 0xfd, 0x1f } }, + { { 0x68, 0x0e, 0x6f, 0x97, 0xba, 0x70, 0xbb, 0xa3, 0x0e, 0xe5, 0x0b, 0x12, 0xf4, 0xa2, 0xdc, 0x47, 0xf8, 0xe6, 0xd0, 0x23, 0x6c, 0x33, 0xa8, 0x99, 0x46, 0x6e, 0x0f, 0x44, 0xba, 0x76, 0x48, 0x0f } } }, + { { { 0xa3, 0x2a, 0x61, 0x37, 0xe2, 0x59, 0x12, 0x0e, 0x27, 0xba, 0x64, 0x43, 0xae, 0xc0, 0x42, 0x69, 0x79, 0xa4, 0x1e, 0x29, 0x8b, 0x15, 0xeb, 0xf8, 0xaf, 0xd4, 0xa2, 0x68, 0x33, 0xb5, 0x7a, 0x24 } }, + { { 0x2c, 0x19, 0x33, 0xdd, 0x1b, 0xab, 0xec, 0x01, 0xb0, 0x23, 0xf8, 0x42, 0x2b, 0x06, 0x88, 0xea, 0x3d, 0x2d, 0x00, 0x2a, 0x78, 0x45, 0x4d, 0x38, 0xed, 0x2e, 0x2e, 0x44, 0x49, 0xed, 0xcb, 0x33 } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0xa0, 0x68, 0xe8, 0x41, 0x8f, 0x91, 0xf8, 0x11, 0x13, 0x90, 0x2e, 0xa7, 0xab, 0x30, 0xef, 0xad, 0xa0, 0x61, 0x00, 0x88, 0xef, 0xdb, 0xce, 0x5b, 0x5c, 0xbb, 0x62, 0xc8, 0x56, 0xf9, 0x00, 0x73 } }, + { { 0x3f, 0x60, 0xc1, 0x82, 0x2d, 0xa3, 0x28, 0x58, 0x24, 0x9e, 0x9f, 0xe3, 0x70, 0xcc, 0x09, 0x4e, 0x1a, 0x3f, 0x11, 0x11, 0x15, 0x07, 0x3c, 0xa4, 0x41, 0xe0, 0x65, 0xa3, 0x0a, 0x41, 0x6d, 0x11 } } }, + { { { 0x31, 0x40, 0x01, 0x52, 0x56, 0x94, 0x5b, 0x28, 0x8a, 0xaa, 0x52, 0xee, 0xd8, 0x0a, 0x05, 0x8d, 0xcd, 0xb5, 0xaa, 0x2e, 0x38, 0xaa, 0xb7, 0x87, 0xf7, 0x2b, 0xfb, 0x04, 0xcb, 0x84, 0x3d, 0x54 } }, + { { 0x20, 0xef, 0x59, 0xde, 0xa4, 0x2b, 0x93, 0x6e, 0x2e, 0xec, 0x42, 0x9a, 0xd4, 0x2d, 0xf4, 0x46, 0x58, 0x27, 0x2b, 0x18, 0x8f, 0x83, 0x3d, 0x69, 0x9e, 0xd4, 0x3e, 0xb6, 0xc5, 0xfd, 0x58, 0x03 } } }, + { { { 0x33, 0x89, 0xc9, 0x63, 0x62, 0x1c, 0x17, 0xb4, 0x60, 0xc4, 0x26, 0x68, 0x09, 0xc3, 0x2e, 0x37, 0x0f, 0x7b, 0xb4, 0x9c, 0xb6, 0xf9, 0xfb, 0xd4, 0x51, 0x78, 0xc8, 0x63, 0xea, 0x77, 0x47, 0x07 } }, + { { 0x32, 0xb4, 0x18, 0x47, 0x79, 0xcb, 0xd4, 0x5a, 0x07, 0x14, 0x0f, 0xa0, 0xd5, 0xac, 0xd0, 0x41, 0x40, 0xab, 0x61, 0x23, 0xe5, 0x2a, 0x2a, 0x6f, 0xf7, 0xa8, 0xd4, 0x76, 0xef, 0xe7, 0x45, 0x6c } } }, + { { { 0xa1, 0x5e, 0x60, 0x4f, 0xfb, 0xe1, 0x70, 0x6a, 0x1f, 0x55, 0x4f, 0x09, 0xb4, 0x95, 0x33, 0x36, 0xc6, 0x81, 0x01, 0x18, 0x06, 0x25, 0x27, 0xa4, 0xb4, 0x24, 0xa4, 0x86, 0x03, 0x4c, 0xac, 0x02 } }, + { { 0x77, 0x38, 0xde, 0xd7, 0x60, 0x48, 0x07, 0xf0, 0x74, 0xa8, 0xff, 0x54, 0xe5, 0x30, 0x43, 0xff, 0x77, 0xfb, 0x21, 0x07, 0xff, 0xb2, 0x07, 0x6b, 0xe4, 0xe5, 0x30, 0xfc, 0x19, 0x6c, 0xa3, 0x01 } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0x13, 0xc5, 0x2c, 0xac, 0xd3, 0x83, 0x82, 0x7c, 0x29, 0xf7, 0x05, 0xa5, 0x00, 0xb6, 0x1f, 0x86, 0x55, 0xf4, 0xd6, 0x2f, 0x0c, 0x99, 0xd0, 0x65, 0x9b, 0x6b, 0x46, 0x0d, 0x43, 0xf8, 0x16, 0x28 } }, + { { 0x1e, 0x7f, 0xb4, 0x74, 0x7e, 0xb1, 0x89, 0x4f, 0x18, 0x5a, 0xab, 0x64, 0x06, 0xdf, 0x45, 0x87, 0xe0, 0x6a, 0xc6, 0xf0, 0x0e, 0xc9, 0x24, 0x35, 0x38, 0xea, 0x30, 0x54, 0xb4, 0xc4, 0x52, 0x54 } } }, + { { { 0xe9, 0x9f, 0xdc, 0x3f, 0xc1, 0x89, 0x44, 0x74, 0x27, 0xe4, 0xc1, 0x90, 0xff, 0x4a, 0xa7, 0x3c, 0xee, 0xcd, 0xf4, 0x1d, 0x25, 0x94, 0x7f, 0x63, 0x16, 0x48, 0xbc, 0x64, 0xfe, 0x95, 0xc4, 0x0c } }, + { { 0x8b, 0x19, 0x75, 0x6e, 0x03, 0x06, 0x5e, 0x6a, 0x6f, 0x1a, 0x8c, 0xe3, 0xd3, 0x28, 0xf2, 0xe0, 0xb9, 0x7a, 0x43, 0x69, 0xe6, 0xd3, 0xc0, 0xfe, 0x7e, 0x97, 0xab, 0x6c, 0x7b, 0x8e, 0x13, 0x42 } } }, + { { { 0xd4, 0xca, 0x70, 0x3d, 0xab, 0xfb, 0x5f, 0x5e, 0x00, 0x0c, 0xcc, 0x77, 0x22, 0xf8, 0x78, 0x55, 0xae, 0x62, 0x35, 0xfb, 0x9a, 0xc6, 0x03, 0xe4, 0x0c, 0xee, 0xab, 0xc7, 0xc0, 0x89, 0x87, 0x54 } }, + { { 0x32, 0xad, 0xae, 0x85, 0x58, 0x43, 0xb8, 0xb1, 0xe6, 0x3e, 0x00, 0x9c, 0x78, 0x88, 0x56, 0xdb, 0x9c, 0xfc, 0x79, 0xf6, 0xf9, 0x41, 0x5f, 0xb7, 0xbc, 0x11, 0xf9, 0x20, 0x36, 0x1c, 0x53, 0x2b } } }, + { { { 0x5a, 0x20, 0x5b, 0xa1, 0xa5, 0x44, 0x91, 0x24, 0x02, 0x63, 0x12, 0x64, 0xb8, 0x55, 0xf6, 0xde, 0x2c, 0xdb, 0x47, 0xb8, 0xc6, 0x0a, 0xc3, 0x00, 0x78, 0x93, 0xd8, 0xf5, 0xf5, 0x18, 0x28, 0x0a } }, + { { 0xd6, 0x1b, 0x9a, 0x6c, 0xe5, 0x46, 0xea, 0x70, 0x96, 0x8d, 0x4e, 0x2a, 0x52, 0x21, 0x26, 0x4b, 0xb1, 0xbb, 0x0f, 0x7c, 0xa9, 0x9b, 0x04, 0xbb, 0x51, 0x08, 0xf1, 0x9a, 0xa4, 0x76, 0x7c, 0x18 } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0xfa, 0x94, 0xf7, 0x40, 0xd0, 0xd7, 0xeb, 0xa9, 0x82, 0x36, 0xd5, 0x15, 0xb9, 0x33, 0x7a, 0xbf, 0x8a, 0xf2, 0x63, 0xaa, 0x37, 0xf5, 0x59, 0xac, 0xbd, 0xbb, 0x32, 0x36, 0xbe, 0x73, 0x99, 0x38 } }, + { { 0x2c, 0xb3, 0xda, 0x7a, 0xd8, 0x3d, 0x99, 0xca, 0xd2, 0xf4, 0xda, 0x99, 0x8e, 0x4f, 0x98, 0xb7, 0xf4, 0xae, 0x3e, 0x9f, 0x8e, 0x35, 0x60, 0xa4, 0x33, 0x75, 0xa4, 0x04, 0x93, 0xb1, 0x6b, 0x4d } } }, + { { { 0x97, 0x9d, 0xa8, 0xcd, 0x97, 0x7b, 0x9d, 0xb9, 0xe7, 0xa5, 0xef, 0xfd, 0xa8, 0x42, 0x6b, 0xc3, 0x62, 0x64, 0x7d, 0xa5, 0x1b, 0xc9, 0x9e, 0xd2, 0x45, 0xb9, 0xee, 0x03, 0xb0, 0xbf, 0xc0, 0x68 } }, + { { 0xed, 0xb7, 0x84, 0x2c, 0xf6, 0xd3, 0xa1, 0x6b, 0x24, 0x6d, 0x87, 0x56, 0x97, 0x59, 0x79, 0x62, 0x9f, 0xac, 0xed, 0xf3, 0xc9, 0x89, 0x21, 0x2e, 0x04, 0xb3, 0xcc, 0x2f, 0xbe, 0xd6, 0x0a, 0x4b } } }, + { { { 0x39, 0x61, 0x05, 0xed, 0x25, 0x89, 0x8b, 0x5d, 0x1b, 0xcb, 0x0c, 0x55, 0xf4, 0x6a, 0x00, 0x8a, 0x46, 0xe8, 0x1e, 0xc6, 0x83, 0xc8, 0x5a, 0x76, 0xdb, 0xcc, 0x19, 0x7a, 0xcc, 0x67, 0x46, 0x0b } }, + { { 0x53, 0xcf, 0xc2, 0xa1, 0xad, 0x6a, 0xf3, 0xcd, 0x8f, 0xc9, 0xde, 0x1c, 0xf8, 0x6c, 0x8f, 0xf8, 0x76, 0x42, 0xe7, 0xfe, 0xb2, 0x72, 0x21, 0x0a, 0x66, 0x74, 0x8f, 0xb7, 0xeb, 0xe4, 0x6f, 0x01 } } }, + { { { 0x22, 0x8c, 0x6b, 0xbe, 0xfc, 0x4d, 0x70, 0x62, 0x6e, 0x52, 0x77, 0x99, 0x88, 0x7e, 0x7b, 0x57, 0x7a, 0x0d, 0xfe, 0xdc, 0x72, 0x92, 0xf1, 0x68, 0x1d, 0x97, 0xd7, 0x7c, 0x8d, 0x53, 0x10, 0x37 } }, + { { 0x53, 0x88, 0x77, 0x02, 0xca, 0x27, 0xa8, 0xe5, 0x45, 0xe2, 0xa8, 0x48, 0x2a, 0xab, 0x18, 0xca, 0xea, 0x2d, 0x2a, 0x54, 0x17, 0x37, 0x32, 0x09, 0xdc, 0xe0, 0x4a, 0xb7, 0x7d, 0x82, 0x10, 0x7d } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0x8a, 0x64, 0x1e, 0x14, 0x0a, 0x57, 0xd4, 0xda, 0x5c, 0x96, 0x9b, 0x01, 0x4c, 0x67, 0xbf, 0x8b, 0x30, 0xfe, 0x08, 0xdb, 0x0d, 0xd5, 0xa8, 0xd7, 0x09, 0x11, 0x85, 0xa2, 0xd3, 0x45, 0xfb, 0x7e } }, + { { 0xda, 0x8c, 0xc2, 0xd0, 0xac, 0x18, 0xe8, 0x52, 0x36, 0xd4, 0x21, 0xa3, 0xdd, 0x57, 0x22, 0x79, 0xb7, 0xf8, 0x71, 0x9d, 0xc6, 0x91, 0x70, 0x86, 0x56, 0xbf, 0xa1, 0x11, 0x8b, 0x19, 0xe1, 0x0f } } }, + { { { 0x18, 0x32, 0x98, 0x2c, 0x8f, 0x91, 0xae, 0x12, 0xf0, 0x8c, 0xea, 0xf3, 0x3c, 0xb9, 0x5d, 0xe4, 0x69, 0xed, 0xb2, 0x47, 0x18, 0xbd, 0xce, 0x16, 0x52, 0x5c, 0x23, 0xe2, 0xa5, 0x25, 0x52, 0x5d } }, + { { 0xb9, 0xb1, 0xe7, 0x5d, 0x4e, 0xbc, 0xee, 0xbb, 0x40, 0x81, 0x77, 0x82, 0x19, 0xab, 0xb5, 0xc6, 0xee, 0xab, 0x5b, 0x6b, 0x63, 0x92, 0x8a, 0x34, 0x8d, 0xcd, 0xee, 0x4f, 0x49, 0xe5, 0xc9, 0x7e } } }, + { { { 0x21, 0xac, 0x8b, 0x22, 0xcd, 0xc3, 0x9a, 0xe9, 0x5e, 0x78, 0xbd, 0xde, 0xba, 0xad, 0xab, 0xbf, 0x75, 0x41, 0x09, 0xc5, 0x58, 0xa4, 0x7d, 0x92, 0xb0, 0x7f, 0xf2, 0xa1, 0xd1, 0xc0, 0xb3, 0x6d } }, + { { 0x62, 0x4f, 0xd0, 0x75, 0x77, 0xba, 0x76, 0x77, 0xd7, 0xb8, 0xd8, 0x92, 0x6f, 0x98, 0x34, 0x3d, 0xd6, 0x4e, 0x1c, 0x0f, 0xf0, 0x8f, 0x2e, 0xf1, 0xb3, 0xbd, 0xb1, 0xb9, 0xec, 0x99, 0xb4, 0x07 } } }, + { { { 0x60, 0x57, 0x2e, 0x9a, 0x72, 0x1d, 0x6b, 0x6e, 0x58, 0x33, 0x24, 0x8c, 0x48, 0x39, 0x46, 0x8e, 0x89, 0x6a, 0x88, 0x51, 0x23, 0x62, 0xb5, 0x32, 0x09, 0x36, 0xe3, 0x57, 0xf5, 0x98, 0xde, 0x6f } }, + { { 0x8b, 0x2c, 0x00, 0x48, 0x4a, 0xf9, 0x5b, 0x87, 0x69, 0x52, 0xe5, 0x5b, 0xd1, 0xb1, 0xe5, 0x25, 0x25, 0xe0, 0x9c, 0xc2, 0x13, 0x44, 0xe8, 0xb9, 0x0a, 0x70, 0xad, 0xbd, 0x0f, 0x51, 0x94, 0x69 } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0xa2, 0xdc, 0xab, 0xa9, 0x25, 0x2d, 0xac, 0x5f, 0x03, 0x33, 0x08, 0xe7, 0x7e, 0xfe, 0x95, 0x36, 0x3c, 0x5b, 0x3a, 0xd3, 0x05, 0x82, 0x1c, 0x95, 0x2d, 0xd8, 0x77, 0x7e, 0x02, 0xd9, 0x5b, 0x70 } }, + { { 0xc2, 0xfe, 0x1b, 0x0c, 0x67, 0xcd, 0xd6, 0xe0, 0x51, 0x8e, 0x2c, 0xe0, 0x79, 0x88, 0xf0, 0xcf, 0x41, 0x4a, 0xad, 0x23, 0xd4, 0x46, 0xca, 0x94, 0xa1, 0xc3, 0xeb, 0x28, 0x06, 0xfa, 0x17, 0x14 } } }, + { { { 0x7b, 0xaa, 0x70, 0x0a, 0x4b, 0xfb, 0xf5, 0xbf, 0x80, 0xc5, 0xcf, 0x08, 0x7a, 0xdd, 0xa1, 0xf4, 0x9d, 0x54, 0x50, 0x53, 0x23, 0x77, 0x23, 0xf5, 0x34, 0xa5, 0x22, 0xd1, 0x0d, 0x96, 0x2e, 0x47 } }, + { { 0xcc, 0xb7, 0x32, 0x89, 0x57, 0xd0, 0x98, 0x75, 0xe4, 0x37, 0x99, 0xa9, 0xe8, 0xba, 0xed, 0xba, 0xeb, 0xc7, 0x4f, 0x15, 0x76, 0x07, 0x0c, 0x4c, 0xef, 0x9f, 0x52, 0xfc, 0x04, 0x5d, 0x58, 0x10 } } }, + { { { 0xce, 0x82, 0xf0, 0x8f, 0x79, 0x02, 0xa8, 0xd1, 0xda, 0x14, 0x09, 0x48, 0xee, 0x8a, 0x40, 0x98, 0x76, 0x60, 0x54, 0x5a, 0xde, 0x03, 0x24, 0xf5, 0xe6, 0x2f, 0xe1, 0x03, 0xbf, 0x68, 0x82, 0x7f } }, + { { 0x64, 0xe9, 0x28, 0xc7, 0xa4, 0xcf, 0x2a, 0xf9, 0x90, 0x64, 0x72, 0x2c, 0x8b, 0xeb, 0xec, 0xa0, 0xf2, 0x7d, 0x35, 0xb5, 0x90, 0x4d, 0x7f, 0x5b, 0x4a, 0x49, 0xe4, 0xb8, 0x3b, 0xc8, 0xa1, 0x2f } } }, + { { { 0x8b, 0xc5, 0xcc, 0x3d, 0x69, 0xa6, 0xa1, 0x18, 0x44, 0xbc, 0x4d, 0x77, 0x37, 0xc7, 0x86, 0xec, 0x0c, 0xc9, 0xd6, 0x44, 0xa9, 0x23, 0x27, 0xb9, 0x03, 0x34, 0xa7, 0x0a, 0xd5, 0xc7, 0x34, 0x37 } }, + { { 0xf9, 0x7e, 0x3e, 0x66, 0xee, 0xf9, 0x99, 0x28, 0xff, 0xad, 0x11, 0xd8, 0xe2, 0x66, 0xc5, 0xcd, 0x0f, 0x0d, 0x0b, 0x6a, 0xfc, 0x7c, 0x24, 0xa8, 0x4f, 0xa8, 0x5e, 0x80, 0x45, 0x8b, 0x6c, 0x41 } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0xef, 0x1e, 0xec, 0xf7, 0x8d, 0x77, 0xf2, 0xea, 0xdb, 0x60, 0x03, 0x21, 0xc0, 0xff, 0x5e, 0x67, 0xc3, 0x71, 0x0b, 0x21, 0xb4, 0x41, 0xa0, 0x68, 0x38, 0xc6, 0x01, 0xa3, 0xd3, 0x51, 0x3c, 0x3c } }, + { { 0x92, 0xf8, 0xd6, 0x4b, 0xef, 0x42, 0x13, 0xb2, 0x4a, 0xc4, 0x2e, 0x72, 0x3f, 0xc9, 0x11, 0xbd, 0x74, 0x02, 0x0e, 0xf5, 0x13, 0x9d, 0x83, 0x1a, 0x1b, 0xd5, 0x54, 0xde, 0xc4, 0x1e, 0x16, 0x6c } } }, + { { { 0x27, 0x52, 0xe4, 0x63, 0xaa, 0x94, 0xe6, 0xc3, 0x28, 0x9c, 0xc6, 0x56, 0xac, 0xfa, 0xb6, 0xbd, 0xe2, 0xcc, 0x76, 0xc6, 0x27, 0x27, 0xa2, 0x8e, 0x78, 0x2b, 0x84, 0x72, 0x10, 0xbd, 0x4e, 0x2a } }, + { { 0xea, 0xa7, 0x23, 0xef, 0x04, 0x61, 0x80, 0x50, 0xc9, 0x6e, 0xa5, 0x96, 0xd1, 0xd1, 0xc8, 0xc3, 0x18, 0xd7, 0x2d, 0xfd, 0x26, 0xbd, 0xcb, 0x7b, 0x92, 0x51, 0x0e, 0x4a, 0x65, 0x57, 0xb8, 0x49 } } }, + { { { 0xab, 0x55, 0x36, 0xc3, 0xec, 0x63, 0x55, 0x11, 0x55, 0xf6, 0xa5, 0xc7, 0x01, 0x5f, 0xfe, 0x79, 0xd8, 0x0a, 0xf7, 0x03, 0xd8, 0x98, 0x99, 0xf5, 0xd0, 0x00, 0x54, 0x6b, 0x66, 0x28, 0xf5, 0x25 } }, + { { 0x7a, 0x8d, 0xa1, 0x5d, 0x70, 0x5d, 0x51, 0x27, 0xee, 0x30, 0x65, 0x56, 0x95, 0x46, 0xde, 0xbd, 0x03, 0x75, 0xb4, 0x57, 0x59, 0x89, 0xeb, 0x02, 0x9e, 0xcc, 0x89, 0x19, 0xa7, 0xcb, 0x17, 0x67 } } }, + { { { 0x6a, 0xeb, 0xfc, 0x9a, 0x9a, 0x10, 0xce, 0xdb, 0x3a, 0x1c, 0x3c, 0x6a, 0x9d, 0xea, 0x46, 0xbc, 0x45, 0x49, 0xac, 0xe3, 0x41, 0x12, 0x7c, 0xf0, 0xf7, 0x4f, 0xf9, 0xf7, 0xff, 0x2c, 0x89, 0x04 } }, + { { 0x30, 0x31, 0x54, 0x1a, 0x46, 0xca, 0xe6, 0xc6, 0xcb, 0xe2, 0xc3, 0xc1, 0x8b, 0x75, 0x81, 0xbe, 0xee, 0xf8, 0xa3, 0x11, 0x1c, 0x25, 0xa3, 0xa7, 0x35, 0x51, 0x55, 0xe2, 0x25, 0xaa, 0xe2, 0x3a } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0xb4, 0x48, 0x10, 0x9f, 0x8a, 0x09, 0x76, 0xfa, 0xf0, 0x7a, 0xb0, 0x70, 0xf7, 0x83, 0x80, 0x52, 0x84, 0x2b, 0x26, 0xa2, 0xc4, 0x5d, 0x4f, 0xba, 0xb1, 0xc8, 0x40, 0x0d, 0x78, 0x97, 0xc4, 0x60 } }, + { { 0xd4, 0xb1, 0x6c, 0x08, 0xc7, 0x40, 0x38, 0x73, 0x5f, 0x0b, 0xf3, 0x76, 0x5d, 0xb2, 0xa5, 0x2f, 0x57, 0x57, 0x07, 0xed, 0x08, 0xa2, 0x6c, 0x4f, 0x08, 0x02, 0xb5, 0x0e, 0xee, 0x44, 0xfa, 0x22 } } }, + { { { 0x0f, 0x00, 0x3f, 0xa6, 0x04, 0x19, 0x56, 0x65, 0x31, 0x7f, 0x8b, 0xeb, 0x0d, 0xe1, 0x47, 0x89, 0x97, 0x16, 0x53, 0xfa, 0x81, 0xa7, 0xaa, 0xb2, 0xbf, 0x67, 0xeb, 0x72, 0x60, 0x81, 0x0d, 0x48 } }, + { { 0x7e, 0x13, 0x33, 0xcd, 0xa8, 0x84, 0x56, 0x1e, 0x67, 0xaf, 0x6b, 0x43, 0xac, 0x17, 0xaf, 0x16, 0xc0, 0x52, 0x99, 0x49, 0x5b, 0x87, 0x73, 0x7e, 0xb5, 0x43, 0xda, 0x6b, 0x1d, 0x0f, 0x2d, 0x55 } } }, + { { { 0xe9, 0x58, 0x1f, 0xff, 0x84, 0x3f, 0x93, 0x1c, 0xcb, 0xe1, 0x30, 0x69, 0xa5, 0x75, 0x19, 0x7e, 0x14, 0x5f, 0xf8, 0xfc, 0x09, 0xdd, 0xa8, 0x78, 0x9d, 0xca, 0x59, 0x8b, 0xd1, 0x30, 0x01, 0x13 } }, + { { 0xff, 0x76, 0x03, 0xc5, 0x4b, 0x89, 0x99, 0x70, 0x00, 0x59, 0x70, 0x9c, 0xd5, 0xd9, 0x11, 0x89, 0x5a, 0x46, 0xfe, 0xef, 0xdc, 0xd9, 0x55, 0x2b, 0x45, 0xa7, 0xb0, 0x2d, 0xfb, 0x24, 0xc2, 0x29 } } }, + { { { 0x38, 0x06, 0xf8, 0x0b, 0xac, 0x82, 0xc4, 0x97, 0x2b, 0x90, 0xe0, 0xf7, 0xa8, 0xab, 0x6c, 0x08, 0x80, 0x66, 0x90, 0x46, 0xf7, 0x26, 0x2d, 0xf8, 0xf1, 0xc4, 0x6b, 0x4a, 0x82, 0x98, 0x8e, 0x37 } }, + { { 0x8e, 0xb4, 0xee, 0xb8, 0xd4, 0x3f, 0xb2, 0x1b, 0xe0, 0x0a, 0x3d, 0x75, 0x34, 0x28, 0xa2, 0x8e, 0xc4, 0x92, 0x7b, 0xfe, 0x60, 0x6e, 0x6d, 0xb8, 0x31, 0x1d, 0x62, 0x0d, 0x78, 0x14, 0x42, 0x11 } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0x5e, 0xa8, 0xd8, 0x04, 0x9b, 0x73, 0xc9, 0xc9, 0xdc, 0x0d, 0x73, 0xbf, 0x0a, 0x0a, 0x73, 0xff, 0x18, 0x1f, 0x9c, 0x51, 0xaa, 0xc6, 0xf1, 0x83, 0x25, 0xfd, 0xab, 0xa3, 0x11, 0xd3, 0x01, 0x24 } }, + { { 0x4d, 0xe3, 0x7e, 0x38, 0x62, 0x5e, 0x64, 0xbb, 0x2b, 0x53, 0xb5, 0x03, 0x68, 0xc4, 0xf2, 0x2b, 0x5a, 0x03, 0x32, 0x99, 0x4a, 0x41, 0x9a, 0xe1, 0x1a, 0xae, 0x8c, 0x48, 0xf3, 0x24, 0x32, 0x65 } } }, + { { { 0xe8, 0xdd, 0xad, 0x3a, 0x8c, 0xea, 0xf4, 0xb3, 0xb2, 0xe5, 0x73, 0xf2, 0xed, 0x8b, 0xbf, 0xed, 0xb1, 0x0c, 0x0c, 0xfb, 0x2b, 0xf1, 0x01, 0x48, 0xe8, 0x26, 0x03, 0x8e, 0x27, 0x4d, 0x96, 0x72 } }, + { { 0xc8, 0x09, 0x3b, 0x60, 0xc9, 0x26, 0x4d, 0x7c, 0xf2, 0x9c, 0xd4, 0xa1, 0x3b, 0x26, 0xc2, 0x04, 0x33, 0x44, 0x76, 0x3c, 0x02, 0xbb, 0x11, 0x42, 0x0c, 0x22, 0xb7, 0xc6, 0xe1, 0xac, 0xb4, 0x0e } } }, + { { { 0x6f, 0x85, 0xe7, 0xef, 0xde, 0x67, 0x30, 0xfc, 0xbf, 0x5a, 0xe0, 0x7b, 0x7a, 0x2a, 0x54, 0x6b, 0x5d, 0x62, 0x85, 0xa1, 0xf8, 0x16, 0x88, 0xec, 0x61, 0xb9, 0x96, 0xb5, 0xef, 0x2d, 0x43, 0x4d } }, + { { 0x7c, 0x31, 0x33, 0xcc, 0xe4, 0xcf, 0x6c, 0xff, 0x80, 0x47, 0x77, 0xd1, 0xd8, 0xe9, 0x69, 0x97, 0x98, 0x7f, 0x20, 0x57, 0x1d, 0x1d, 0x4f, 0x08, 0x27, 0xc8, 0x35, 0x57, 0x40, 0xc6, 0x21, 0x0c } } }, + { { { 0xd2, 0x8e, 0x9b, 0xfa, 0x42, 0x8e, 0xdf, 0x8f, 0xc7, 0x86, 0xf9, 0xa4, 0xca, 0x70, 0x00, 0x9d, 0x21, 0xbf, 0xec, 0x57, 0x62, 0x30, 0x58, 0x8c, 0x0d, 0x35, 0xdb, 0x5d, 0x8b, 0x6a, 0xa0, 0x5a } }, + { { 0xc1, 0x58, 0x7c, 0x0d, 0x20, 0xdd, 0x11, 0x26, 0x5f, 0x89, 0x3b, 0x97, 0x58, 0xf8, 0x8b, 0xe3, 0xdf, 0x32, 0xe2, 0xfc, 0xd8, 0x67, 0xf2, 0xa5, 0x37, 0x1e, 0x6d, 0xec, 0x7c, 0x27, 0x20, 0x79 } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0xd0, 0xe9, 0xc0, 0xfa, 0x95, 0x45, 0x23, 0x96, 0xf1, 0x2c, 0x79, 0x25, 0x14, 0xce, 0x40, 0x14, 0x44, 0x2c, 0x36, 0x50, 0xd9, 0x63, 0x56, 0xb7, 0x56, 0x3b, 0x9e, 0xa7, 0xef, 0x89, 0xbb, 0x0e } }, + { { 0xce, 0x7f, 0xdc, 0x0a, 0xcc, 0x82, 0x1c, 0x0a, 0x78, 0x71, 0xe8, 0x74, 0x8d, 0x01, 0x30, 0x0f, 0xa7, 0x11, 0x4c, 0xdf, 0x38, 0xd7, 0xa7, 0x0d, 0xf8, 0x48, 0x52, 0x00, 0x80, 0x7b, 0x5f, 0x0e } } }, + { { { 0x25, 0x83, 0xe6, 0x94, 0x7b, 0x81, 0xb2, 0x91, 0xae, 0x0e, 0x05, 0xc9, 0xa3, 0x68, 0x2d, 0xd9, 0x88, 0x25, 0x19, 0x2a, 0x61, 0x61, 0x21, 0x97, 0x15, 0xa1, 0x35, 0xa5, 0x46, 0xc8, 0xa2, 0x0e } }, + { { 0x1b, 0x03, 0x0d, 0x8b, 0x5a, 0x1b, 0x97, 0x4b, 0xf2, 0x16, 0x31, 0x3d, 0x1f, 0x33, 0xa0, 0x50, 0x3a, 0x18, 0xbe, 0x13, 0xa1, 0x76, 0xc1, 0xba, 0x1b, 0xf1, 0x05, 0x7b, 0x33, 0xa8, 0x82, 0x3b } } }, + { { { 0xba, 0x36, 0x7b, 0x6d, 0xa9, 0xea, 0x14, 0x12, 0xc5, 0xfa, 0x91, 0x00, 0xba, 0x9b, 0x99, 0xcc, 0x56, 0x02, 0xe9, 0xa0, 0x26, 0x40, 0x66, 0x8c, 0xc4, 0xf8, 0x85, 0x33, 0x68, 0xe7, 0x03, 0x20 } }, + { { 0x50, 0x5b, 0xff, 0xa9, 0xb2, 0xf1, 0xf1, 0x78, 0xcf, 0x14, 0xa4, 0xa9, 0xfc, 0x09, 0x46, 0x94, 0x54, 0x65, 0x0d, 0x9c, 0x5f, 0x72, 0x21, 0xe2, 0x97, 0xa5, 0x2d, 0x81, 0xce, 0x4a, 0x5f, 0x79 } } }, + { { { 0x3d, 0x5f, 0x5c, 0xd2, 0xbc, 0x7d, 0x77, 0x0e, 0x2a, 0x6d, 0x22, 0x45, 0x84, 0x06, 0xc4, 0xdd, 0xc6, 0xa6, 0xc6, 0xd7, 0x49, 0xad, 0x6d, 0x87, 0x91, 0x0e, 0x3a, 0x67, 0x1d, 0x2c, 0x1d, 0x56 } }, + { { 0xfe, 0x7a, 0x74, 0xcf, 0xd4, 0xd2, 0xe5, 0x19, 0xde, 0xd0, 0xdb, 0x70, 0x23, 0x69, 0xe6, 0x6d, 0xec, 0xec, 0xcc, 0x09, 0x33, 0x6a, 0x77, 0xdc, 0x6b, 0x22, 0x76, 0x5d, 0x92, 0x09, 0xac, 0x2d } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0x23, 0x15, 0x17, 0xeb, 0xd3, 0xdb, 0x12, 0x5e, 0x01, 0xf0, 0x91, 0xab, 0x2c, 0x41, 0xce, 0xac, 0xed, 0x1b, 0x4b, 0x2d, 0xbc, 0xdb, 0x17, 0x66, 0x89, 0x46, 0xad, 0x4b, 0x1e, 0x6f, 0x0b, 0x14 } }, + { { 0x11, 0xce, 0xbf, 0xb6, 0x77, 0x2d, 0x48, 0x22, 0x18, 0x4f, 0xa3, 0x5d, 0x4a, 0xb0, 0x70, 0x12, 0x3e, 0x54, 0xd7, 0xd8, 0x0e, 0x2b, 0x27, 0xdc, 0x53, 0xff, 0xca, 0x8c, 0x59, 0xb3, 0x4e, 0x44 } } }, + { { { 0x07, 0x76, 0x61, 0x0f, 0x66, 0xb2, 0x21, 0x39, 0x7e, 0xc0, 0xec, 0x45, 0x28, 0x82, 0xa1, 0x29, 0x32, 0x44, 0x35, 0x13, 0x5e, 0x61, 0x5e, 0x54, 0xcb, 0x7c, 0xef, 0xf6, 0x41, 0xcf, 0x9f, 0x0a } }, + { { 0xdd, 0xf9, 0xda, 0x84, 0xc3, 0xe6, 0x8a, 0x9f, 0x24, 0xd2, 0x96, 0x5d, 0x39, 0x6f, 0x58, 0x8c, 0xc1, 0x56, 0x93, 0xab, 0xb5, 0x79, 0x3b, 0xd2, 0xa8, 0x73, 0x16, 0xed, 0xfa, 0xb4, 0x2f, 0x73 } } }, + { { { 0x8b, 0xb1, 0x95, 0xe5, 0x92, 0x50, 0x35, 0x11, 0x76, 0xac, 0xf4, 0x4d, 0x24, 0xc3, 0x32, 0xe6, 0xeb, 0xfe, 0x2c, 0x87, 0xc4, 0xf1, 0x56, 0xc4, 0x75, 0x24, 0x7a, 0x56, 0x85, 0x5a, 0x3a, 0x13 } }, + { { 0x0d, 0x16, 0xac, 0x3c, 0x4a, 0x58, 0x86, 0x3a, 0x46, 0x7f, 0x6c, 0xa3, 0x52, 0x6e, 0x37, 0xe4, 0x96, 0x9c, 0xe9, 0x5c, 0x66, 0x41, 0x67, 0xe4, 0xfb, 0x79, 0x0c, 0x05, 0xf6, 0x64, 0xd5, 0x7c } } }, + { { { 0x28, 0xc1, 0xe1, 0x54, 0x73, 0xf2, 0xbf, 0x76, 0x74, 0x19, 0x19, 0x1b, 0xe4, 0xb9, 0xa8, 0x46, 0x65, 0x73, 0xf3, 0x77, 0x9b, 0x29, 0x74, 0x5b, 0xc6, 0x89, 0x6c, 0x2c, 0x7c, 0xf8, 0xb3, 0x0f } }, + { { 0xf7, 0xd5, 0xe9, 0x74, 0x5d, 0xb8, 0x25, 0x16, 0xb5, 0x30, 0xbc, 0x84, 0xc5, 0xf0, 0xad, 0xca, 0x12, 0x28, 0xbc, 0x9d, 0xd4, 0xfa, 0x82, 0xe6, 0xe3, 0xbf, 0xa2, 0x15, 0x2c, 0xd4, 0x34, 0x10 } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0x61, 0xb1, 0x46, 0xba, 0x0e, 0x31, 0xa5, 0x67, 0x6c, 0x7f, 0xd6, 0xd9, 0x27, 0x85, 0x0f, 0x79, 0x14, 0xc8, 0x6c, 0x2f, 0x5f, 0x5b, 0x9c, 0x35, 0x3d, 0x38, 0x86, 0x77, 0x65, 0x55, 0x6a, 0x7b } }, + { { 0xd3, 0xb0, 0x3a, 0x66, 0x60, 0x1b, 0x43, 0xf1, 0x26, 0x58, 0x99, 0x09, 0x8f, 0x2d, 0xa3, 0x14, 0x71, 0x85, 0xdb, 0xed, 0xf6, 0x26, 0xd5, 0x61, 0x9a, 0x73, 0xac, 0x0e, 0xea, 0xac, 0xb7, 0x0c } } }, + { { { 0x5e, 0xf4, 0xe5, 0x17, 0x0e, 0x10, 0x9f, 0xe7, 0x43, 0x5f, 0x67, 0x5c, 0xac, 0x4b, 0xe5, 0x14, 0x41, 0xd2, 0xbf, 0x48, 0xf5, 0x14, 0xb0, 0x71, 0xc6, 0x61, 0xc1, 0xb2, 0x70, 0x58, 0xd2, 0x5a } }, + { { 0x2d, 0xba, 0x16, 0x07, 0x92, 0x94, 0xdc, 0xbd, 0x50, 0x2b, 0xc9, 0x7f, 0x42, 0x00, 0xba, 0x61, 0xed, 0xf8, 0x43, 0xed, 0xf5, 0xf9, 0x40, 0x60, 0xb2, 0xb0, 0x82, 0xcb, 0xed, 0x75, 0xc7, 0x65 } } }, + { { { 0x80, 0xba, 0x0d, 0x09, 0x40, 0xa7, 0x39, 0xa6, 0x67, 0x34, 0x7e, 0x66, 0xbe, 0x56, 0xfb, 0x53, 0x78, 0xc4, 0x46, 0xe8, 0xed, 0x68, 0x6c, 0x7f, 0xce, 0xe8, 0x9f, 0xce, 0xa2, 0x64, 0x58, 0x53 } }, + { { 0xe8, 0xc1, 0xa9, 0xc2, 0x7b, 0x59, 0x21, 0x33, 0xe2, 0x43, 0x73, 0x2b, 0xac, 0x2d, 0xc1, 0x89, 0x3b, 0x15, 0xe2, 0xd5, 0xc0, 0x97, 0x8a, 0xfd, 0x6f, 0x36, 0x33, 0xb7, 0xb9, 0xc3, 0x88, 0x09 } } }, + { { { 0xd0, 0xb6, 0x56, 0x30, 0x5c, 0xae, 0xb3, 0x75, 0x44, 0xa4, 0x83, 0x51, 0x6e, 0x01, 0x65, 0xef, 0x45, 0x76, 0xe6, 0xf5, 0xa2, 0x0d, 0xd4, 0x16, 0x3b, 0x58, 0x2f, 0xf2, 0x2f, 0x36, 0x18, 0x3f } }, + { { 0xfd, 0x2f, 0xe0, 0x9b, 0x1e, 0x8c, 0xc5, 0x18, 0xa9, 0xca, 0xd4, 0x2b, 0x35, 0xb6, 0x95, 0x0a, 0x9f, 0x7e, 0xfb, 0xc4, 0xef, 0x88, 0x7b, 0x23, 0x43, 0xec, 0x2f, 0x0d, 0x0f, 0x7a, 0xfc, 0x5c } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0x8d, 0xd2, 0xda, 0xc7, 0x44, 0xd6, 0x7a, 0xdb, 0x26, 0x7d, 0x1d, 0xb8, 0xe1, 0xde, 0x9d, 0x7a, 0x7d, 0x17, 0x7e, 0x1c, 0x37, 0x04, 0x8d, 0x2d, 0x7c, 0x5e, 0x18, 0x38, 0x1e, 0xaf, 0xc7, 0x1b } }, + { { 0x33, 0x48, 0x31, 0x00, 0x59, 0xf6, 0xf2, 0xca, 0x0f, 0x27, 0x1b, 0x63, 0x12, 0x7e, 0x02, 0x1d, 0x49, 0xc0, 0x5d, 0x79, 0x87, 0xef, 0x5e, 0x7a, 0x2f, 0x1f, 0x66, 0x55, 0xd8, 0x09, 0xd9, 0x61 } } }, + { { { 0x54, 0x83, 0x02, 0x18, 0x82, 0x93, 0x99, 0x07, 0xd0, 0xa7, 0xda, 0xd8, 0x75, 0x89, 0xfa, 0xf2, 0xd9, 0xa3, 0xb8, 0x6b, 0x5a, 0x35, 0x28, 0xd2, 0x6b, 0x59, 0xc2, 0xf8, 0x45, 0xe2, 0xbc, 0x06 } }, + { { 0x65, 0xc0, 0xa3, 0x88, 0x51, 0x95, 0xfc, 0x96, 0x94, 0x78, 0xe8, 0x0d, 0x8b, 0x41, 0xc9, 0xc2, 0x58, 0x48, 0x75, 0x10, 0x2f, 0xcd, 0x2a, 0xc9, 0xa0, 0x6d, 0x0f, 0xdd, 0x9c, 0x98, 0x26, 0x3d } } }, + { { { 0x2f, 0x66, 0x29, 0x1b, 0x04, 0x89, 0xbd, 0x7e, 0xee, 0x6e, 0xdd, 0xb7, 0x0e, 0xef, 0xb0, 0x0c, 0xb4, 0xfc, 0x7f, 0xc2, 0xc9, 0x3a, 0x3c, 0x64, 0xef, 0x45, 0x44, 0xaf, 0x8a, 0x90, 0x65, 0x76 } }, + { { 0xa1, 0x4c, 0x70, 0x4b, 0x0e, 0xa0, 0x83, 0x70, 0x13, 0xa4, 0xaf, 0xb8, 0x38, 0x19, 0x22, 0x65, 0x09, 0xb4, 0x02, 0x4f, 0x06, 0xf8, 0x17, 0xce, 0x46, 0x45, 0xda, 0x50, 0x7c, 0x8a, 0xd1, 0x4e } } }, + { { { 0xf7, 0xd4, 0x16, 0x6c, 0x4e, 0x95, 0x9d, 0x5d, 0x0f, 0x91, 0x2b, 0x52, 0xfe, 0x5c, 0x34, 0xe5, 0x30, 0xe6, 0xa4, 0x3b, 0xf3, 0xf3, 0x34, 0x08, 0xa9, 0x4a, 0xa0, 0xb5, 0x6e, 0xb3, 0x09, 0x0a } }, + { { 0x26, 0xd9, 0x5e, 0xa3, 0x0f, 0xeb, 0xa2, 0xf3, 0x20, 0x3b, 0x37, 0xd4, 0xe4, 0x9e, 0xce, 0x06, 0x3d, 0x53, 0xed, 0xae, 0x2b, 0xeb, 0xb6, 0x24, 0x0a, 0x11, 0xa3, 0x0f, 0xd6, 0x7f, 0xa4, 0x3a } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0xdb, 0x9f, 0x2c, 0xfc, 0xd6, 0xb2, 0x1e, 0x2e, 0x52, 0x7a, 0x06, 0x87, 0x2d, 0x86, 0x72, 0x2b, 0x6d, 0x90, 0x77, 0x46, 0x43, 0xb5, 0x7a, 0xf8, 0x60, 0x7d, 0x91, 0x60, 0x5b, 0x9d, 0x9e, 0x07 } }, + { { 0x97, 0x87, 0xc7, 0x04, 0x1c, 0x38, 0x01, 0x39, 0x58, 0xc7, 0x85, 0xa3, 0xfc, 0x64, 0x00, 0x64, 0x25, 0xa2, 0xbf, 0x50, 0x94, 0xca, 0x26, 0x31, 0x45, 0x0a, 0x24, 0xd2, 0x51, 0x29, 0x51, 0x16 } } }, + { { { 0x4d, 0x4a, 0xd7, 0x98, 0x71, 0x57, 0xac, 0x7d, 0x8b, 0x37, 0xbd, 0x63, 0xff, 0x87, 0xb1, 0x49, 0x95, 0x20, 0x7c, 0xcf, 0x7c, 0x59, 0xc4, 0x91, 0x9c, 0xef, 0xd0, 0xdb, 0x60, 0x09, 0x9d, 0x46 } }, + { { 0xcb, 0x78, 0x94, 0x90, 0xe4, 0x45, 0xb3, 0xf6, 0xd9, 0xf6, 0x57, 0x74, 0xd5, 0xf8, 0x83, 0x4f, 0x39, 0xc9, 0xbd, 0x88, 0xc2, 0x57, 0x21, 0x1f, 0x24, 0x32, 0x68, 0xf8, 0xc7, 0x21, 0x5f, 0x0b } } }, + { { { 0x2a, 0x36, 0x68, 0xfc, 0x5f, 0xb6, 0x4f, 0xa5, 0xe3, 0x9d, 0x24, 0x2f, 0xc0, 0x93, 0x61, 0xcf, 0xf8, 0x0a, 0xed, 0xe1, 0xdb, 0x27, 0xec, 0x0e, 0x14, 0x32, 0x5f, 0x8e, 0xa1, 0x62, 0x41, 0x16 } }, + { { 0x95, 0x21, 0x01, 0xce, 0x95, 0x5b, 0x0e, 0x57, 0xc7, 0xb9, 0x62, 0xb5, 0x28, 0xca, 0x11, 0xec, 0xb4, 0x46, 0x06, 0x73, 0x26, 0xff, 0xfb, 0x66, 0x7d, 0xee, 0x5f, 0xb2, 0x56, 0xfd, 0x2a, 0x08 } } }, + { { { 0x92, 0x67, 0x77, 0x56, 0xa1, 0xff, 0xc4, 0xc5, 0x95, 0xf0, 0xe3, 0x3a, 0x0a, 0xca, 0x94, 0x4d, 0x9e, 0x7e, 0x3d, 0xb9, 0x6e, 0xb6, 0xb0, 0xce, 0xa4, 0x30, 0x89, 0x99, 0xe9, 0xad, 0x11, 0x59 } }, + { { 0xf6, 0x48, 0x95, 0xa1, 0x6f, 0x5f, 0xb7, 0xa5, 0xbb, 0x30, 0x00, 0x1c, 0xd2, 0x8a, 0xd6, 0x25, 0x26, 0x1b, 0xb2, 0x0d, 0x37, 0x6a, 0x05, 0xf4, 0x9d, 0x3e, 0x17, 0x2a, 0x43, 0xd2, 0x3a, 0x06 } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0x32, 0x99, 0x93, 0xd1, 0x9a, 0x72, 0xf3, 0xa9, 0x16, 0xbd, 0xb4, 0x4c, 0xdd, 0xf9, 0xd4, 0xb2, 0x64, 0x9a, 0xd3, 0x05, 0xe4, 0xa3, 0x73, 0x1c, 0xcb, 0x7e, 0x57, 0x67, 0xff, 0x04, 0xb3, 0x10 } }, + { { 0xb9, 0x4b, 0xa4, 0xad, 0xd0, 0x6d, 0x61, 0x23, 0xb4, 0xaf, 0x34, 0xa9, 0xaa, 0x65, 0xec, 0xd9, 0x69, 0xe3, 0x85, 0xcd, 0xcc, 0xe7, 0xb0, 0x9b, 0x41, 0xc1, 0x1c, 0xf9, 0xa0, 0xfa, 0xb7, 0x13 } } }, + { { { 0x04, 0xfd, 0x88, 0x3c, 0x0c, 0xd0, 0x09, 0x52, 0x51, 0x4f, 0x06, 0x19, 0xcc, 0xc3, 0xbb, 0xde, 0x80, 0xc5, 0x33, 0xbc, 0xf9, 0xf3, 0x17, 0x36, 0xdd, 0xc6, 0xde, 0xe8, 0x9b, 0x5d, 0x79, 0x1b } }, + { { 0x65, 0x0a, 0xbe, 0x51, 0x57, 0xad, 0x50, 0x79, 0x08, 0x71, 0x9b, 0x07, 0x95, 0x8f, 0xfb, 0xae, 0x4b, 0x38, 0xba, 0xcf, 0x53, 0x2a, 0x86, 0x1e, 0xc0, 0x50, 0x5c, 0x67, 0x1b, 0xf6, 0x87, 0x6c } } }, + { { { 0x4f, 0x00, 0xb2, 0x66, 0x55, 0xed, 0x4a, 0xed, 0x8d, 0xe1, 0x66, 0x18, 0xb2, 0x14, 0x74, 0x8d, 0xfd, 0x1a, 0x36, 0x0f, 0x26, 0x5c, 0x8b, 0x89, 0xf3, 0xab, 0xf2, 0xf3, 0x24, 0x67, 0xfd, 0x70 } }, + { { 0xfd, 0x4e, 0x2a, 0xc1, 0x3a, 0xca, 0x8f, 0x00, 0xd8, 0xec, 0x74, 0x67, 0xef, 0x61, 0xe0, 0x28, 0xd0, 0x96, 0xf4, 0x48, 0xde, 0x81, 0xe3, 0xef, 0xdc, 0xaa, 0x7d, 0xf3, 0xb6, 0x55, 0xa6, 0x65 } } }, + { { { 0xeb, 0xcb, 0xc5, 0x70, 0x91, 0x31, 0x10, 0x93, 0x0d, 0xc8, 0xd0, 0xef, 0x62, 0xe8, 0x6f, 0x82, 0xe3, 0x69, 0x3d, 0x91, 0x7f, 0x31, 0xe1, 0x26, 0x35, 0x3c, 0x4a, 0x2f, 0xab, 0xc4, 0x9a, 0x5e } }, + { { 0xab, 0x1b, 0xb5, 0xe5, 0x2b, 0xc3, 0x0e, 0x29, 0xb0, 0xd0, 0x73, 0xe6, 0x4f, 0x64, 0xf2, 0xbc, 0xe4, 0xe4, 0xe1, 0x9a, 0x52, 0x33, 0x2f, 0xbd, 0xcc, 0x03, 0xee, 0x8a, 0xfa, 0x00, 0x5f, 0x50 } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0xf6, 0xdb, 0x0d, 0x22, 0x3d, 0xb5, 0x14, 0x75, 0x31, 0xf0, 0x81, 0xe2, 0xb9, 0x37, 0xa2, 0xa9, 0x84, 0x11, 0x9a, 0x07, 0xb5, 0x53, 0x89, 0x78, 0xa9, 0x30, 0x27, 0xa1, 0xf1, 0x4e, 0x5c, 0x2e } }, + { { 0x8b, 0x00, 0x54, 0xfb, 0x4d, 0xdc, 0xcb, 0x17, 0x35, 0x40, 0xff, 0xb7, 0x8c, 0xfe, 0x4a, 0xe4, 0x4e, 0x99, 0x4e, 0xa8, 0x74, 0x54, 0x5d, 0x5c, 0x96, 0xa3, 0x12, 0x55, 0x36, 0x31, 0x17, 0x5c } } }, + { { { 0xce, 0x24, 0xef, 0x7b, 0x86, 0xf2, 0x0f, 0x77, 0xe8, 0x5c, 0x7d, 0x87, 0x38, 0x2d, 0xef, 0xaf, 0xf2, 0x8c, 0x72, 0x2e, 0xeb, 0xb6, 0x55, 0x4b, 0x6e, 0xf1, 0x4e, 0x8a, 0x0e, 0x9a, 0x6c, 0x4c } }, + { { 0x25, 0xea, 0x86, 0xc2, 0xd1, 0x4f, 0xb7, 0x3e, 0xa8, 0x5c, 0x8d, 0x66, 0x81, 0x25, 0xed, 0xc5, 0x4c, 0x05, 0xb9, 0xd8, 0xd6, 0x70, 0xbe, 0x73, 0x82, 0xe8, 0xa1, 0xe5, 0x1e, 0x71, 0xd5, 0x26 } } }, + { { { 0x4e, 0x6d, 0xc3, 0xa7, 0x4f, 0x22, 0x45, 0x26, 0xa2, 0x7e, 0x16, 0xf7, 0xf7, 0x63, 0xdc, 0x86, 0x01, 0x2a, 0x71, 0x38, 0x5c, 0x33, 0xc3, 0xce, 0x30, 0xff, 0xf9, 0x2c, 0x91, 0x71, 0x8a, 0x72 } }, + { { 0x8c, 0x44, 0x09, 0x28, 0xd5, 0x23, 0xc9, 0x8f, 0xf3, 0x84, 0x45, 0xc6, 0x9a, 0x5e, 0xff, 0xd2, 0xc7, 0x57, 0x93, 0xa3, 0xc1, 0x69, 0xdd, 0x62, 0x0f, 0xda, 0x5c, 0x30, 0x59, 0x5d, 0xe9, 0x4c } } }, + { { { 0x92, 0x7e, 0x50, 0x27, 0x72, 0xd7, 0x0c, 0xd6, 0x69, 0x96, 0x81, 0x35, 0x84, 0x94, 0x35, 0x8b, 0x6c, 0xaa, 0x62, 0x86, 0x6e, 0x1c, 0x15, 0xf3, 0x6c, 0xb3, 0xff, 0x65, 0x1b, 0xa2, 0x9b, 0x59 } }, + { { 0xe2, 0xa9, 0x65, 0x88, 0xc4, 0x50, 0xfa, 0xbb, 0x3b, 0x6e, 0x5f, 0x44, 0x01, 0xca, 0x97, 0xd4, 0xdd, 0xf6, 0xcd, 0x3f, 0x3f, 0xe5, 0x97, 0x67, 0x2b, 0x8c, 0x66, 0x0f, 0x35, 0x9b, 0xf5, 0x07 } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0xf1, 0x59, 0x27, 0xd8, 0xdb, 0x5a, 0x11, 0x5e, 0x82, 0xf3, 0x38, 0xff, 0x1c, 0xed, 0xfe, 0x3f, 0x64, 0x54, 0x3f, 0x7f, 0xd1, 0x81, 0xed, 0xef, 0x65, 0xc5, 0xcb, 0xfd, 0xe1, 0x80, 0xcd, 0x11 } }, + { { 0xe0, 0xdb, 0x22, 0x28, 0xe6, 0xff, 0x61, 0x9d, 0x41, 0x14, 0x2d, 0x3b, 0x26, 0x22, 0xdf, 0xf1, 0x34, 0x81, 0xe9, 0x45, 0xee, 0x0f, 0x98, 0x8b, 0xa6, 0x3f, 0xef, 0xf7, 0x43, 0x19, 0xf1, 0x43 } } }, + { { { 0xee, 0xf3, 0x00, 0xa1, 0x50, 0xde, 0xc0, 0xb6, 0x01, 0xe3, 0x8c, 0x3c, 0x4d, 0x31, 0xd2, 0xb0, 0x58, 0xcd, 0xed, 0x10, 0x4a, 0x7a, 0xef, 0x80, 0xa9, 0x19, 0x32, 0xf3, 0xd8, 0x33, 0x8c, 0x06 } }, + { { 0xcb, 0x7d, 0x4f, 0xff, 0x30, 0xd8, 0x12, 0x3b, 0x39, 0x1c, 0x06, 0xf9, 0x4c, 0x34, 0x35, 0x71, 0xb5, 0x16, 0x94, 0x67, 0xdf, 0xee, 0x11, 0xde, 0xa4, 0x1d, 0x88, 0x93, 0x35, 0xa9, 0x32, 0x10 } } }, + { { { 0xe9, 0xc3, 0xbc, 0x7b, 0x5c, 0xfc, 0xb2, 0xf9, 0xc9, 0x2f, 0xe5, 0xba, 0x3a, 0x0b, 0xab, 0x64, 0x38, 0x6f, 0x5b, 0x4b, 0x93, 0xda, 0x64, 0xec, 0x4d, 0x3d, 0xa0, 0xf5, 0xbb, 0xba, 0x47, 0x48 } }, + { { 0x60, 0xbc, 0x45, 0x1f, 0x23, 0xa2, 0x3b, 0x70, 0x76, 0xe6, 0x97, 0x99, 0x4f, 0x77, 0x54, 0x67, 0x30, 0x9a, 0xe7, 0x66, 0xd6, 0xcd, 0x2e, 0x51, 0x24, 0x2c, 0x42, 0x4a, 0x11, 0xfe, 0x6f, 0x7e } } }, + { { { 0x87, 0xc0, 0xb1, 0xf0, 0xa3, 0x6f, 0x0c, 0x93, 0xa9, 0x0a, 0x72, 0xef, 0x5c, 0xbe, 0x65, 0x35, 0xa7, 0x6a, 0x4e, 0x2c, 0xbf, 0x21, 0x23, 0xe8, 0x2f, 0x97, 0xc7, 0x3e, 0xc8, 0x17, 0xac, 0x1e } }, + { { 0x7b, 0xef, 0x21, 0xe5, 0x40, 0xcc, 0x1e, 0xdc, 0xd6, 0xbd, 0x97, 0x7a, 0x7c, 0x75, 0x86, 0x7a, 0x25, 0x5a, 0x6e, 0x7c, 0xe5, 0x51, 0x3c, 0x1b, 0x5b, 0x82, 0x9a, 0x07, 0x60, 0xa1, 0x19, 0x04 } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0x96, 0x88, 0xa6, 0xab, 0x8f, 0xe3, 0x3a, 0x49, 0xf8, 0xfe, 0x34, 0xe7, 0x6a, 0xb2, 0xfe, 0x40, 0x26, 0x74, 0x57, 0x4c, 0xf6, 0xd4, 0x99, 0xce, 0x5d, 0x7b, 0x2f, 0x67, 0xd6, 0x5a, 0xe4, 0x4e } }, + { { 0x5c, 0x82, 0xb3, 0xbd, 0x55, 0x25, 0xf6, 0x6a, 0x93, 0xa4, 0x02, 0xc6, 0x7d, 0x5c, 0xb1, 0x2b, 0x5b, 0xff, 0xfb, 0x56, 0xf8, 0x01, 0x41, 0x90, 0xc6, 0xb6, 0xac, 0x4f, 0xfe, 0xa7, 0x41, 0x70 } } }, + { { { 0xdb, 0xfa, 0x9b, 0x2c, 0xd4, 0x23, 0x67, 0x2c, 0x8a, 0x63, 0x6c, 0x07, 0x26, 0x48, 0x4f, 0xc2, 0x03, 0xd2, 0x53, 0x20, 0x28, 0xed, 0x65, 0x71, 0x47, 0xa9, 0x16, 0x16, 0x12, 0xbc, 0x28, 0x33 } }, + { { 0x39, 0xc0, 0xfa, 0xfa, 0xcd, 0x33, 0x43, 0xc7, 0x97, 0x76, 0x9b, 0x93, 0x91, 0x72, 0xeb, 0xc5, 0x18, 0x67, 0x4c, 0x11, 0xf0, 0xf4, 0xe5, 0x73, 0xb2, 0x5c, 0x1b, 0xc2, 0x26, 0x3f, 0xbf, 0x2b } } }, + { { { 0x86, 0xe6, 0x8c, 0x1d, 0xdf, 0xca, 0xfc, 0xd5, 0xf8, 0x3a, 0xc3, 0x44, 0x72, 0xe6, 0x78, 0x9d, 0x2b, 0x97, 0xf8, 0x28, 0x45, 0xb4, 0x20, 0xc9, 0x2a, 0x8c, 0x67, 0xaa, 0x11, 0xc5, 0x5b, 0x2f } }, + { { 0x17, 0x0f, 0x86, 0x52, 0xd7, 0x9d, 0xc3, 0x44, 0x51, 0x76, 0x32, 0x65, 0xb4, 0x37, 0x81, 0x99, 0x46, 0x37, 0x62, 0xed, 0xcf, 0x64, 0x9d, 0x72, 0x40, 0x7a, 0x4c, 0x0b, 0x76, 0x2a, 0xfb, 0x56 } } }, + { { { 0x33, 0xa7, 0x90, 0x7c, 0xc3, 0x6f, 0x17, 0xa5, 0xa0, 0x67, 0x72, 0x17, 0xea, 0x7e, 0x63, 0x14, 0x83, 0xde, 0xc1, 0x71, 0x2d, 0x41, 0x32, 0x7a, 0xf3, 0xd1, 0x2b, 0xd8, 0x2a, 0xa6, 0x46, 0x36 } }, + { { 0xac, 0xcc, 0x6b, 0x7c, 0xf9, 0xb8, 0x8b, 0x08, 0x5c, 0xd0, 0x7d, 0x8f, 0x73, 0xea, 0x20, 0xda, 0x86, 0xca, 0x00, 0xc7, 0xad, 0x73, 0x4d, 0xe9, 0xe8, 0xa9, 0xda, 0x1f, 0x03, 0x06, 0xdd, 0x24 } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0x9c, 0xb2, 0x61, 0x0a, 0x98, 0x2a, 0xa5, 0xd7, 0xee, 0xa9, 0xac, 0x65, 0xcb, 0x0a, 0x1e, 0xe2, 0xbe, 0xdc, 0x85, 0x59, 0x0f, 0x9c, 0xa6, 0x57, 0x34, 0xa5, 0x87, 0xeb, 0x7b, 0x1e, 0x0c, 0x3c } }, + { { 0x2f, 0xbd, 0x84, 0x63, 0x0d, 0xb5, 0xa0, 0xf0, 0x4b, 0x9e, 0x93, 0xc6, 0x34, 0x9a, 0x34, 0xff, 0x73, 0x19, 0x2f, 0x6e, 0x54, 0x45, 0x2c, 0x92, 0x31, 0x76, 0x34, 0xf1, 0xb2, 0x26, 0xe8, 0x74 } } }, + { { { 0x0a, 0x67, 0x90, 0x6d, 0x0c, 0x4c, 0xcc, 0xc0, 0xe6, 0xbd, 0xa7, 0x5e, 0x55, 0x8c, 0xcd, 0x58, 0x9b, 0x11, 0xa2, 0xbb, 0x4b, 0xb1, 0x43, 0x04, 0x3c, 0x55, 0xed, 0x23, 0xfe, 0xcd, 0xb1, 0x53 } }, + { { 0x05, 0xfb, 0x75, 0xf5, 0x01, 0xaf, 0x38, 0x72, 0x58, 0xfc, 0x04, 0x29, 0x34, 0x7a, 0x67, 0xa2, 0x08, 0x50, 0x6e, 0xd0, 0x2b, 0x73, 0xd5, 0xb8, 0xe4, 0x30, 0x96, 0xad, 0x45, 0xdf, 0xa6, 0x5c } } }, + { { { 0x0d, 0x88, 0x1a, 0x90, 0x7e, 0xdc, 0xd8, 0xfe, 0xc1, 0x2f, 0x5d, 0x67, 0xee, 0x67, 0x2f, 0xed, 0x6f, 0x55, 0x43, 0x5f, 0x87, 0x14, 0x35, 0x42, 0xd3, 0x75, 0xae, 0xd5, 0xd3, 0x85, 0x1a, 0x76 } }, + { { 0x87, 0xc8, 0xa0, 0x6e, 0xe1, 0xb0, 0xad, 0x6a, 0x4a, 0x34, 0x71, 0xed, 0x7c, 0xd6, 0x44, 0x03, 0x65, 0x4a, 0x5c, 0x5c, 0x04, 0xf5, 0x24, 0x3f, 0xb0, 0x16, 0x5e, 0x8c, 0xb2, 0xd2, 0xc5, 0x20 } } }, + { { { 0x98, 0x83, 0xc2, 0x37, 0xa0, 0x41, 0xa8, 0x48, 0x5c, 0x5f, 0xbf, 0xc8, 0xfa, 0x24, 0xe0, 0x59, 0x2c, 0xbd, 0xf6, 0x81, 0x7e, 0x88, 0xe6, 0xca, 0x04, 0xd8, 0x5d, 0x60, 0xbb, 0x74, 0xa7, 0x0b } }, + { { 0x21, 0x13, 0x91, 0xbf, 0x77, 0x7a, 0x33, 0xbc, 0xe9, 0x07, 0x39, 0x0a, 0xdd, 0x7d, 0x06, 0x10, 0x9a, 0xee, 0x47, 0x73, 0x1b, 0x15, 0x5a, 0xfb, 0xcd, 0x4d, 0xd0, 0xd2, 0x3a, 0x01, 0xba, 0x54 } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0x48, 0xd5, 0x39, 0x4a, 0x0b, 0x20, 0x6a, 0x43, 0xa0, 0x07, 0x82, 0x5e, 0x49, 0x7c, 0xc9, 0x47, 0xf1, 0x7c, 0x37, 0xb9, 0x23, 0xef, 0x6b, 0x46, 0x45, 0x8c, 0x45, 0x76, 0xdf, 0x14, 0x6b, 0x6e } }, + { { 0x42, 0xc9, 0xca, 0x29, 0x4c, 0x76, 0x37, 0xda, 0x8a, 0x2d, 0x7c, 0x3a, 0x58, 0xf2, 0x03, 0xb4, 0xb5, 0xb9, 0x1a, 0x13, 0x2d, 0xde, 0x5f, 0x6b, 0x9d, 0xba, 0x52, 0xc9, 0x5d, 0xb3, 0xf3, 0x30 } } }, + { { { 0x4c, 0x6f, 0xfe, 0x6b, 0x0c, 0x62, 0xd7, 0x48, 0x71, 0xef, 0xb1, 0x85, 0x79, 0xc0, 0xed, 0x24, 0xb1, 0x08, 0x93, 0x76, 0x8e, 0xf7, 0x38, 0x8e, 0xeb, 0xfe, 0x80, 0x40, 0xaf, 0x90, 0x64, 0x49 } }, + { { 0x4a, 0x88, 0xda, 0xc1, 0x98, 0x44, 0x3c, 0x53, 0x4e, 0xdb, 0x4b, 0xb9, 0x12, 0x5f, 0xcd, 0x08, 0x04, 0xef, 0x75, 0xe7, 0xb1, 0x3a, 0xe5, 0x07, 0xfa, 0xca, 0x65, 0x7b, 0x72, 0x10, 0x64, 0x7f } } }, + { { { 0x3d, 0x81, 0xf0, 0xeb, 0x16, 0xfd, 0x58, 0x33, 0x8d, 0x7c, 0x1a, 0xfb, 0x20, 0x2c, 0x8a, 0xee, 0x90, 0xbb, 0x33, 0x6d, 0x45, 0xe9, 0x8e, 0x99, 0x85, 0xe1, 0x08, 0x1f, 0xc5, 0xf1, 0xb5, 0x46 } }, + { { 0xe4, 0xe7, 0x43, 0x4b, 0xa0, 0x3f, 0x2b, 0x06, 0xba, 0x17, 0xae, 0x3d, 0xe6, 0xce, 0xbd, 0xb8, 0xed, 0x74, 0x11, 0x35, 0xec, 0x96, 0xfe, 0x31, 0xe3, 0x0e, 0x7a, 0x4e, 0xc9, 0x1d, 0xcb, 0x20 } } }, + { { { 0xe0, 0x67, 0xe9, 0x7b, 0xdb, 0x96, 0x5c, 0xb0, 0x32, 0xd0, 0x59, 0x31, 0x90, 0xdc, 0x92, 0x97, 0xac, 0x09, 0x38, 0x31, 0x0f, 0x7e, 0xd6, 0x5d, 0xd0, 0x06, 0xb6, 0x1f, 0xea, 0xf0, 0x5b, 0x07 } }, + { { 0x81, 0x9f, 0xc7, 0xde, 0x6b, 0x41, 0x22, 0x35, 0x14, 0x67, 0x77, 0x3e, 0x90, 0x81, 0xb0, 0xd9, 0x85, 0x4c, 0xca, 0x9b, 0x3f, 0x04, 0x59, 0xd6, 0xaa, 0x17, 0xc3, 0x88, 0x34, 0x37, 0xba, 0x43 } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0x4c, 0xb6, 0x69, 0xc8, 0x81, 0x95, 0x94, 0x33, 0x92, 0x34, 0xe9, 0x3c, 0x84, 0x0d, 0x3d, 0x5a, 0x37, 0x9c, 0x22, 0xa0, 0xaa, 0x65, 0xce, 0xb4, 0xc2, 0x2d, 0x66, 0x67, 0x02, 0xff, 0x74, 0x10 } }, + { { 0x22, 0xb0, 0xd5, 0xe6, 0xc7, 0xef, 0xb1, 0xa7, 0x13, 0xda, 0x60, 0xb4, 0x80, 0xc1, 0x42, 0x7d, 0x10, 0x70, 0x97, 0x04, 0x4d, 0xda, 0x23, 0x89, 0xc2, 0x0e, 0x68, 0xcb, 0xde, 0xe0, 0x9b, 0x29 } } }, + { { { 0x33, 0xfe, 0x42, 0x2a, 0x36, 0x2b, 0x2e, 0x36, 0x64, 0x5c, 0x8b, 0xcc, 0x81, 0x6a, 0x15, 0x08, 0xa1, 0x27, 0xe8, 0x57, 0xe5, 0x78, 0x8e, 0xf2, 0x58, 0x19, 0x12, 0x42, 0xae, 0xc4, 0x63, 0x3e } }, + { { 0x78, 0x96, 0x9c, 0xa7, 0xca, 0x80, 0xae, 0x02, 0x85, 0xb1, 0x7c, 0x04, 0x5c, 0xc1, 0x5b, 0x26, 0xc1, 0xba, 0xed, 0xa5, 0x59, 0x70, 0x85, 0x8c, 0x8c, 0xe8, 0x87, 0xac, 0x6a, 0x28, 0x99, 0x35 } } }, + { { { 0x9f, 0x04, 0x08, 0x28, 0xbe, 0x87, 0xda, 0x80, 0x28, 0x38, 0xde, 0x9f, 0xcd, 0xe4, 0xe3, 0x62, 0xfb, 0x2e, 0x46, 0x8d, 0x01, 0xb3, 0x06, 0x51, 0xd4, 0x19, 0x3b, 0x11, 0xfa, 0xe2, 0xad, 0x1e } }, + { { 0xa0, 0x20, 0x99, 0x69, 0x0a, 0xae, 0xa3, 0x70, 0x4e, 0x64, 0x80, 0xb7, 0x85, 0x9c, 0x87, 0x54, 0x43, 0x43, 0x55, 0x80, 0x6d, 0x8d, 0x7c, 0xa9, 0x64, 0xca, 0x6c, 0x2e, 0x21, 0xd8, 0xc8, 0x6c } } }, + { { { 0x91, 0x4a, 0x07, 0xad, 0x08, 0x75, 0xc1, 0x4f, 0xa4, 0xb2, 0xc3, 0x6f, 0x46, 0x3e, 0xb1, 0xce, 0x52, 0xab, 0x67, 0x09, 0x54, 0x48, 0x6b, 0x6c, 0xd7, 0x1d, 0x71, 0x76, 0xcb, 0xff, 0xdd, 0x31 } }, + { { 0x36, 0x88, 0xfa, 0xfd, 0xf0, 0x36, 0x6f, 0x07, 0x74, 0x88, 0x50, 0xd0, 0x95, 0x38, 0x4a, 0x48, 0x2e, 0x07, 0x64, 0x97, 0x11, 0x76, 0x01, 0x1a, 0x27, 0x4d, 0x8e, 0x25, 0x9a, 0x9b, 0x1c, 0x22 } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0xbe, 0x57, 0xbd, 0x0e, 0x0f, 0xac, 0x5e, 0x76, 0xa3, 0x71, 0xad, 0x2b, 0x10, 0x45, 0x02, 0xec, 0x59, 0xd5, 0x5d, 0xa9, 0x44, 0xcc, 0x25, 0x4c, 0xb3, 0x3c, 0x5b, 0x69, 0x07, 0x55, 0x26, 0x6b } }, + { { 0x30, 0x6b, 0xd4, 0xa7, 0x51, 0x29, 0xe3, 0xf9, 0x7a, 0x75, 0x2a, 0x82, 0x2f, 0xd6, 0x1d, 0x99, 0x2b, 0x80, 0xd5, 0x67, 0x1e, 0x15, 0x9d, 0xca, 0xfd, 0xeb, 0xac, 0x97, 0x35, 0x09, 0x7f, 0x3f } } }, + { { { 0x35, 0x0d, 0x34, 0x0a, 0xb8, 0x67, 0x56, 0x29, 0x20, 0xf3, 0x19, 0x5f, 0xe2, 0x83, 0x42, 0x73, 0x53, 0xa8, 0xc5, 0x02, 0x19, 0x33, 0xb4, 0x64, 0xbd, 0xc3, 0x87, 0x8c, 0xd7, 0x76, 0xed, 0x25 } }, + { { 0x47, 0x39, 0x37, 0x76, 0x0d, 0x1d, 0x0c, 0xf5, 0x5a, 0x6d, 0x43, 0x88, 0x99, 0x15, 0xb4, 0x52, 0x0f, 0x2a, 0xb3, 0xb0, 0x3f, 0xa6, 0xb3, 0x26, 0xb3, 0xc7, 0x45, 0xf5, 0x92, 0x5f, 0x9b, 0x17 } } }, + { { { 0x9d, 0x23, 0xbd, 0x15, 0xfe, 0x52, 0x52, 0x15, 0x26, 0x79, 0x86, 0xba, 0x06, 0x56, 0x66, 0xbb, 0x8c, 0x2e, 0x10, 0x11, 0xd5, 0x4a, 0x18, 0x52, 0xda, 0x84, 0x44, 0xf0, 0x3e, 0xe9, 0x8c, 0x35 } }, + { { 0xad, 0xa0, 0x41, 0xec, 0xc8, 0x4d, 0xb9, 0xd2, 0x6e, 0x96, 0x4e, 0x5b, 0xc5, 0xc2, 0xa0, 0x1b, 0xcf, 0x0c, 0xbf, 0x17, 0x66, 0x57, 0xc1, 0x17, 0x90, 0x45, 0x71, 0xc2, 0xe1, 0x24, 0xeb, 0x27 } } }, + { { { 0x2c, 0xb9, 0x42, 0xa4, 0xaf, 0x3b, 0x42, 0x0e, 0xc2, 0x0f, 0xf2, 0xea, 0x83, 0xaf, 0x9a, 0x13, 0x17, 0xb0, 0xbd, 0x89, 0x17, 0xe3, 0x72, 0xcb, 0x0e, 0x76, 0x7e, 0x41, 0x63, 0x04, 0x88, 0x71 } }, + { { 0x75, 0x78, 0x38, 0x86, 0x57, 0xdd, 0x9f, 0xee, 0x54, 0x70, 0x65, 0xbf, 0xf1, 0x2c, 0xe0, 0x39, 0x0d, 0xe3, 0x89, 0xfd, 0x8e, 0x93, 0x4f, 0x43, 0xdc, 0xd5, 0x5b, 0xde, 0xf9, 0x98, 0xe5, 0x7b } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0xe7, 0x3b, 0x65, 0x11, 0xdf, 0xb2, 0xf2, 0x63, 0x94, 0x12, 0x6f, 0x5c, 0x9e, 0x77, 0xc1, 0xb6, 0xd8, 0xab, 0x58, 0x7a, 0x1d, 0x95, 0x73, 0xdd, 0xe7, 0xe3, 0x6f, 0xf2, 0x03, 0x1d, 0xdb, 0x76 } }, + { { 0xae, 0x06, 0x4e, 0x2c, 0x52, 0x1b, 0xbc, 0x5a, 0x5a, 0xa5, 0xbe, 0x27, 0xbd, 0xeb, 0xe1, 0x14, 0x17, 0x68, 0x26, 0x07, 0x03, 0xd1, 0x18, 0x0b, 0xdf, 0xf1, 0x06, 0x5c, 0xa6, 0x1b, 0xb9, 0x24 } } }, + { { { 0xc5, 0x66, 0x80, 0x13, 0x0e, 0x48, 0x8c, 0x87, 0x31, 0x84, 0xb4, 0x60, 0xed, 0xc5, 0xec, 0xb6, 0xc5, 0x05, 0x33, 0x5f, 0x2f, 0x7d, 0x40, 0xb6, 0x32, 0x1d, 0x38, 0x74, 0x1b, 0xf1, 0x09, 0x3d } }, + { { 0xd4, 0x69, 0x82, 0xbc, 0x8d, 0xf8, 0x34, 0x36, 0x75, 0x55, 0x18, 0x55, 0x58, 0x3c, 0x79, 0xaf, 0x26, 0x80, 0xab, 0x9b, 0x95, 0x00, 0xf1, 0xcb, 0xda, 0xc1, 0x9f, 0xf6, 0x2f, 0xa2, 0xf4, 0x45 } } }, + { { { 0x17, 0xbe, 0xeb, 0x85, 0xed, 0x9e, 0xcd, 0x56, 0xf5, 0x17, 0x45, 0x42, 0xb4, 0x1f, 0x44, 0x4c, 0x05, 0x74, 0x15, 0x47, 0x00, 0xc6, 0x6a, 0x3d, 0x24, 0x09, 0x0d, 0x58, 0xb1, 0x42, 0xd7, 0x04 } }, + { { 0x8d, 0xbd, 0xa3, 0xc4, 0x06, 0x9b, 0x1f, 0x90, 0x58, 0x60, 0x74, 0xb2, 0x00, 0x3b, 0x3c, 0xd2, 0xda, 0x82, 0xbb, 0x10, 0x90, 0x69, 0x92, 0xa9, 0xb4, 0x30, 0x81, 0xe3, 0x7c, 0xa8, 0x89, 0x45 } } }, + { { { 0x3f, 0xdc, 0x05, 0xcb, 0x41, 0x3c, 0xc8, 0x23, 0x04, 0x2c, 0x38, 0x99, 0xe3, 0x68, 0x55, 0xf9, 0xd3, 0x32, 0xc7, 0xbf, 0xfa, 0xd4, 0x1b, 0x5d, 0xde, 0xdc, 0x10, 0x42, 0xc0, 0x42, 0xd9, 0x75 } }, + { { 0x2d, 0xab, 0x35, 0x4e, 0x87, 0xc4, 0x65, 0x97, 0x67, 0x24, 0xa4, 0x47, 0xad, 0x3f, 0x8e, 0xf3, 0xcb, 0x31, 0x17, 0x77, 0xc5, 0xe2, 0xd7, 0x8f, 0x3c, 0xc1, 0xcd, 0x56, 0x48, 0xc1, 0x6c, 0x69 } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0x14, 0xae, 0x5f, 0x88, 0x7b, 0xa5, 0x90, 0xdf, 0x10, 0xb2, 0x8b, 0x5e, 0x24, 0x17, 0xc3, 0xa3, 0xd4, 0x0f, 0x92, 0x61, 0x1a, 0x19, 0x5a, 0xad, 0x76, 0xbd, 0xd8, 0x1c, 0xdd, 0xe0, 0x12, 0x6d } }, + { { 0x8e, 0xbd, 0x70, 0x8f, 0x02, 0xa3, 0x24, 0x4d, 0x5a, 0x67, 0xc4, 0xda, 0xf7, 0x20, 0x0f, 0x81, 0x5b, 0x7a, 0x05, 0x24, 0x67, 0x83, 0x0b, 0x2a, 0x80, 0xe7, 0xfd, 0x74, 0x4b, 0x9e, 0x5c, 0x0d } } }, + { { { 0x94, 0xd5, 0x5f, 0x1f, 0xa2, 0xfb, 0xeb, 0xe1, 0x07, 0x34, 0xf8, 0x20, 0xad, 0x81, 0x30, 0x06, 0x2d, 0xa1, 0x81, 0x95, 0x36, 0xcf, 0x11, 0x0b, 0xaf, 0xc1, 0x2b, 0x9a, 0x6c, 0x55, 0xc1, 0x16 } }, + { { 0x36, 0x4f, 0xf1, 0x5e, 0x74, 0x35, 0x13, 0x28, 0xd7, 0x11, 0xcf, 0xb8, 0xde, 0x93, 0xb3, 0x05, 0xb8, 0xb5, 0x73, 0xe9, 0xeb, 0xad, 0x19, 0x1e, 0x89, 0x0f, 0x8b, 0x15, 0xd5, 0x8c, 0xe3, 0x23 } } }, + { { { 0x33, 0x79, 0xe7, 0x18, 0xe6, 0x0f, 0x57, 0x93, 0x15, 0xa0, 0xa7, 0xaa, 0xc4, 0xbf, 0x4f, 0x30, 0x74, 0x95, 0x5e, 0x69, 0x4a, 0x5b, 0x45, 0xe4, 0x00, 0xeb, 0x23, 0x74, 0x4c, 0xdf, 0x6b, 0x45 } }, + { { 0x97, 0x29, 0x6c, 0xc4, 0x42, 0x0b, 0xdd, 0xc0, 0x29, 0x5c, 0x9b, 0x34, 0x97, 0xd0, 0xc7, 0x79, 0x80, 0x63, 0x74, 0xe4, 0x8e, 0x37, 0xb0, 0x2b, 0x7c, 0xe8, 0x68, 0x6c, 0xc3, 0x82, 0x97, 0x57 } } }, + { { { 0x22, 0xbe, 0x83, 0xb6, 0x4b, 0x80, 0x6b, 0x43, 0x24, 0x5e, 0xef, 0x99, 0x9b, 0xa8, 0xfc, 0x25, 0x8d, 0x3b, 0x03, 0x94, 0x2b, 0x3e, 0xe7, 0x95, 0x76, 0x9b, 0xcc, 0x15, 0xdb, 0x32, 0xe6, 0x66 } }, + { { 0x84, 0xf0, 0x4a, 0x13, 0xa6, 0xd6, 0xfa, 0x93, 0x46, 0x07, 0xf6, 0x7e, 0x5c, 0x6d, 0x5e, 0xf6, 0xa6, 0xe7, 0x48, 0xf0, 0x06, 0xea, 0xff, 0x90, 0xc1, 0xcc, 0x4c, 0x19, 0x9c, 0x3c, 0x4e, 0x53 } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0x2a, 0x50, 0xe3, 0x07, 0x15, 0x59, 0xf2, 0x8b, 0x81, 0xf2, 0xf3, 0xd3, 0x6c, 0x99, 0x8c, 0x70, 0x67, 0xec, 0xcc, 0xee, 0x9e, 0x59, 0x45, 0x59, 0x7d, 0x47, 0x75, 0x69, 0xf5, 0x24, 0x93, 0x5d } }, + { { 0x6a, 0x4f, 0x1b, 0xbe, 0x6b, 0x30, 0xcf, 0x75, 0x46, 0xe3, 0x7b, 0x9d, 0xfc, 0xcd, 0xd8, 0x5c, 0x1f, 0xb4, 0xc8, 0xe2, 0x24, 0xec, 0x1a, 0x28, 0x05, 0x32, 0x57, 0xfd, 0x3c, 0x5a, 0x98, 0x10 } } }, + { { { 0xa3, 0xdb, 0xf7, 0x30, 0xd8, 0xc2, 0x9a, 0xe1, 0xd3, 0xce, 0x22, 0xe5, 0x80, 0x1e, 0xd9, 0xe4, 0x1f, 0xab, 0xc0, 0x71, 0x1a, 0x86, 0x0e, 0x27, 0x99, 0x5b, 0xfa, 0x76, 0x99, 0xb0, 0x08, 0x3c } }, + { { 0x2a, 0x93, 0xd2, 0x85, 0x1b, 0x6a, 0x5d, 0xa6, 0xee, 0xd1, 0xd1, 0x33, 0xbd, 0x6a, 0x36, 0x73, 0x37, 0x3a, 0x44, 0xb4, 0xec, 0xa9, 0x7a, 0xde, 0x83, 0x40, 0xd7, 0xdf, 0x28, 0xba, 0xa2, 0x30 } } }, + { { { 0xd3, 0xb5, 0x6d, 0x05, 0x3f, 0x9f, 0xf3, 0x15, 0x8d, 0x7c, 0xca, 0xc9, 0xfc, 0x8a, 0x7c, 0x94, 0xb0, 0x63, 0x36, 0x9b, 0x78, 0xd1, 0x91, 0x1f, 0x93, 0xd8, 0x57, 0x43, 0xde, 0x76, 0xa3, 0x43 } }, + { { 0x9b, 0x35, 0xe2, 0xa9, 0x3d, 0x32, 0x1e, 0xbb, 0x16, 0x28, 0x70, 0xe9, 0x45, 0x2f, 0x8f, 0x70, 0x7f, 0x08, 0x7e, 0x53, 0xc4, 0x7a, 0xbf, 0xf7, 0xe1, 0xa4, 0x6a, 0xd8, 0xac, 0x64, 0x1b, 0x11 } } }, + { { { 0xb2, 0xeb, 0x47, 0x46, 0x18, 0x3e, 0x1f, 0x99, 0x0c, 0xcc, 0xf1, 0x2c, 0xe0, 0xe7, 0x8f, 0xe0, 0x01, 0x7e, 0x65, 0xb8, 0x0c, 0xd0, 0xfb, 0xc8, 0xb9, 0x90, 0x98, 0x33, 0x61, 0x3b, 0xd8, 0x27 } }, + { { 0xa0, 0xbe, 0x72, 0x3a, 0x50, 0x4b, 0x74, 0xab, 0x01, 0xc8, 0x93, 0xc5, 0xe4, 0xc7, 0x08, 0x6c, 0xb4, 0xca, 0xee, 0xeb, 0x8e, 0xd7, 0x4e, 0x26, 0xc6, 0x1d, 0xe2, 0x71, 0xaf, 0x89, 0xa0, 0x2a } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0x98, 0x0b, 0xe4, 0xde, 0xdb, 0xa8, 0xfa, 0x82, 0x74, 0x06, 0x52, 0x6d, 0x08, 0x52, 0x8a, 0xff, 0x62, 0xc5, 0x6a, 0x44, 0x0f, 0x51, 0x8c, 0x1f, 0x6e, 0xb6, 0xc6, 0x2c, 0x81, 0xd3, 0x76, 0x46 } }, + { { 0xf4, 0x29, 0x74, 0x2e, 0x80, 0xa7, 0x1a, 0x8f, 0xf6, 0xbd, 0xd6, 0x8e, 0xbf, 0xc1, 0x95, 0x2a, 0xeb, 0xa0, 0x7f, 0x45, 0xa0, 0x50, 0x14, 0x05, 0xb1, 0x57, 0x4c, 0x74, 0xb7, 0xe2, 0x89, 0x7d } } }, + { { { 0x07, 0xee, 0xa7, 0xad, 0xb7, 0x09, 0x0b, 0x49, 0x4e, 0xbf, 0xca, 0xe5, 0x21, 0xe6, 0xe6, 0xaf, 0xd5, 0x67, 0xf3, 0xce, 0x7e, 0x7c, 0x93, 0x7b, 0x5a, 0x10, 0x12, 0x0e, 0x6c, 0x06, 0x11, 0x75 } }, + { { 0xd5, 0xfc, 0x86, 0xa3, 0x3b, 0xa3, 0x3e, 0x0a, 0xfb, 0x0b, 0xf7, 0x36, 0xb1, 0x5b, 0xda, 0x70, 0xb7, 0x00, 0xa7, 0xda, 0x88, 0x8f, 0x84, 0xa8, 0xbc, 0x1c, 0x39, 0xb8, 0x65, 0xf3, 0x4d, 0x60 } } }, + { { { 0x96, 0x9d, 0x31, 0xf4, 0xa2, 0xbe, 0x81, 0xb9, 0xa5, 0x59, 0x9e, 0xba, 0x07, 0xbe, 0x74, 0x58, 0xd8, 0xeb, 0xc5, 0x9f, 0x3d, 0xd1, 0xf4, 0xae, 0xce, 0x53, 0xdf, 0x4f, 0xc7, 0x2a, 0x89, 0x4d } }, + { { 0x29, 0xd8, 0xf2, 0xaa, 0xe9, 0x0e, 0xf7, 0x2e, 0x5f, 0x9d, 0x8a, 0x5b, 0x09, 0xed, 0xc9, 0x24, 0x22, 0xf4, 0x0f, 0x25, 0x8f, 0x1c, 0x84, 0x6e, 0x34, 0x14, 0x6c, 0xea, 0xb3, 0x86, 0x5d, 0x04 } } }, + { { { 0x07, 0x98, 0x61, 0xe8, 0x6a, 0xd2, 0x81, 0x49, 0x25, 0xd5, 0x5b, 0x18, 0xc7, 0x35, 0x52, 0x51, 0xa4, 0x46, 0xad, 0x18, 0x0d, 0xc9, 0x5f, 0x18, 0x91, 0x3b, 0xb4, 0xc0, 0x60, 0x59, 0x8d, 0x66 } }, + { { 0x03, 0x1b, 0x79, 0x53, 0x6e, 0x24, 0xae, 0x57, 0xd9, 0x58, 0x09, 0x85, 0x48, 0xa2, 0xd3, 0xb5, 0xe2, 0x4d, 0x11, 0x82, 0xe6, 0x86, 0x3c, 0xe9, 0xb1, 0x00, 0x19, 0xc2, 0x57, 0xf7, 0x66, 0x7a } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0x0f, 0xe3, 0x89, 0x03, 0xd7, 0x22, 0x95, 0x9f, 0xca, 0xb4, 0x8d, 0x9e, 0x6d, 0x97, 0xff, 0x8d, 0x21, 0x59, 0x07, 0xef, 0x03, 0x2d, 0x5e, 0xf8, 0x44, 0x46, 0xe7, 0x85, 0x80, 0xc5, 0x89, 0x50 } }, + { { 0x8b, 0xd8, 0x53, 0x86, 0x24, 0x86, 0x29, 0x52, 0x01, 0xfa, 0x20, 0xc3, 0x4e, 0x95, 0xcb, 0xad, 0x7b, 0x34, 0x94, 0x30, 0xb7, 0x7a, 0xfa, 0x96, 0x41, 0x60, 0x2b, 0xcb, 0x59, 0xb9, 0xca, 0x50 } } }, + { { { 0xc2, 0x5b, 0x9b, 0x78, 0x23, 0x1b, 0x3a, 0x88, 0x94, 0x5f, 0x0a, 0x9b, 0x98, 0x2b, 0x6e, 0x53, 0x11, 0xf6, 0xff, 0xc6, 0x7d, 0x42, 0xcc, 0x02, 0x80, 0x40, 0x0d, 0x1e, 0xfb, 0xaf, 0x61, 0x07 } }, + { { 0xb0, 0xe6, 0x2f, 0x81, 0x70, 0xa1, 0x2e, 0x39, 0x04, 0x7c, 0xc4, 0x2c, 0x87, 0x45, 0x4a, 0x5b, 0x69, 0x97, 0xac, 0x6d, 0x2c, 0x10, 0x42, 0x7c, 0x3b, 0x15, 0x70, 0x60, 0x0e, 0x11, 0x6d, 0x3a } } }, + { { { 0x9b, 0x18, 0x80, 0x5e, 0xdb, 0x05, 0xbd, 0xc6, 0xb7, 0x3c, 0xc2, 0x40, 0x4d, 0x5d, 0xce, 0x97, 0x8a, 0x34, 0x15, 0xab, 0x28, 0x5d, 0x10, 0xf0, 0x37, 0x0c, 0xcc, 0x16, 0xfa, 0x1f, 0x33, 0x0d } }, + { { 0x19, 0xf9, 0x35, 0xaa, 0x59, 0x1a, 0x0c, 0x5c, 0x06, 0xfc, 0x6a, 0x0b, 0x97, 0x53, 0x36, 0xfc, 0x2a, 0xa5, 0x5a, 0x9b, 0x30, 0xef, 0x23, 0xaf, 0x39, 0x5d, 0x9a, 0x6b, 0x75, 0x57, 0x48, 0x0b } } }, + { { { 0x26, 0xdc, 0x76, 0x3b, 0xfc, 0xf9, 0x9c, 0x3f, 0x89, 0x0b, 0x62, 0x53, 0xaf, 0x83, 0x01, 0x2e, 0xbc, 0x6a, 0xc6, 0x03, 0x0d, 0x75, 0x2a, 0x0d, 0xe6, 0x94, 0x54, 0xcf, 0xb3, 0xe5, 0x96, 0x25 } }, + { { 0xfe, 0x82, 0xb1, 0x74, 0x31, 0x8a, 0xa7, 0x6f, 0x56, 0xbd, 0x8d, 0xf4, 0xe0, 0x94, 0x51, 0x59, 0xde, 0x2c, 0x5a, 0xf4, 0x84, 0x6b, 0x4a, 0x88, 0x93, 0xc0, 0x0c, 0x9a, 0xac, 0xa7, 0xa0, 0x68 } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0x25, 0x0d, 0xd6, 0xc7, 0x23, 0x47, 0x10, 0xad, 0xc7, 0x08, 0x5c, 0x87, 0x87, 0x93, 0x98, 0x18, 0xb8, 0xd3, 0x9c, 0xac, 0x5a, 0x3d, 0xc5, 0x75, 0xf8, 0x49, 0x32, 0x14, 0xcc, 0x51, 0x96, 0x24 } }, + { { 0x65, 0x9c, 0x5d, 0xf0, 0x37, 0x04, 0xf0, 0x34, 0x69, 0x2a, 0xf0, 0xa5, 0x64, 0xca, 0xde, 0x2b, 0x5b, 0x15, 0x10, 0xd2, 0xab, 0x06, 0xdd, 0xc4, 0xb0, 0xb6, 0x5b, 0xc1, 0x17, 0xdf, 0x8f, 0x02 } } }, + { { { 0xbd, 0x59, 0x3d, 0xbf, 0x5c, 0x31, 0x44, 0x2c, 0x32, 0x94, 0x04, 0x60, 0x84, 0x0f, 0xad, 0x00, 0xb6, 0x8f, 0xc9, 0x1d, 0xcc, 0x5c, 0xa2, 0x49, 0x0e, 0x50, 0x91, 0x08, 0x9a, 0x43, 0x55, 0x05 } }, + { { 0x5d, 0x93, 0x55, 0xdf, 0x9b, 0x12, 0x19, 0xec, 0x93, 0x85, 0x42, 0x9e, 0x66, 0x0f, 0x9d, 0xaf, 0x99, 0xaf, 0x26, 0x89, 0xbc, 0x61, 0xfd, 0xff, 0xce, 0x4b, 0xf4, 0x33, 0x95, 0xc9, 0x35, 0x58 } } }, + { { { 0x12, 0x55, 0xf9, 0xda, 0xcb, 0x44, 0xa7, 0xdc, 0x57, 0xe2, 0xf9, 0x9a, 0xe6, 0x07, 0x23, 0x60, 0x54, 0xa7, 0x39, 0xa5, 0x9b, 0x84, 0x56, 0x6e, 0xaa, 0x8b, 0x8f, 0xb0, 0x2c, 0x87, 0xaf, 0x67 } }, + { { 0x00, 0xa9, 0x4c, 0xb2, 0x12, 0xf8, 0x32, 0xa8, 0x7a, 0x00, 0x4b, 0x49, 0x32, 0xba, 0x1f, 0x5d, 0x44, 0x8e, 0x44, 0x7a, 0xdc, 0x11, 0xfb, 0x39, 0x08, 0x57, 0x87, 0xa5, 0x12, 0x42, 0x93, 0x0e } } }, + { { { 0x17, 0xb4, 0xae, 0x72, 0x59, 0xd0, 0xaa, 0xa8, 0x16, 0x8b, 0x63, 0x11, 0xb3, 0x43, 0x04, 0xda, 0x0c, 0xa8, 0xb7, 0x68, 0xdd, 0x4e, 0x54, 0xe7, 0xaf, 0x5d, 0x5d, 0x05, 0x76, 0x36, 0xec, 0x0d } }, + { { 0x6d, 0x7c, 0x82, 0x32, 0x38, 0x55, 0x57, 0x74, 0x5b, 0x7d, 0xc3, 0xc4, 0xfb, 0x06, 0x29, 0xf0, 0x13, 0x55, 0x54, 0xc6, 0xa7, 0xdc, 0x4c, 0x9f, 0x98, 0x49, 0x20, 0xa8, 0xc3, 0x8d, 0xfa, 0x48 } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0x87, 0x47, 0x9d, 0xe9, 0x25, 0xd5, 0xe3, 0x47, 0x78, 0xdf, 0x85, 0xa7, 0x85, 0x5e, 0x7a, 0x4c, 0x5f, 0x79, 0x1a, 0xf3, 0xa2, 0xb2, 0x28, 0xa0, 0x9c, 0xdd, 0x30, 0x40, 0xd4, 0x38, 0xbd, 0x28 } }, + { { 0xfc, 0xbb, 0xd5, 0x78, 0x6d, 0x1d, 0xd4, 0x99, 0xb4, 0xaa, 0x44, 0x44, 0x7a, 0x1b, 0xd8, 0xfe, 0xb4, 0x99, 0xb9, 0xcc, 0xe7, 0xc4, 0xd3, 0x3a, 0x73, 0x83, 0x41, 0x5c, 0x40, 0xd7, 0x2d, 0x55 } } }, + { { { 0x26, 0xe1, 0x7b, 0x5f, 0xe5, 0xdc, 0x3f, 0x7d, 0xa1, 0xa7, 0x26, 0x44, 0x22, 0x23, 0xc0, 0x8f, 0x7d, 0xf1, 0xb5, 0x11, 0x47, 0x7b, 0x19, 0xd4, 0x75, 0x6f, 0x1e, 0xa5, 0x27, 0xfe, 0xc8, 0x0e } }, + { { 0xd3, 0x11, 0x3d, 0xab, 0xef, 0x2c, 0xed, 0xb1, 0x3d, 0x7c, 0x32, 0x81, 0x6b, 0xfe, 0xf8, 0x1c, 0x3c, 0x7b, 0xc0, 0x61, 0xdf, 0xb8, 0x75, 0x76, 0x7f, 0xaa, 0xd8, 0x93, 0xaf, 0x3d, 0xe8, 0x3d } } }, + { { { 0xfd, 0x5b, 0x4e, 0x8d, 0xb6, 0x7e, 0x82, 0x9b, 0xef, 0xce, 0x04, 0x69, 0x51, 0x52, 0xff, 0xef, 0xa0, 0x52, 0xb5, 0x79, 0x17, 0x5e, 0x2f, 0xde, 0xd6, 0x3c, 0x2d, 0xa0, 0x43, 0xb4, 0x0b, 0x19 } }, + { { 0xc0, 0x61, 0x48, 0x48, 0x17, 0xf4, 0x9e, 0x18, 0x51, 0x2d, 0xea, 0x2f, 0xf2, 0xf2, 0xe0, 0xa3, 0x14, 0xb7, 0x8b, 0x3a, 0x30, 0xf5, 0x81, 0xc1, 0x5d, 0x71, 0x39, 0x62, 0x55, 0x1f, 0x60, 0x5a } } }, + { { { 0xe5, 0x89, 0x8a, 0x76, 0x6c, 0xdb, 0x4d, 0x0a, 0x5b, 0x72, 0x9d, 0x59, 0x6e, 0x63, 0x63, 0x18, 0x7c, 0xe3, 0xfa, 0xe2, 0xdb, 0xa1, 0x8d, 0xf4, 0xa5, 0xd7, 0x16, 0xb2, 0xd0, 0xb3, 0x3f, 0x39 } }, + { { 0xce, 0x60, 0x09, 0x6c, 0xf5, 0x76, 0x17, 0x24, 0x80, 0x3a, 0x96, 0xc7, 0x94, 0x2e, 0xf7, 0x6b, 0xef, 0xb5, 0x05, 0x96, 0xef, 0xd3, 0x7b, 0x51, 0xda, 0x05, 0x44, 0x67, 0xbc, 0x07, 0x21, 0x4e } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0xe9, 0x73, 0x6f, 0x21, 0xb9, 0xde, 0x22, 0x7d, 0xeb, 0x97, 0x31, 0x10, 0xa3, 0xea, 0xe1, 0xc6, 0x37, 0xeb, 0x8f, 0x43, 0x58, 0xde, 0x41, 0x64, 0x0e, 0x3e, 0x07, 0x99, 0x3d, 0xf1, 0xdf, 0x1e } }, + { { 0xf8, 0xad, 0x43, 0xc2, 0x17, 0x06, 0xe2, 0xe4, 0xa9, 0x86, 0xcd, 0x18, 0xd7, 0x78, 0xc8, 0x74, 0x66, 0xd2, 0x09, 0x18, 0xa5, 0xf1, 0xca, 0xa6, 0x62, 0x92, 0xc1, 0xcb, 0x00, 0xeb, 0x42, 0x2e } } }, + { { { 0x7b, 0x34, 0x24, 0x4c, 0xcf, 0x38, 0xe5, 0x6c, 0x0a, 0x01, 0x2c, 0x22, 0x0b, 0x24, 0x38, 0xad, 0x24, 0x7e, 0x19, 0xf0, 0x6c, 0xf9, 0x31, 0xf4, 0x35, 0x11, 0xf6, 0x46, 0x33, 0x3a, 0x23, 0x59 } }, + { { 0x20, 0x0b, 0xa1, 0x08, 0x19, 0xad, 0x39, 0x54, 0xea, 0x3e, 0x23, 0x09, 0xb6, 0xe2, 0xd2, 0xbc, 0x4d, 0xfc, 0x9c, 0xf0, 0x13, 0x16, 0x22, 0x3f, 0xb9, 0xd2, 0x11, 0x86, 0x90, 0x55, 0xce, 0x3c } } }, + { { { 0xc4, 0x0b, 0x4b, 0x62, 0x99, 0x37, 0x84, 0x3f, 0x74, 0xa2, 0xf9, 0xce, 0xe2, 0x0b, 0x0f, 0x2a, 0x3d, 0xa3, 0xe3, 0xdb, 0x5a, 0x9d, 0x93, 0xcc, 0xa5, 0xef, 0x82, 0x91, 0x1d, 0xe6, 0x6c, 0x68 } }, + { { 0xa3, 0x64, 0x17, 0x9b, 0x8b, 0xc8, 0x3a, 0x61, 0xe6, 0x9d, 0xc6, 0xed, 0x7b, 0x03, 0x52, 0x26, 0x9d, 0x3a, 0xb3, 0x13, 0xcc, 0x8a, 0xfd, 0x2c, 0x1a, 0x1d, 0xed, 0x13, 0xd0, 0x55, 0x57, 0x0e } } }, + { { { 0x1a, 0xea, 0xbf, 0xfd, 0x4a, 0x3c, 0x8e, 0xec, 0x29, 0x7e, 0x77, 0x77, 0x12, 0x99, 0xd7, 0x84, 0xf9, 0x55, 0x7f, 0xf1, 0x8b, 0xb4, 0xd2, 0x95, 0xa3, 0x8d, 0xf0, 0x8a, 0xa7, 0xeb, 0x82, 0x4b } }, + { { 0x2c, 0x28, 0xf4, 0x3a, 0xf6, 0xde, 0x0a, 0xe0, 0x41, 0x44, 0x23, 0xf8, 0x3f, 0x03, 0x64, 0x9f, 0xc3, 0x55, 0x4c, 0xc6, 0xc1, 0x94, 0x1c, 0x24, 0x5d, 0x5f, 0x92, 0x45, 0x96, 0x57, 0x37, 0x14 } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0xc1, 0xcd, 0x90, 0x66, 0xb9, 0x76, 0xa0, 0x5b, 0xa5, 0x85, 0x75, 0x23, 0xf9, 0x89, 0xa5, 0x82, 0xb2, 0x6f, 0xb1, 0xeb, 0xc4, 0x69, 0x6f, 0x18, 0x5a, 0xed, 0x94, 0x3d, 0x9d, 0xd9, 0x2c, 0x1a } }, + { { 0x35, 0xb0, 0xe6, 0x73, 0x06, 0xb7, 0x37, 0xe0, 0xf8, 0xb0, 0x22, 0xe8, 0xd2, 0xed, 0x0b, 0xef, 0xe6, 0xc6, 0x5a, 0x99, 0x9e, 0x1a, 0x9f, 0x04, 0x97, 0xe4, 0x4d, 0x0b, 0xbe, 0xba, 0x44, 0x40 } } }, + { { { 0xc1, 0x56, 0x96, 0x91, 0x5f, 0x1f, 0xbb, 0x54, 0x6f, 0x88, 0x89, 0x0a, 0xb2, 0xd6, 0x41, 0x42, 0x6a, 0x82, 0xee, 0x14, 0xaa, 0x76, 0x30, 0x65, 0x0f, 0x67, 0x39, 0xa6, 0x51, 0x7c, 0x49, 0x24 } }, + { { 0x35, 0xa3, 0x78, 0xd1, 0x11, 0x0f, 0x75, 0xd3, 0x70, 0x46, 0xdb, 0x20, 0x51, 0xcb, 0x92, 0x80, 0x54, 0x10, 0x74, 0x36, 0x86, 0xa9, 0xd7, 0xa3, 0x08, 0x78, 0xf1, 0x01, 0x29, 0xf8, 0x80, 0x3b } } }, + { { { 0xdb, 0xa7, 0x9d, 0x9d, 0xbf, 0xa0, 0xcc, 0xed, 0x53, 0xa2, 0xa2, 0x19, 0x39, 0x48, 0x83, 0x19, 0x37, 0x58, 0xd1, 0x04, 0x28, 0x40, 0xf7, 0x8a, 0xc2, 0x08, 0xb7, 0xa5, 0x42, 0xcf, 0x53, 0x4c } }, + { { 0xa7, 0xbb, 0xf6, 0x8e, 0xad, 0xdd, 0xf7, 0x90, 0xdd, 0x5f, 0x93, 0x89, 0xae, 0x04, 0x37, 0xe6, 0x9a, 0xb7, 0xe8, 0xc0, 0xdf, 0x16, 0x2a, 0xbf, 0xc4, 0x3a, 0x3c, 0x41, 0xd5, 0x89, 0x72, 0x5a } } }, + { { { 0x1f, 0x96, 0xff, 0x34, 0x2c, 0x13, 0x21, 0xcb, 0x0a, 0x89, 0x85, 0xbe, 0xb3, 0x70, 0x9e, 0x1e, 0xde, 0x97, 0xaf, 0x96, 0x30, 0xf7, 0x48, 0x89, 0x40, 0x8d, 0x07, 0xf1, 0x25, 0xf0, 0x30, 0x58 } }, + { { 0x1e, 0xd4, 0x93, 0x57, 0xe2, 0x17, 0xe7, 0x9d, 0xab, 0x3c, 0x55, 0x03, 0x82, 0x2f, 0x2b, 0xdb, 0x56, 0x1e, 0x30, 0x2e, 0x24, 0x47, 0x6e, 0xe6, 0xff, 0x33, 0x24, 0x2c, 0x75, 0x51, 0xd4, 0x67 } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0x2b, 0x06, 0xd9, 0xa1, 0x5d, 0xe1, 0xf4, 0xd1, 0x1e, 0x3c, 0x9a, 0xc6, 0x29, 0x2b, 0x13, 0x13, 0x78, 0xc0, 0xd8, 0x16, 0x17, 0x2d, 0x9e, 0xa9, 0xc9, 0x79, 0x57, 0xab, 0x24, 0x91, 0x92, 0x19 } }, + { { 0x69, 0xfb, 0xa1, 0x9c, 0xa6, 0x75, 0x49, 0x7d, 0x60, 0x73, 0x40, 0x42, 0xc4, 0x13, 0x0a, 0x95, 0x79, 0x1e, 0x04, 0x83, 0x94, 0x99, 0x9b, 0x1e, 0x0c, 0xe8, 0x1f, 0x54, 0xef, 0xcb, 0xc0, 0x52 } } }, + { { { 0x14, 0x89, 0x73, 0xa1, 0x37, 0x87, 0x6a, 0x7a, 0xcf, 0x1d, 0xd9, 0x2e, 0x1a, 0x67, 0xed, 0x74, 0xc0, 0xf0, 0x9c, 0x33, 0xdd, 0xdf, 0x08, 0xbf, 0x7b, 0xd1, 0x66, 0xda, 0xe6, 0xc9, 0x49, 0x08 } }, + { { 0xe9, 0xdd, 0x5e, 0x55, 0xb0, 0x0a, 0xde, 0x21, 0x4c, 0x5a, 0x2e, 0xd4, 0x80, 0x3a, 0x57, 0x92, 0x7a, 0xf1, 0xc4, 0x2c, 0x40, 0xaf, 0x2f, 0xc9, 0x92, 0x03, 0xe5, 0x5a, 0xbc, 0xdc, 0xf4, 0x09 } } }, + { { { 0xf3, 0xe1, 0x2b, 0x7c, 0x05, 0x86, 0x80, 0x93, 0x4a, 0xad, 0xb4, 0x8f, 0x7e, 0x99, 0x0c, 0xfd, 0xcd, 0xef, 0xd1, 0xff, 0x2c, 0x69, 0x34, 0x13, 0x41, 0x64, 0xcf, 0x3b, 0xd0, 0x90, 0x09, 0x1e } }, + { { 0x9d, 0x45, 0xd6, 0x80, 0xe6, 0x45, 0xaa, 0xf4, 0x15, 0xaa, 0x5c, 0x34, 0x87, 0x99, 0xa2, 0x8c, 0x26, 0x84, 0x62, 0x7d, 0xb6, 0x29, 0xc0, 0x52, 0xea, 0xf5, 0x81, 0x18, 0x0f, 0x35, 0xa9, 0x0e } } }, + { { { 0xe7, 0x20, 0x72, 0x7c, 0x6d, 0x94, 0x5f, 0x52, 0x44, 0x54, 0xe3, 0xf1, 0xb2, 0xb0, 0x36, 0x46, 0x0f, 0xae, 0x92, 0xe8, 0x70, 0x9d, 0x6e, 0x79, 0xb1, 0xad, 0x37, 0xa9, 0x5f, 0xc0, 0xde, 0x03 } }, + { { 0x15, 0x55, 0x37, 0xc6, 0x1c, 0x27, 0x1c, 0x6d, 0x14, 0x4f, 0xca, 0xa4, 0xc4, 0x88, 0x25, 0x46, 0x39, 0xfc, 0x5a, 0xe5, 0xfe, 0x29, 0x11, 0x69, 0xf5, 0x72, 0x84, 0x4d, 0x78, 0x9f, 0x94, 0x15 } } }, + { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, + { { { 0xec, 0xd3, 0xff, 0x57, 0x0b, 0xb0, 0xb2, 0xdc, 0xf8, 0x4f, 0xe2, 0x12, 0xd5, 0x36, 0xbe, 0x6b, 0x09, 0x43, 0x6d, 0xa3, 0x4d, 0x90, 0x2d, 0xb8, 0x74, 0xe8, 0x71, 0x45, 0x19, 0x8b, 0x0c, 0x6a } }, + { { 0xb8, 0x42, 0x1c, 0x03, 0xad, 0x2c, 0x03, 0x8e, 0xac, 0xd7, 0x98, 0x29, 0x13, 0xc6, 0x02, 0x29, 0xb5, 0xd4, 0xe7, 0xcf, 0xcc, 0x8b, 0x83, 0xec, 0x35, 0xc7, 0x9c, 0x74, 0xb7, 0xad, 0x85, 0x5f } } }, + { { { 0x78, 0x84, 0xe1, 0x56, 0x45, 0x69, 0x68, 0x5a, 0x4f, 0xb8, 0xb1, 0x29, 0xff, 0x33, 0x03, 0x31, 0xb7, 0xcb, 0x96, 0x25, 0xe6, 0xe6, 0x41, 0x98, 0x1a, 0xbb, 0x03, 0x56, 0xf2, 0xb2, 0x91, 0x34 } }, + { { 0x2c, 0x6c, 0xf7, 0x66, 0xa4, 0x62, 0x6b, 0x39, 0xb3, 0xba, 0x65, 0xd3, 0x1c, 0xf8, 0x11, 0xaa, 0xbe, 0xdc, 0x80, 0x59, 0x87, 0xf5, 0x7b, 0xe5, 0xe3, 0xb3, 0x3e, 0x39, 0xda, 0xbe, 0x88, 0x09 } } }, + { { { 0x8b, 0xf1, 0xa0, 0xf5, 0xdc, 0x29, 0xb4, 0xe2, 0x07, 0xc6, 0x7a, 0x00, 0xd0, 0x89, 0x17, 0x51, 0xd4, 0xbb, 0xd4, 0x22, 0xea, 0x7e, 0x7d, 0x7c, 0x24, 0xea, 0xf2, 0xe8, 0x22, 0x12, 0x95, 0x06 } }, + { { 0xda, 0x7c, 0xa4, 0x0c, 0xf4, 0xba, 0x6e, 0xe1, 0x89, 0xb5, 0x59, 0xca, 0xf1, 0xc0, 0x29, 0x36, 0x09, 0x44, 0xe2, 0x7f, 0xd1, 0x63, 0x15, 0x99, 0xea, 0x25, 0xcf, 0x0c, 0x9d, 0xc0, 0x44, 0x6f } } }, + { { { 0x1d, 0x86, 0x4e, 0xcf, 0xf7, 0x37, 0x10, 0x25, 0x8f, 0x12, 0xfb, 0x19, 0xfb, 0xe0, 0xed, 0x10, 0xc8, 0xe2, 0xf5, 0x75, 0xb1, 0x33, 0xc0, 0x96, 0x0d, 0xfb, 0x15, 0x6c, 0x0d, 0x07, 0x5f, 0x05 } }, + { { 0x69, 0x3e, 0x47, 0x97, 0x2c, 0xaf, 0x52, 0x7c, 0x78, 0x83, 0xad, 0x1b, 0x39, 0x82, 0x2f, 0x02, 0x6f, 0x47, 0xdb, 0x2a, 0xb0, 0xe1, 0x91, 0x99, 0x55, 0xb8, 0x99, 0x3a, 0xa0, 0x44, 0x11, 0x51 } } } +}; + +static inline void p1p1_to_p2(ge25519_p2* r, const ge25519_p1p1* p) +{ + fe25519_mul(&r->x, &p->x, &p->t); + fe25519_mul(&r->y, &p->y, &p->z); + fe25519_mul(&r->z, &p->z, &p->t); +} + +static inline void p1p1_to_p2_2(ge25519_p3* r, const ge25519_p1p1* p) +{ + fe25519_mul(&r->x, &p->x, &p->t); + fe25519_mul(&r->y, &p->y, &p->z); + fe25519_mul(&r->z, &p->z, &p->t); +} + +static inline void p1p1_to_p3(ge25519_p3* r, const ge25519_p1p1* p) +{ + p1p1_to_p2_2(r, p); + fe25519_mul(&r->t, &p->x, &p->y); +} + +static inline void ge25519_mixadd2(ge25519_p3* r, const ge25519_aff* q) +{ + fe25519 a, b, t1, t2, c, d, e, f, g, h, qt; + fe25519_mul(&qt, &q->x, &q->y); + fe25519_sub(&a, &r->y, &r->x); /* A = (Y1-X1)*(Y2-X2) */ + fe25519_add(&b, &r->y, &r->x); /* B = (Y1+X1)*(Y2+X2) */ + fe25519_sub(&t1, &q->y, &q->x); + fe25519_add(&t2, &q->y, &q->x); + fe25519_mul(&a, &a, &t1); + fe25519_mul(&b, &b, &t2); + fe25519_sub(&e, &b, &a); /* E = B-A */ + fe25519_add(&h, &b, &a); /* H = B+A */ + fe25519_mul(&c, &r->t, &qt); /* C = T1*k*T2 */ + fe25519_mul(&c, &c, &ge25519_ec2d); + fe25519_add(&d, &r->z, &r->z); /* D = Z1*2 */ + fe25519_sub(&f, &d, &c); /* F = D-C */ + fe25519_add(&g, &d, &c); /* G = D+C */ + fe25519_mul(&r->x, &e, &f); + fe25519_mul(&r->y, &h, &g); + fe25519_mul(&r->z, &g, &f); + fe25519_mul(&r->t, &e, &h); +} + +static inline void add_p1p1(ge25519_p1p1* r, const ge25519_p3* p, const ge25519_p3* q) +{ + fe25519 a, b, c, d, t; + + fe25519_sub(&a, &p->y, &p->x); /* A = (Y1-X1)*(Y2-X2) */ + fe25519_sub(&t, &q->y, &q->x); + fe25519_mul(&a, &a, &t); + fe25519_add(&b, &p->x, &p->y); /* B = (Y1+X1)*(Y2+X2) */ + fe25519_add(&t, &q->x, &q->y); + fe25519_mul(&b, &b, &t); + fe25519_mul(&c, &p->t, &q->t); /* C = T1*k*T2 */ + fe25519_mul(&c, &c, &ge25519_ec2d); + fe25519_mul(&d, &p->z, &q->z); /* D = Z1*2*Z2 */ + fe25519_add(&d, &d, &d); + fe25519_sub(&r->x, &b, &a); /* E = B-A */ + fe25519_sub(&r->t, &d, &c); /* F = D-C */ + fe25519_add(&r->z, &d, &c); /* G = D+C */ + fe25519_add(&r->y, &b, &a); /* H = B+A */ +} + +/* See http://www.hyperelliptic.org/EFD/g1p/auto-twisted-extended-1.html#doubling-dbl-2008-hwcd */ +static inline void dbl_p1p1(ge25519_p1p1* r, const ge25519_p2* p) +{ + fe25519 a, b, c, d; + fe25519_square(&a, &p->x); + fe25519_square(&b, &p->y); + fe25519_square(&c, &p->z); + fe25519_add(&c, &c, &c); + fe25519_neg(&d, &a); + + fe25519_add(&r->x, &p->x, &p->y); + fe25519_square(&r->x, &r->x); + fe25519_sub(&r->x, &r->x, &a); + fe25519_sub(&r->x, &r->x, &b); + fe25519_add(&r->z, &d, &b); + fe25519_sub(&r->t, &r->z, &c); + fe25519_sub(&r->y, &d, &b); +} + +/* Constant-time version of: if(b) r = p */ +static inline void cmov_aff(ge25519_aff* r, const ge25519_aff* p, unsigned char b) +{ + fe25519_cmov(&r->x, &p->x, b); + fe25519_cmov(&r->y, &p->y, b); +} + +static inline unsigned char equal(signed char b, signed char c) +{ + unsigned char ub = b; + unsigned char uc = c; + unsigned char x = ub ^ uc; /* 0: yes; 1..255: no */ + crypto_uint32 y = x; /* 0: yes; 1..255: no */ + y -= 1; /* 4294967295: yes; 0..254: no */ + y >>= 31; /* 1: yes; 0: no */ + return (unsigned char)y; +} + +static inline unsigned char negative(signed char b) +{ + unsigned long long x = b; /* 18446744073709551361..18446744073709551615: yes; 0..255: no */ + x >>= 63; /* 1: yes; 0: no */ + return (unsigned char)x; +} + +static inline void choose_t(ge25519_aff* t, unsigned long long pos, signed char b) +{ + /* constant time */ + fe25519 v; + *t = ge25519_base_multiples_affine[5 * pos + 0]; + cmov_aff(t, &ge25519_base_multiples_affine[5 * pos + 1], equal(b, 1) | equal(b, -1)); + cmov_aff(t, &ge25519_base_multiples_affine[5 * pos + 2], equal(b, 2) | equal(b, -2)); + cmov_aff(t, &ge25519_base_multiples_affine[5 * pos + 3], equal(b, 3) | equal(b, -3)); + cmov_aff(t, &ge25519_base_multiples_affine[5 * pos + 4], equal(b, -4)); + fe25519_neg(&v, &t->x); + fe25519_cmov(&t->x, &v, negative(b)); +} + +static inline void setneutral(ge25519* r) +{ + fe25519_setzero(&r->x); + fe25519_setone(&r->y); + fe25519_setone(&r->z); + fe25519_setzero(&r->t); +} + +/* return 0 on success, -1 otherwise */ +static inline int ge25519_unpackneg_vartime(ge25519_p3* r, const unsigned char p[32]) +{ + unsigned char par; + fe25519 t, chk, num, den, den2, den4, den6; + fe25519_setone(&r->z); + par = p[31] >> 7; + fe25519_unpack(&r->y, p); + fe25519_square(&num, &r->y); /* x = y^2 */ + fe25519_mul(&den, &num, &ge25519_ecd); /* den = dy^2 */ + fe25519_sub(&num, &num, &r->z); /* x = y^2-1 */ + fe25519_add(&den, &r->z, &den); /* den = dy^2+1 */ + + /* Computation of sqrt(num/den) */ + /* 1.: computation of num^((p-5)/8)*den^((7p-35)/8) = (num*den^7)^((p-5)/8) */ + fe25519_square(&den2, &den); + fe25519_square(&den4, &den2); + fe25519_mul(&den6, &den4, &den2); + fe25519_mul(&t, &den6, &num); + fe25519_mul(&t, &t, &den); + + fe25519_pow2523(&t, &t); + /* 2. computation of r->x = t * num * den^3 */ + fe25519_mul(&t, &t, &num); + fe25519_mul(&t, &t, &den); + fe25519_mul(&t, &t, &den); + fe25519_mul(&r->x, &t, &den); + + /* 3. Check whether sqrt computation gave correct result, multiply by sqrt(-1) if not: */ + fe25519_square(&chk, &r->x); + fe25519_mul(&chk, &chk, &den); + if (! fe25519_iseq_vartime(&chk, &num)) { + fe25519_mul(&r->x, &r->x, &ge25519_sqrtm1); + } + + /* 4. Now we have one of the two square roots, except if input was not a square */ + fe25519_square(&chk, &r->x); + fe25519_mul(&chk, &chk, &den); + if (! fe25519_iseq_vartime(&chk, &num)) { + return -1; + } + + /* 5. Choose the desired square root according to parity: */ + if (fe25519_getparity(&r->x) != (1 - par)) { + fe25519_neg(&r->x, &r->x); + } + + fe25519_mul(&r->t, &r->x, &r->y); + return 0; +} + +static inline void ge25519_pack(unsigned char r[32], const ge25519_p3* p) +{ + fe25519 tx, ty, zi; + fe25519_invert(&zi, &p->z); + fe25519_mul(&tx, &p->x, &zi); + fe25519_mul(&ty, &p->y, &zi); + fe25519_pack(r, &ty); + r[31] ^= fe25519_getparity(&tx) << 7; +} + +/* computes [s1]p1 + [s2]p2 */ +static inline void ge25519_double_scalarmult_vartime(ge25519_p3* r, const ge25519_p3* p1, const sc25519* s1, const ge25519_p3* p2, const sc25519* s2) +{ + ge25519_p1p1 tp1p1; + ge25519_p3 pre[16]; + char* pre5 = (char*)(&(pre[5])); // eliminate type punning warning + unsigned char b[127]; + int i; + + /* precomputation s2 s1 */ + setneutral(pre); /* 00 00 */ + pre[1] = *p1; /* 00 01 */ + dbl_p1p1(&tp1p1, (ge25519_p2*)p1); + p1p1_to_p3(&pre[2], &tp1p1); /* 00 10 */ + add_p1p1(&tp1p1, &pre[1], &pre[2]); + p1p1_to_p3(&pre[3], &tp1p1); /* 00 11 */ + pre[4] = *p2; /* 01 00 */ + add_p1p1(&tp1p1, &pre[1], &pre[4]); + p1p1_to_p3(&pre[5], &tp1p1); /* 01 01 */ + add_p1p1(&tp1p1, &pre[2], &pre[4]); + p1p1_to_p3(&pre[6], &tp1p1); /* 01 10 */ + add_p1p1(&tp1p1, &pre[3], &pre[4]); + p1p1_to_p3(&pre[7], &tp1p1); /* 01 11 */ + dbl_p1p1(&tp1p1, (ge25519_p2*)p2); + p1p1_to_p3(&pre[8], &tp1p1); /* 10 00 */ + add_p1p1(&tp1p1, &pre[1], &pre[8]); + p1p1_to_p3(&pre[9], &tp1p1); /* 10 01 */ + dbl_p1p1(&tp1p1, (ge25519_p2*)pre5); + p1p1_to_p3(&pre[10], &tp1p1); /* 10 10 */ + add_p1p1(&tp1p1, &pre[3], &pre[8]); + p1p1_to_p3(&pre[11], &tp1p1); /* 10 11 */ + add_p1p1(&tp1p1, &pre[4], &pre[8]); + p1p1_to_p3(&pre[12], &tp1p1); /* 11 00 */ + add_p1p1(&tp1p1, &pre[1], &pre[12]); + p1p1_to_p3(&pre[13], &tp1p1); /* 11 01 */ + add_p1p1(&tp1p1, &pre[2], &pre[12]); + p1p1_to_p3(&pre[14], &tp1p1); /* 11 10 */ + add_p1p1(&tp1p1, &pre[3], &pre[12]); + p1p1_to_p3(&pre[15], &tp1p1); /* 11 11 */ + + sc25519_2interleave2(b, s1, s2); + + /* scalar multiplication */ + *r = pre[b[126]]; + for (i = 125; i >= 0; i--) { + dbl_p1p1(&tp1p1, (ge25519_p2*)r); + p1p1_to_p2((ge25519_p2*)r, &tp1p1); + dbl_p1p1(&tp1p1, (ge25519_p2*)r); + if (b[i] != 0) { + p1p1_to_p3(r, &tp1p1); + add_p1p1(&tp1p1, r, &pre[b[i]]); + } + if (i != 0) { + p1p1_to_p2((ge25519_p2*)r, &tp1p1); + } + else { + p1p1_to_p3(r, &tp1p1); + } + } +} + +static inline void ge25519_scalarmult_base(ge25519_p3* r, const sc25519* s) +{ + signed char b[85]; + int i; + ge25519_aff t; + sc25519_window3(b, s); + + choose_t((ge25519_aff*)r, 0, b[0]); + fe25519_setone(&r->z); + fe25519_mul(&r->t, &r->x, &r->y); + for (i = 1; i < 85; i++) { + choose_t(&t, (unsigned long long)i, b[i]); + ge25519_mixadd2(r, &t); + } +} + +static inline void get_hram(unsigned char* hram, const unsigned char* sm, const unsigned char* pk, unsigned char* playground, unsigned long long smlen) +{ + unsigned long long i; + + for (i = 0; i < 32; ++i) { + playground[i] = sm[i]; + } + for (i = 32; i < 64; ++i) { + playground[i] = pk[i - 32]; + } + for (i = 64; i < smlen; ++i) { + playground[i] = sm[i]; + } + + ZeroTier::SHA512(hram, playground, (unsigned int)smlen); +} + +////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + +} // anonymous namespace + +#ifdef ZT_USE_FAST_X64_ED25519 +extern "C" void ed25519_amd64_asm_sign(const unsigned char* sk, const unsigned char* pk, const unsigned char* digest, unsigned char* sig); +#endif + +namespace ZeroTier { + +void ECC::agree(const ECC::Private& mine, const ECC::Public& their, void* keybuf, unsigned int keylen) +{ + unsigned char rawkey[32]; + unsigned char digest[64]; + + crypto_scalarmult(rawkey, mine.data, their.data); + SHA512(digest, rawkey, 32); + for (unsigned int i = 0, k = 0; i < keylen;) { + if (k == 64) { + k = 0; + SHA512(digest, digest, 64); + } + ((unsigned char*)keybuf)[i++] = digest[k++]; + } +} + +void ECC::sign(const ECC::Private& myPrivate, const ECC::Public& myPublic, const void* msg, unsigned int len, void* signature) +{ + unsigned char digest[64]; // we sign the first 32 bytes of SHA-512(msg) + SHA512(digest, msg, len); + +#ifdef ZT_USE_FAST_X64_ED25519 + ed25519_amd64_asm_sign(myPrivate.data + 32, myPublic.data + 32, digest, (unsigned char*)signature); +#else + sc25519 sck, scs, scsk; + ge25519 ger; + unsigned char r[32]; + unsigned char s[32]; + unsigned char extsk[64]; + unsigned char hmg[crypto_hash_sha512_BYTES]; + unsigned char hram[crypto_hash_sha512_BYTES]; + unsigned char* sig = (unsigned char*)signature; + + SHA512(extsk, myPrivate.data + 32, 32); + extsk[0] &= 248; + extsk[31] &= 127; + extsk[31] |= 64; + + for (unsigned int i = 0; i < 32; i++) { + sig[32 + i] = extsk[32 + i]; + } + for (unsigned int i = 0; i < 32; i++) { + sig[64 + i] = digest[i]; + } + + SHA512(hmg, sig + 32, 64); + + /* Computation of R */ + sc25519_from64bytes(&sck, hmg); + ge25519_scalarmult_base(&ger, &sck); + ge25519_pack(r, &ger); + + /* Computation of s */ + for (unsigned int i = 0; i < 32; i++) { + sig[i] = r[i]; + } + + get_hram(hram, sig, myPublic.data + 32, sig, 96); + + sc25519_from64bytes(&scs, hram); + sc25519_from32bytes(&scsk, extsk); + sc25519_mul(&scs, &scs, &scsk); + + sc25519_add(&scs, &scs, &sck); + + sc25519_to32bytes(s, &scs); /* cat s */ + for (unsigned int i = 0; i < 32; i++) { + sig[32 + i] = s[i]; + } +#endif +} + +bool ECC::verify(const ECC::Public& their, const void* msg, unsigned int len, const void* signature) +{ + const unsigned char* const sig = (const unsigned char*)signature; + unsigned char digest[64]; // we sign the first 32 bytes of SHA-512(msg) + SHA512(digest, msg, len); + if (! Utils::secureEq(sig + 64, digest, 32)) { + return false; + } + + unsigned char t2[32]; + ge25519 get1, get2; + sc25519 schram, scs; + unsigned char hram[crypto_hash_sha512_BYTES]; + unsigned char m[96]; + + if (ge25519_unpackneg_vartime(&get1, their.data + 32)) { + return false; + } + + get_hram(hram, sig, their.data + 32, m, 96); + + sc25519_from64bytes(&schram, hram); + + sc25519_from32bytes(&scs, sig + 32); + + ge25519_double_scalarmult_vartime(&get2, &get1, &schram, &ge25519_base, &scs); + ge25519_pack(t2, &get2); + + return Utils::secureEq(sig, t2, 32); +} + +void ECC::_calcPubDH(ECC::Pair& kp) +{ + // First 32 bytes of pub and priv are the keys for ECDH key + // agreement. This generates the public portion from the private. + crypto_scalarmult_base(kp.pub.data, kp.priv.data); +} + +void ECC::_calcPubED(ECC::Pair& kp) +{ + unsigned char extsk[64]; + sc25519 scsk; + ge25519 gepk; + + // Second 32 bytes of pub and priv are the keys for ed25519 + // signing and verification. + SHA512(extsk, kp.priv.data + 32, 32); + extsk[0] &= 248; + extsk[31] &= 127; + extsk[31] |= 64; + sc25519_from32bytes(&scsk, extsk); + ge25519_scalarmult_base(&gepk, &scsk); + ge25519_pack(kp.pub.data + 32, &gepk); + // In NaCl, the public key is crammed into the next 32 bytes + // of the private key for signing since both keys are required + // to sign. In this version we just get it from kp.pub, so we + // leave that out of private. +} + +} // namespace ZeroTier diff --git a/node/ECC.hpp b/node/ECC.hpp new file mode 100644 index 00000000..045f5cfc --- /dev/null +++ b/node/ECC.hpp @@ -0,0 +1,227 @@ +/* + * Copyright (c)2019 ZeroTier, Inc. + * + * Use of this software is governed by the Business Source License included + * in the LICENSE.TXT file in the project's root directory. + * + * Change Date: 2026-01-01 + * + * On the date above, in accordance with the Business Source License, use + * of this software will be governed by version 2.0 of the Apache License. + */ +/****/ + +/* + * This file defines the elliptic curve crypto used for ZeroTier V1. The normal + * public version uses C25519 and Ed25519, while the FIPS version uses NIST. + * FIPS builds are completely incompatible with regular ZeroTier, but that's + * fine since FIPS users typically want a fully isolated private network. If you + * are not such a user you probably don't want this. + */ + +#ifndef ZT_ECC_HPP +#define ZT_ECC_HPP + +#include "Utils.hpp" + +#ifdef ZT_FIPS + +/* FIPS140/NIST ECC cryptography */ +/* Note that to be FIPS we also need to link against a FIPS-certified library. */ + +#include +#include +#include +#include +#include + +#define ZT_ECC_EPHEMERAL_PUBLIC_KEY_LEN 97 /* Single ECC P-384 key */ +#define ZT_ECC_PUBLIC_KEY_SET_LEN (97 * 2) /* Two ECC P-384 keys */ +#define ZT_ECC_PRIVATE_KEY_SET_LEN (48 * 2) /* Two ECC P-384 secret keys */ +#define ZT_ECC_SIGNATURE_LEN 96 /* NIST P-384 ECDSA signature */ + +class ECC { + public: + struct Public { + uint8_t data[ZT_ECC_PUBLIC_KEY_SET_LEN]; + }; + struct Private { + uint8_t data[ZT_ECC_PRIVATE_KEY_SET_LEN]; + }; + struct Signature { + uint8_t data[ZT_ECC_SIGNATURE_LEN]; + }; + struct Pair { + Public pub; + Private priv; + }; +}; + +#else // Curve25519 / Ed25519 + +namespace ZeroTier { + +#define ZT_ECC_EPHEMERAL_PUBLIC_KEY_LEN 32 /* Single C25519 ECDH key */ +#define ZT_ECC_PUBLIC_KEY_SET_LEN 64 /* C25519 and Ed25519 keys */ +#define ZT_ECC_PRIVATE_KEY_SET_LEN 64 /* C25519 and Ed25519 secret keys */ +#define ZT_ECC_SIGNATURE_LEN 96 /* Ed25519 signature plus (not necessary) hash */ + +class ECC { + public: + struct Public { + uint8_t data[ZT_ECC_PUBLIC_KEY_SET_LEN]; + }; + struct Private { + uint8_t data[ZT_ECC_PRIVATE_KEY_SET_LEN]; + }; + struct Signature { + uint8_t data[ZT_ECC_SIGNATURE_LEN]; + }; + struct Pair { + Public pub; + Private priv; + }; + + /** + * Generate an elliptic curve key pair + */ + static inline Pair generate() + { + Pair kp; + Utils::getSecureRandom(kp.priv.data, ZT_ECC_PRIVATE_KEY_SET_LEN); + _calcPubDH(kp); + _calcPubED(kp); + return kp; + } + + /** + * Generate a key pair satisfying a condition + * + * This begins with a random keypair from a random secret key and then + * iteratively increments the random secret until cond(kp) returns true. + * This is used to compute key pairs in which the public key, its hash + * or some other aspect of it satisfies some condition, such as for a + * hashcash criteria. + * + * @param cond Condition function or function object + * @return Key pair where cond(kp) returns true + * @tparam F Type of 'cond' + */ + template static inline Pair generateSatisfying(F cond) + { + Pair kp; + void* const priv = (void*)kp.priv.data; + Utils::getSecureRandom(priv, ZT_ECC_PRIVATE_KEY_SET_LEN); + _calcPubED(kp); // do Ed25519 key -- bytes 32-63 of pub and priv + do { + ++(((uint64_t*)priv)[1]); + --(((uint64_t*)priv)[2]); + _calcPubDH(kp); // keep regenerating bytes 0-31 until satisfied + } while (! cond(kp)); + return kp; + } + + /** + * Perform C25519 ECC key agreement + * + * Actual key bytes are generated from one or more SHA-512 digests of + * the raw result of key agreement. + * + * @param mine My private key + * @param their Their public key + * @param keybuf Buffer to fill + * @param keylen Number of key bytes to generate + */ + static void agree(const Private& mine, const Public& their, void* keybuf, unsigned int keylen); + static inline void agree(const Pair& mine, const Public& their, void* keybuf, unsigned int keylen) + { + agree(mine.priv, their, keybuf, keylen); + } + + /** + * Sign a message with a sender's key pair + * + * This takes the SHA-521 of msg[] and then signs the first 32 bytes of this + * digest, returning it and the 64-byte ed25519 signature in signature[]. + * This results in a signature that verifies both the signer's authenticity + * and the integrity of the message. + * + * This is based on the original ed25519 code from NaCl and the SUPERCOP + * cipher benchmark suite, but with the modification that it always + * produces a signature of fixed 96-byte length based on the hash of an + * arbitrary-length message. + * + * @param myPrivate My private key + * @param myPublic My public key + * @param msg Message to sign + * @param len Length of message in bytes + * @param signature Buffer to fill with signature -- MUST be 96 bytes in length + */ + static void sign(const Private& myPrivate, const Public& myPublic, const void* msg, unsigned int len, void* signature); + static inline void sign(const Pair& mine, const void* msg, unsigned int len, void* signature) + { + sign(mine.priv, mine.pub, msg, len, signature); + } + + /** + * Sign a message with a sender's key pair + * + * @param myPrivate My private key + * @param myPublic My public key + * @param msg Message to sign + * @param len Length of message in bytes + * @return Signature + */ + static inline Signature sign(const Private& myPrivate, const Public& myPublic, const void* msg, unsigned int len) + { + Signature sig; + sign(myPrivate, myPublic, msg, len, sig.data); + return sig; + } + static inline Signature sign(const Pair& mine, const void* msg, unsigned int len) + { + Signature sig; + sign(mine.priv, mine.pub, msg, len, sig.data); + return sig; + } + + /** + * Verify a message's signature + * + * @param their Public key to verify against + * @param msg Message to verify signature integrity against + * @param len Length of message in bytes + * @param signature 96-byte signature + * @return True if signature is valid and the message is authentic and unmodified + */ + static bool verify(const Public& their, const void* msg, unsigned int len, const void* signature); + + /** + * Verify a message's signature + * + * @param their Public key to verify against + * @param msg Message to verify signature integrity against + * @param len Length of message in bytes + * @param signature 96-byte signature + * @return True if signature is valid and the message is authentic and unmodified + */ + static inline bool verify(const Public& their, const void* msg, unsigned int len, const Signature& signature) + { + return verify(their, msg, len, signature.data); + } + + private: + // derive first 32 bytes of kp.pub from first 32 bytes of kp.priv + // this is the ECDH key + static void _calcPubDH(Pair& kp); + + // derive 2nd 32 bytes of kp.pub from 2nd 32 bytes of kp.priv + // this is the Ed25519 sign/verify key + static void _calcPubED(Pair& kp); +}; + +} // namespace ZeroTier + +#endif + +#endif diff --git a/node/Hashtable.hpp b/node/Hashtable.hpp index 0656246b..280ccfc6 100644 --- a/node/Hashtable.hpp +++ b/node/Hashtable.hpp @@ -16,420 +16,425 @@ #include "Constants.hpp" +#include +#include #include #include #include - -#include -#include #include -#include +#include namespace ZeroTier { /** * A minimal hash table implementation for the ZeroTier core */ -template -class Hashtable -{ -private: - struct _Bucket - { - _Bucket(const K &k,const V &v) : k(k),v(v) {} - _Bucket(const K &k) : k(k),v() {} - _Bucket(const _Bucket &b) : k(b.k),v(b.v) {} - inline _Bucket &operator=(const _Bucket &b) { k = b.k; v = b.v; return *this; } - K k; - V v; - _Bucket *next; // must be set manually for each _Bucket - }; +template class Hashtable { + private: + struct _Bucket { + _Bucket(const K& k, const V& v) : k(k), v(v) + { + } + _Bucket(const K& k) : k(k), v() + { + } + _Bucket(const _Bucket& b) : k(b.k), v(b.v) + { + } + inline _Bucket& operator=(const _Bucket& b) + { + k = b.k; + v = b.v; + return *this; + } + K k; + V v; + _Bucket* next; // must be set manually for each _Bucket + }; -public: - /** - * A simple forward iterator (different from STL) - * - * It's safe to erase the last key, but not others. Don't use set() since that - * may rehash and invalidate the iterator. Note the erasing the key will destroy - * the targets of the pointers returned by next(). - */ - class Iterator - { - public: - /** - * @param ht Hash table to iterate over - */ - Iterator(Hashtable &ht) : - _idx(0), - _ht(&ht), - _b(ht._t[0]) - { - } + public: + /** + * A simple forward iterator (different from STL) + * + * It's safe to erase the last key, but not others. Don't use set() since that + * may rehash and invalidate the iterator. Note the erasing the key will destroy + * the targets of the pointers returned by next(). + */ + class Iterator { + public: + /** + * @param ht Hash table to iterate over + */ + Iterator(Hashtable& ht) : _idx(0), _ht(&ht), _b(ht._t[0]) + { + } - /** - * @param kptr Pointer to set to point to next key - * @param vptr Pointer to set to point to next value - * @return True if kptr and vptr are set, false if no more entries - */ - inline bool next(K *&kptr,V *&vptr) - { - for(;;) { - if (_b) { - kptr = &(_b->k); - vptr = &(_b->v); - _b = _b->next; - return true; - } - ++_idx; - if (_idx >= _ht->_bc) { - return false; - } - _b = _ht->_t[_idx]; - } - } + /** + * @param kptr Pointer to set to point to next key + * @param vptr Pointer to set to point to next value + * @return True if kptr and vptr are set, false if no more entries + */ + inline bool next(K*& kptr, V*& vptr) + { + for (;;) { + if (_b) { + kptr = &(_b->k); + vptr = &(_b->v); + _b = _b->next; + return true; + } + ++_idx; + if (_idx >= _ht->_bc) { + return false; + } + _b = _ht->_t[_idx]; + } + } - private: - unsigned long _idx; - Hashtable *_ht; - _Bucket *_b; - }; - //friend class Hashtable::Iterator; + private: + unsigned long _idx; + Hashtable* _ht; + _Bucket* _b; + }; + // friend class Hashtable::Iterator; - /** - * @param bc Initial capacity in buckets (default: 64, must be nonzero) - */ - Hashtable(unsigned long bc = 64) : - _t(reinterpret_cast<_Bucket **>(::malloc(sizeof(_Bucket *) * bc))), - _bc(bc), - _s(0) - { - if (!_t) { - throw ZT_EXCEPTION_OUT_OF_MEMORY; - } - for(unsigned long i=0;i(::malloc(sizeof(_Bucket*) * bc))), _bc(bc), _s(0) + { + if (! _t) { + throw ZT_EXCEPTION_OUT_OF_MEMORY; + } + for (unsigned long i = 0; i < bc; ++i) { + _t[i] = (_Bucket*)0; + } + } - Hashtable(const Hashtable &ht) : - _t(reinterpret_cast<_Bucket **>(::malloc(sizeof(_Bucket *) * ht._bc))), - _bc(ht._bc), - _s(ht._s) - { - if (!_t) { - throw ZT_EXCEPTION_OUT_OF_MEMORY; - } - for(unsigned long i=0;i<_bc;++i) { - _t[i] = (_Bucket *)0; - } - for(unsigned long i=0;i<_bc;++i) { - const _Bucket *b = ht._t[i]; - while (b) { - _Bucket *nb = new _Bucket(*b); - nb->next = _t[i]; - _t[i] = nb; - b = b->next; - } - } - } + Hashtable(const Hashtable& ht) : _t(reinterpret_cast<_Bucket**>(::malloc(sizeof(_Bucket*) * ht._bc))), _bc(ht._bc), _s(ht._s) + { + if (! _t) { + throw ZT_EXCEPTION_OUT_OF_MEMORY; + } + for (unsigned long i = 0; i < _bc; ++i) { + _t[i] = (_Bucket*)0; + } + for (unsigned long i = 0; i < _bc; ++i) { + const _Bucket* b = ht._t[i]; + while (b) { + _Bucket* nb = new _Bucket(*b); + nb->next = _t[i]; + _t[i] = nb; + b = b->next; + } + } + } - ~Hashtable() - { - this->clear(); - ::free(_t); - } + ~Hashtable() + { + this->clear(); + ::free(_t); + } - inline Hashtable &operator=(const Hashtable &ht) - { - this->clear(); - if (ht._s) { - for(unsigned long i=0;iset(b->k,b->v); - b = b->next; - } - } - } - return *this; - } + inline Hashtable& operator=(const Hashtable& ht) + { + this->clear(); + if (ht._s) { + for (unsigned long i = 0; i < ht._bc; ++i) { + const _Bucket* b = ht._t[i]; + while (b) { + this->set(b->k, b->v); + b = b->next; + } + } + } + return *this; + } - /** - * Erase all entries - */ - inline void clear() - { - if (_s) { - for(unsigned long i=0;i<_bc;++i) { - _Bucket *b = _t[i]; - while (b) { - _Bucket *const nb = b->next; - delete b; - b = nb; - } - _t[i] = (_Bucket *)0; - } - _s = 0; - } - } + /** + * Erase all entries + */ + inline void clear() + { + if (_s) { + for (unsigned long i = 0; i < _bc; ++i) { + _Bucket* b = _t[i]; + while (b) { + _Bucket* const nb = b->next; + delete b; + b = nb; + } + _t[i] = (_Bucket*)0; + } + _s = 0; + } + } - /** - * @return Vector of all keys - */ - inline typename std::vector keys() const - { - typename std::vector k; - if (_s) { - k.reserve(_s); - for(unsigned long i=0;i<_bc;++i) { - _Bucket *b = _t[i]; - while (b) { - k.push_back(b->k); - b = b->next; - } - } - } - return k; - } + /** + * @return Vector of all keys + */ + inline typename std::vector keys() const + { + typename std::vector k; + if (_s) { + k.reserve(_s); + for (unsigned long i = 0; i < _bc; ++i) { + _Bucket* b = _t[i]; + while (b) { + k.push_back(b->k); + b = b->next; + } + } + } + return k; + } - /** - * Append all keys (in unspecified order) to the supplied vector or list - * - * @param v Vector, list, or other compliant container - * @tparam Type of V (generally inferred) - */ - template - inline void appendKeys(C &v) const - { - if (_s) { - for(unsigned long i=0;i<_bc;++i) { - _Bucket *b = _t[i]; - while (b) { - v.push_back(b->k); - b = b->next; - } - } - } - } + /** + * Append all keys (in unspecified order) to the supplied vector or list + * + * @param v Vector, list, or other compliant container + * @tparam Type of V (generally inferred) + */ + template inline void appendKeys(C& v) const + { + if (_s) { + for (unsigned long i = 0; i < _bc; ++i) { + _Bucket* b = _t[i]; + while (b) { + v.push_back(b->k); + b = b->next; + } + } + } + } - /** - * @return Vector of all entries (pairs of K,V) - */ - inline typename std::vector< std::pair > entries() const - { - typename std::vector< std::pair > k; - if (_s) { - k.reserve(_s); - for(unsigned long i=0;i<_bc;++i) { - _Bucket *b = _t[i]; - while (b) { - k.push_back(std::pair(b->k,b->v)); - b = b->next; - } - } - } - return k; - } + /** + * @return Vector of all entries (pairs of K,V) + */ + inline typename std::vector > entries() const + { + typename std::vector > k; + if (_s) { + k.reserve(_s); + for (unsigned long i = 0; i < _bc; ++i) { + _Bucket* b = _t[i]; + while (b) { + k.push_back(std::pair(b->k, b->v)); + b = b->next; + } + } + } + return k; + } - /** - * @param k Key - * @return Pointer to value or NULL if not found - */ - inline V *get(const K &k) - { - _Bucket *b = _t[_hc(k) % _bc]; - while (b) { - if (b->k == k) { - return &(b->v); - } - b = b->next; - } - return (V *)0; - } - inline const V *get(const K &k) const { return const_cast(this)->get(k); } + /** + * @param k Key + * @return Pointer to value or NULL if not found + */ + inline V* get(const K& k) + { + _Bucket* b = _t[_hc(k) % _bc]; + while (b) { + if (b->k == k) { + return &(b->v); + } + b = b->next; + } + return (V*)0; + } + inline const V* get(const K& k) const + { + return const_cast(this)->get(k); + } - /** - * @param k Key - * @param v Value to fill with result - * @return True if value was found and set (if false, v is not modified) - */ - inline bool get(const K &k,V &v) const - { - _Bucket *b = _t[_hc(k) % _bc]; - while (b) { - if (b->k == k) { - v = b->v; - return true; - } - b = b->next; - } - return false; - } + /** + * @param k Key + * @param v Value to fill with result + * @return True if value was found and set (if false, v is not modified) + */ + inline bool get(const K& k, V& v) const + { + _Bucket* b = _t[_hc(k) % _bc]; + while (b) { + if (b->k == k) { + v = b->v; + return true; + } + b = b->next; + } + return false; + } - /** - * @param k Key to check - * @return True if key is present - */ - inline bool contains(const K &k) const - { - _Bucket *b = _t[_hc(k) % _bc]; - while (b) { - if (b->k == k) { - return true; - } - b = b->next; - } - return false; - } + /** + * @param k Key to check + * @return True if key is present + */ + inline bool contains(const K& k) const + { + _Bucket* b = _t[_hc(k) % _bc]; + while (b) { + if (b->k == k) { + return true; + } + b = b->next; + } + return false; + } - /** - * @param k Key - * @return True if value was present - */ - inline bool erase(const K &k) - { - const unsigned long bidx = _hc(k) % _bc; - _Bucket *lastb = (_Bucket *)0; - _Bucket *b = _t[bidx]; - while (b) { - if (b->k == k) { - if (lastb) { - lastb->next = b->next; - } else { - _t[bidx] = b->next; - } - delete b; - --_s; - return true; - } - lastb = b; - b = b->next; - } - return false; - } + /** + * @param k Key + * @return True if value was present + */ + inline bool erase(const K& k) + { + const unsigned long bidx = _hc(k) % _bc; + _Bucket* lastb = (_Bucket*)0; + _Bucket* b = _t[bidx]; + while (b) { + if (b->k == k) { + if (lastb) { + lastb->next = b->next; + } + else { + _t[bidx] = b->next; + } + delete b; + --_s; + return true; + } + lastb = b; + b = b->next; + } + return false; + } - /** - * @param k Key - * @param v Value - * @return Reference to value in table - */ - inline V &set(const K &k,const V &v) - { - const unsigned long h = _hc(k); - unsigned long bidx = h % _bc; + /** + * @param k Key + * @param v Value + * @return Reference to value in table + */ + inline V& set(const K& k, const V& v) + { + const unsigned long h = _hc(k); + unsigned long bidx = h % _bc; - _Bucket *b = _t[bidx]; - while (b) { - if (b->k == k) { - b->v = v; - return b->v; - } - b = b->next; - } + _Bucket* b = _t[bidx]; + while (b) { + if (b->k == k) { + b->v = v; + return b->v; + } + b = b->next; + } - if (_s >= _bc) { - _grow(); - bidx = h % _bc; - } + if (_s >= _bc) { + _grow(); + bidx = h % _bc; + } - b = new _Bucket(k,v); - b->next = _t[bidx]; - _t[bidx] = b; - ++_s; - return b->v; - } + b = new _Bucket(k, v); + b->next = _t[bidx]; + _t[bidx] = b; + ++_s; + return b->v; + } - /** - * @param k Key - * @return Value, possibly newly created - */ - inline V &operator[](const K &k) - { - const unsigned long h = _hc(k); - unsigned long bidx = h % _bc; + /** + * @param k Key + * @return Value, possibly newly created + */ + inline V& operator[](const K& k) + { + const unsigned long h = _hc(k); + unsigned long bidx = h % _bc; - _Bucket *b = _t[bidx]; - while (b) { - if (b->k == k) { - return b->v; - } - b = b->next; - } + _Bucket* b = _t[bidx]; + while (b) { + if (b->k == k) { + return b->v; + } + b = b->next; + } - if (_s >= _bc) { - _grow(); - bidx = h % _bc; - } + if (_s >= _bc) { + _grow(); + bidx = h % _bc; + } - b = new _Bucket(k); - b->next = _t[bidx]; - _t[bidx] = b; - ++_s; - return b->v; - } + b = new _Bucket(k); + b->next = _t[bidx]; + _t[bidx] = b; + ++_s; + return b->v; + } - /** - * @return Number of entries - */ - inline unsigned long size() const { return _s; } + /** + * @return Number of entries + */ + inline unsigned long size() const + { + return _s; + } - /** - * @return True if table is empty - */ - inline bool empty() const { return (_s == 0); } + /** + * @return True if table is empty + */ + inline bool empty() const + { + return (_s == 0); + } -private: - template - static inline unsigned long _hc(const O &obj) - { - return (unsigned long)obj.hashCode(); - } - static inline unsigned long _hc(const uint64_t i) - { - return (unsigned long)(i ^ (i >> 32)); // good for network IDs and addresses - } - static inline unsigned long _hc(const uint32_t i) - { - return ((unsigned long)i * (unsigned long)0x9e3779b1); - } - static inline unsigned long _hc(const uint16_t i) - { - return ((unsigned long)i * (unsigned long)0x9e3779b1); - } - static inline unsigned long _hc(const int i) - { - return ((unsigned long)i * (unsigned long)0x9e3379b1); - } + private: + template static inline unsigned long _hc(const O& obj) + { + return (unsigned long)obj.hashCode(); + } + static inline unsigned long _hc(const uint64_t i) + { + return (unsigned long)(i ^ (i >> 32)); // good for network IDs and addresses + } + static inline unsigned long _hc(const uint32_t i) + { + return ((unsigned long)i * (unsigned long)0x9e3779b1); + } + static inline unsigned long _hc(const uint16_t i) + { + return ((unsigned long)i * (unsigned long)0x9e3779b1); + } + static inline unsigned long _hc(const int i) + { + return ((unsigned long)i * (unsigned long)0x9e3379b1); + } - inline void _grow() - { - const unsigned long nc = _bc * 2; - _Bucket **nt = reinterpret_cast<_Bucket **>(::malloc(sizeof(_Bucket *) * nc)); - if (nt) { - for(unsigned long i=0;inext; - const unsigned long nidx = _hc(b->k) % nc; - b->next = nt[nidx]; - nt[nidx] = b; - b = nb; - } - } - ::free(_t); - _t = nt; - _bc = nc; - } - } + inline void _grow() + { + const unsigned long nc = _bc * 2; + _Bucket** nt = reinterpret_cast<_Bucket**>(::malloc(sizeof(_Bucket*) * nc)); + if (nt) { + for (unsigned long i = 0; i < nc; ++i) { + nt[i] = (_Bucket*)0; + } + for (unsigned long i = 0; i < _bc; ++i) { + _Bucket* b = _t[i]; + while (b) { + _Bucket* const nb = b->next; + const unsigned long nidx = _hc(b->k) % nc; + b->next = nt[nidx]; + nt[nidx] = b; + b = nb; + } + } + ::free(_t); + _t = nt; + _bc = nc; + } + } - _Bucket **_t; - unsigned long _bc; - unsigned long _s; + _Bucket** _t; + unsigned long _bc; + unsigned long _s; }; -} // namespace ZeroTier +} // namespace ZeroTier #endif diff --git a/node/Identity.cpp b/node/Identity.cpp index f47de79c..75649760 100644 --- a/node/Identity.cpp +++ b/node/Identity.cpp @@ -11,194 +11,193 @@ */ /****/ -#include -#include -#include -#include +#include "Identity.hpp" #include "Constants.hpp" -#include "Identity.hpp" +#include "ECC.hpp" #include "SHA512.hpp" #include "Salsa20.hpp" #include "Utils.hpp" +#include +#include +#include +#include + // These can't be changed without a new identity type. They define the // parameters of the hashcash hashing/searching algorithm. #define ZT_IDENTITY_GEN_HASHCASH_FIRST_BYTE_LESS_THAN 17 -#define ZT_IDENTITY_GEN_MEMORY 2097152 +#define ZT_IDENTITY_GEN_MEMORY 2097152 namespace ZeroTier { // A memory-hard composition of SHA-512 and Salsa20 for hashcash hashing -static inline void _computeMemoryHardHash(const void *publicKey,unsigned int publicKeyBytes,void *digest,void *genmem) +static inline void _computeMemoryHardHash(const void* publicKey, unsigned int publicKeyBytes, void* digest, void* genmem) { - // Digest publicKey[] to obtain initial digest - SHA512(digest,publicKey,publicKeyBytes); + // Digest publicKey[] to obtain initial digest + SHA512(digest, publicKey, publicKeyBytes); - // Initialize genmem[] using Salsa20 in a CBC-like configuration since - // ordinary Salsa20 is randomly seek-able. This is good for a cipher - // but is not what we want for sequential memory-hardness. - memset(genmem,0,ZT_IDENTITY_GEN_MEMORY); - Salsa20 s20(digest,(char *)digest + 32); - s20.crypt20((char *)genmem,(char *)genmem,64); - for(unsigned long i=64;idata,ZT_C25519_PRIVATE_KEY_LEN,p); - p += ZT_C25519_PRIVATE_KEY_LEN * 2; - } - *p = (char)0; - return buf; + char* p = buf; + Utils::hex10(_address.toInt(), p); + p += 10; + *(p++) = ':'; + *(p++) = '0'; + *(p++) = ':'; + Utils::hex(_publicKey.data, ZT_ECC_PUBLIC_KEY_SET_LEN, p); + p += ZT_ECC_PUBLIC_KEY_SET_LEN * 2; + if ((_privateKey) && (includePrivate)) { + *(p++) = ':'; + Utils::hex(_privateKey->data, ZT_ECC_PRIVATE_KEY_SET_LEN, p); + p += ZT_ECC_PRIVATE_KEY_SET_LEN * 2; + } + *p = (char)0; + return buf; } -bool Identity::fromString(const char *str) +bool Identity::fromString(const char* str) { - if (!str) { - _address.zero(); - return false; - } - char tmp[ZT_IDENTITY_STRING_BUFFER_LENGTH]; - if (!Utils::scopy(tmp,sizeof(tmp),str)) { - _address.zero(); - return false; - } + if (! str) { + _address.zero(); + return false; + } + char tmp[ZT_IDENTITY_STRING_BUFFER_LENGTH]; + if (! Utils::scopy(tmp, sizeof(tmp), str)) { + _address.zero(); + return false; + } - delete _privateKey; - _privateKey = (C25519::Private *)0; + delete _privateKey; + _privateKey = (ECC::Private*)0; - int fno = 0; - char *saveptr = (char *)0; - for(char *f=Utils::stok(tmp,":",&saveptr);(f);f=Utils::stok((char *)0,":",&saveptr)) { - switch(fno++) { - case 0: - _address = Address(Utils::hexStrToU64(f)); - if (_address.isReserved()) { - _address.zero(); - return false; - } - break; - case 1: - if ((f[0] != '0')||(f[1])) { - _address.zero(); - return false; - } - break; - case 2: - if (Utils::unhex(f,_publicKey.data,ZT_C25519_PUBLIC_KEY_LEN) != ZT_C25519_PUBLIC_KEY_LEN) { - _address.zero(); - return false; - } - break; - case 3: - _privateKey = new C25519::Private(); - if (Utils::unhex(f,_privateKey->data,ZT_C25519_PRIVATE_KEY_LEN) != ZT_C25519_PRIVATE_KEY_LEN) { - _address.zero(); - return false; - } - break; - default: - _address.zero(); - return false; - } - } - if (fno < 3) { - _address.zero(); - return false; - } + int fno = 0; + char* saveptr = (char*)0; + for (char* f = Utils::stok(tmp, ":", &saveptr); (f); f = Utils::stok((char*)0, ":", &saveptr)) { + switch (fno++) { + case 0: + _address = Address(Utils::hexStrToU64(f)); + if (_address.isReserved()) { + _address.zero(); + return false; + } + break; + case 1: + if ((f[0] != '0') || (f[1])) { + _address.zero(); + return false; + } + break; + case 2: + if (Utils::unhex(f, _publicKey.data, ZT_ECC_PUBLIC_KEY_SET_LEN) != ZT_ECC_PUBLIC_KEY_SET_LEN) { + _address.zero(); + return false; + } + break; + case 3: + _privateKey = new ECC::Private(); + if (Utils::unhex(f, _privateKey->data, ZT_ECC_PRIVATE_KEY_SET_LEN) != ZT_ECC_PRIVATE_KEY_SET_LEN) { + _address.zero(); + return false; + } + break; + default: + _address.zero(); + return false; + } + } + if (fno < 3) { + _address.zero(); + return false; + } - return true; + return true; } -} // namespace ZeroTier +} // namespace ZeroTier diff --git a/node/Identity.hpp b/node/Identity.hpp index b7580a80..bf337eb2 100644 --- a/node/Identity.hpp +++ b/node/Identity.hpp @@ -14,16 +14,16 @@ #ifndef ZT_IDENTITY_HPP #define ZT_IDENTITY_HPP +#include "Address.hpp" +#include "Buffer.hpp" +#include "Constants.hpp" +#include "ECC.hpp" +#include "SHA512.hpp" +#include "Utils.hpp" + #include #include -#include "Constants.hpp" -#include "Utils.hpp" -#include "Address.hpp" -#include "C25519.hpp" -#include "Buffer.hpp" -#include "SHA512.hpp" - #define ZT_IDENTITY_STRING_BUFFER_LENGTH 384 namespace ZeroTier { @@ -38,295 +38,318 @@ namespace ZeroTier { * search for a different public key that duplicates an existing address. (See * code for deriveAddress() for this algorithm.) */ -class Identity -{ -public: - Identity() : - _privateKey((C25519::Private *)0) - { - } +class Identity { + public: + Identity() : _privateKey((ECC::Private*)0) + { + } - Identity(const Identity &id) : - _address(id._address), - _publicKey(id._publicKey), - _privateKey((id._privateKey) ? new C25519::Private(*(id._privateKey)) : (C25519::Private *)0) - { - } + Identity(const Identity& id) : _address(id._address), _publicKey(id._publicKey), _privateKey((id._privateKey) ? new ECC::Private(*(id._privateKey)) : (ECC::Private*)0) + { + } - Identity(const char *str) : - _privateKey((C25519::Private *)0) - { - if (!fromString(str)) { - throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_INVALID_TYPE; - } - } + Identity(const char* str) : _privateKey((ECC::Private*)0) + { + if (! fromString(str)) { + throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_INVALID_TYPE; + } + } - template - Identity(const Buffer &b,unsigned int startAt = 0) : - _privateKey((C25519::Private *)0) - { - deserialize(b,startAt); - } + template Identity(const Buffer& b, unsigned int startAt = 0) : _privateKey((ECC::Private*)0) + { + deserialize(b, startAt); + } - ~Identity() - { - if (_privateKey) { - Utils::burn(_privateKey,sizeof(C25519::Private)); - delete _privateKey; - } - } + ~Identity() + { + if (_privateKey) { + Utils::burn(_privateKey, sizeof(ECC::Private)); + delete _privateKey; + } + } - inline Identity &operator=(const Identity &id) - { - _address = id._address; - _publicKey = id._publicKey; - if (id._privateKey) { - if (!_privateKey) { - _privateKey = new C25519::Private(); - } - *_privateKey = *(id._privateKey); - } else { - delete _privateKey; - _privateKey = (C25519::Private *)0; - } - return *this; - } + inline Identity& operator=(const Identity& id) + { + _address = id._address; + _publicKey = id._publicKey; + if (id._privateKey) { + if (! _privateKey) { + _privateKey = new ECC::Private(); + } + *_privateKey = *(id._privateKey); + } + else { + delete _privateKey; + _privateKey = (ECC::Private*)0; + } + return *this; + } - /** - * Generate a new identity (address, key pair) - * - * This is a time consuming operation. - */ - void generate(); + /** + * Generate a new identity (address, key pair) + * + * This is a time consuming operation. + */ + void generate(); - /** - * Check the validity of this identity's pairing of key to address - * - * @return True if validation check passes - */ - bool locallyValidate() const; + /** + * Check the validity of this identity's pairing of key to address + * + * @return True if validation check passes + */ + bool locallyValidate() const; - /** - * @return True if this identity contains a private key - */ - inline bool hasPrivate() const { return (_privateKey != (C25519::Private *)0); } + /** + * @return True if this identity contains a private key + */ + inline bool hasPrivate() const + { + return (_privateKey != (ECC::Private*)0); + } - /** - * Compute a SHA384 hash of this identity's address and public key(s). - * - * @param sha384buf Buffer with 48 bytes of space to receive hash - */ - inline void publicKeyHash(void *sha384buf) const - { - uint8_t address[ZT_ADDRESS_LENGTH]; - _address.copyTo(address, ZT_ADDRESS_LENGTH); - SHA384(sha384buf, address, ZT_ADDRESS_LENGTH, _publicKey.data, ZT_C25519_PUBLIC_KEY_LEN); - } + /** + * Compute a SHA384 hash of this identity's address and public key(s). + * + * @param sha384buf Buffer with 48 bytes of space to receive hash + */ + inline void publicKeyHash(void* sha384buf) const + { + uint8_t address[ZT_ADDRESS_LENGTH]; + _address.copyTo(address, ZT_ADDRESS_LENGTH); + SHA384(sha384buf, address, ZT_ADDRESS_LENGTH, _publicKey.data, ZT_ECC_PUBLIC_KEY_SET_LEN); + } - /** - * Compute the SHA512 hash of our private key (if we have one) - * - * @param sha Buffer to receive SHA512 (MUST be ZT_SHA512_DIGEST_LEN (64) bytes in length) - * @return True on success, false if no private key - */ - inline bool sha512PrivateKey(void *sha) const - { - if (_privateKey) { - SHA512(sha,_privateKey->data,ZT_C25519_PRIVATE_KEY_LEN); - return true; - } - return false; - } + /** + * Compute the SHA512 hash of our private key (if we have one) + * + * @param sha Buffer to receive SHA512 (MUST be ZT_SHA512_DIGEST_LEN (64) bytes in length) + * @return True on success, false if no private key + */ + inline bool sha512PrivateKey(void* sha) const + { + if (_privateKey) { + SHA512(sha, _privateKey->data, ZT_ECC_PRIVATE_KEY_SET_LEN); + return true; + } + return false; + } - /** - * Sign a message with this identity (private key required) - * - * @param data Data to sign - * @param len Length of data - */ - inline C25519::Signature sign(const void *data,unsigned int len) const - { - if (_privateKey) { - return C25519::sign(*_privateKey,_publicKey,data,len); - } - throw ZT_EXCEPTION_PRIVATE_KEY_REQUIRED; - } + /** + * Sign a message with this identity (private key required) + * + * @param data Data to sign + * @param len Length of data + */ + inline ECC::Signature sign(const void* data, unsigned int len) const + { + if (_privateKey) { + return ECC::sign(*_privateKey, _publicKey, data, len); + } + throw ZT_EXCEPTION_PRIVATE_KEY_REQUIRED; + } - /** - * Verify a message signature against this identity - * - * @param data Data to check - * @param len Length of data - * @param signature Signature bytes - * @param siglen Length of signature in bytes - * @return True if signature validates and data integrity checks - */ - inline bool verify(const void *data,unsigned int len,const void *signature,unsigned int siglen) const - { - if (siglen != ZT_C25519_SIGNATURE_LEN) { - return false; - } - return C25519::verify(_publicKey,data,len,signature); - } + /** + * Verify a message signature against this identity + * + * @param data Data to check + * @param len Length of data + * @param signature Signature bytes + * @param siglen Length of signature in bytes + * @return True if signature validates and data integrity checks + */ + inline bool verify(const void* data, unsigned int len, const void* signature, unsigned int siglen) const + { + if (siglen != ZT_ECC_SIGNATURE_LEN) { + return false; + } + return ECC::verify(_publicKey, data, len, signature); + } - /** - * Verify a message signature against this identity - * - * @param data Data to check - * @param len Length of data - * @param signature Signature - * @return True if signature validates and data integrity checks - */ - inline bool verify(const void *data,unsigned int len,const C25519::Signature &signature) const - { - return C25519::verify(_publicKey,data,len,signature); - } + /** + * Verify a message signature against this identity + * + * @param data Data to check + * @param len Length of data + * @param signature Signature + * @return True if signature validates and data integrity checks + */ + inline bool verify(const void* data, unsigned int len, const ECC::Signature& signature) const + { + return ECC::verify(_publicKey, data, len, signature); + } - /** - * Shortcut method to perform key agreement with another identity - * - * This identity must have a private key. (Check hasPrivate()) - * - * @param id Identity to agree with - * @param key Result parameter to fill with key bytes - * @return Was agreement successful? - */ - inline bool agree(const Identity &id,void *const key) const - { - if (_privateKey) { - C25519::agree(*_privateKey,id._publicKey,key,ZT_SYMMETRIC_KEY_SIZE); - return true; - } - return false; - } + /** + * Shortcut method to perform key agreement with another identity + * + * This identity must have a private key. (Check hasPrivate()) + * + * @param id Identity to agree with + * @param key Result parameter to fill with key bytes + * @return Was agreement successful? + */ + inline bool agree(const Identity& id, void* const key) const + { + if (_privateKey) { + ECC::agree(*_privateKey, id._publicKey, key, ZT_SYMMETRIC_KEY_SIZE); + return true; + } + return false; + } - /** - * @return This identity's address - */ - inline const Address &address() const { return _address; } + /** + * @return This identity's address + */ + inline const Address& address() const + { + return _address; + } - /** - * Serialize this identity (binary) - * - * @param b Destination buffer to append to - * @param includePrivate If true, include private key component (if present) (default: false) - * @throws std::out_of_range Buffer too small - */ - template - inline void serialize(Buffer &b,bool includePrivate = false) const - { - _address.appendTo(b); - b.append((uint8_t)0); // C25519/Ed25519 identity type - b.append(_publicKey.data,ZT_C25519_PUBLIC_KEY_LEN); - if ((_privateKey)&&(includePrivate)) { - b.append((unsigned char)ZT_C25519_PRIVATE_KEY_LEN); - b.append(_privateKey->data,ZT_C25519_PRIVATE_KEY_LEN); - } else { - b.append((unsigned char)0); - } - } + /** + * Serialize this identity (binary) + * + * @param b Destination buffer to append to + * @param includePrivate If true, include private key component (if present) (default: false) + * @throws std::out_of_range Buffer too small + */ + template inline void serialize(Buffer& b, bool includePrivate = false) const + { + _address.appendTo(b); + b.append((uint8_t)0); // C25519/Ed25519 identity type + b.append(_publicKey.data, ZT_ECC_PUBLIC_KEY_SET_LEN); + if ((_privateKey) && (includePrivate)) { + b.append((unsigned char)ZT_ECC_PRIVATE_KEY_SET_LEN); + b.append(_privateKey->data, ZT_ECC_PRIVATE_KEY_SET_LEN); + } + else { + b.append((unsigned char)0); + } + } - /** - * Deserialize a binary serialized identity - * - * If an exception is thrown, the Identity object is left in an undefined - * state and should not be used. - * - * @param b Buffer containing serialized data - * @param startAt Index within buffer of serialized data (default: 0) - * @return Length of serialized data read from buffer - * @throws std::out_of_range Serialized data invalid - * @throws std::invalid_argument Serialized data invalid - */ - template - inline unsigned int deserialize(const Buffer &b,unsigned int startAt = 0) - { - delete _privateKey; - _privateKey = (C25519::Private *)0; + /** + * Deserialize a binary serialized identity + * + * If an exception is thrown, the Identity object is left in an undefined + * state and should not be used. + * + * @param b Buffer containing serialized data + * @param startAt Index within buffer of serialized data (default: 0) + * @return Length of serialized data read from buffer + * @throws std::out_of_range Serialized data invalid + * @throws std::invalid_argument Serialized data invalid + */ + template inline unsigned int deserialize(const Buffer& b, unsigned int startAt = 0) + { + delete _privateKey; + _privateKey = (ECC::Private*)0; - unsigned int p = startAt; + unsigned int p = startAt; - _address.setTo(b.field(p,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); - p += ZT_ADDRESS_LENGTH; + _address.setTo(b.field(p, ZT_ADDRESS_LENGTH), ZT_ADDRESS_LENGTH); + p += ZT_ADDRESS_LENGTH; - if (b[p++] != 0) { - throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_INVALID_TYPE; - } + if (b[p++] != 0) { + throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_INVALID_TYPE; + } - memcpy(_publicKey.data,b.field(p,ZT_C25519_PUBLIC_KEY_LEN),ZT_C25519_PUBLIC_KEY_LEN); - p += ZT_C25519_PUBLIC_KEY_LEN; + memcpy(_publicKey.data, b.field(p, ZT_ECC_PUBLIC_KEY_SET_LEN), ZT_ECC_PUBLIC_KEY_SET_LEN); + p += ZT_ECC_PUBLIC_KEY_SET_LEN; - unsigned int privateKeyLength = (unsigned int)b[p++]; - if (privateKeyLength) { - if (privateKeyLength != ZT_C25519_PRIVATE_KEY_LEN) { - throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_INVALID_CRYPTOGRAPHIC_TOKEN; - } - _privateKey = new C25519::Private(); - memcpy(_privateKey->data,b.field(p,ZT_C25519_PRIVATE_KEY_LEN),ZT_C25519_PRIVATE_KEY_LEN); - p += ZT_C25519_PRIVATE_KEY_LEN; - } + unsigned int privateKeyLength = (unsigned int)b[p++]; + if (privateKeyLength) { + if (privateKeyLength != ZT_ECC_PRIVATE_KEY_SET_LEN) { + throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_INVALID_CRYPTOGRAPHIC_TOKEN; + } + _privateKey = new ECC::Private(); + memcpy(_privateKey->data, b.field(p, ZT_ECC_PRIVATE_KEY_SET_LEN), ZT_ECC_PRIVATE_KEY_SET_LEN); + p += ZT_ECC_PRIVATE_KEY_SET_LEN; + } - return (p - startAt); - } + return (p - startAt); + } - /** - * Serialize to a more human-friendly string - * - * @param includePrivate If true, include private key (if it exists) - * @param buf Buffer to store string - * @return ASCII string representation of identity - */ - char *toString(bool includePrivate,char buf[ZT_IDENTITY_STRING_BUFFER_LENGTH]) const; + /** + * Serialize to a more human-friendly string + * + * @param includePrivate If true, include private key (if it exists) + * @param buf Buffer to store string + * @return ASCII string representation of identity + */ + char* toString(bool includePrivate, char buf[ZT_IDENTITY_STRING_BUFFER_LENGTH]) const; - /** - * Deserialize a human-friendly string - * - * Note: validation is for the format only. The locallyValidate() method - * must be used to check signature and address/key correspondence. - * - * @param str String to deserialize - * @return True if deserialization appears successful - */ - bool fromString(const char *str); + /** + * Deserialize a human-friendly string + * + * Note: validation is for the format only. The locallyValidate() method + * must be used to check signature and address/key correspondence. + * + * @param str String to deserialize + * @return True if deserialization appears successful + */ + bool fromString(const char* str); - /** - * @return C25519 public key - */ - inline const C25519::Public &publicKey() const { return _publicKey; } + /** + * @return C25519 public key + */ + inline const ECC::Public& publicKey() const + { + return _publicKey; + } - /** - * @return C25519 key pair (only returns valid pair if private key is present in this Identity object) - */ - inline const C25519::Pair privateKeyPair() const - { - C25519::Pair pair; - pair.pub = _publicKey; - if (_privateKey) { - pair.priv = *_privateKey; - } else { - memset(pair.priv.data,0,ZT_C25519_PRIVATE_KEY_LEN); - } - return pair; - } + /** + * @return C25519 key pair (only returns valid pair if private key is present in this Identity object) + */ + inline const ECC::Pair privateKeyPair() const + { + ECC::Pair pair; + pair.pub = _publicKey; + if (_privateKey) { + pair.priv = *_privateKey; + } + else { + memset(pair.priv.data, 0, ZT_ECC_PRIVATE_KEY_SET_LEN); + } + return pair; + } - /** - * @return True if this identity contains something - */ - inline operator bool() const { return (_address); } + /** + * @return True if this identity contains something + */ + inline operator bool() const + { + return (_address); + } - inline bool operator==(const Identity &id) const { return ((_address == id._address)&&(memcmp(_publicKey.data,id._publicKey.data,ZT_C25519_PUBLIC_KEY_LEN) == 0)); } - inline bool operator<(const Identity &id) const { return ((_address < id._address)||((_address == id._address)&&(memcmp(_publicKey.data,id._publicKey.data,ZT_C25519_PUBLIC_KEY_LEN) < 0))); } - inline bool operator!=(const Identity &id) const { return !(*this == id); } - inline bool operator>(const Identity &id) const { return (id < *this); } - inline bool operator<=(const Identity &id) const { return !(id < *this); } - inline bool operator>=(const Identity &id) const { return !(*this < id); } + inline bool operator==(const Identity& id) const + { + return ((_address == id._address) && (memcmp(_publicKey.data, id._publicKey.data, ZT_ECC_PUBLIC_KEY_SET_LEN) == 0)); + } + inline bool operator<(const Identity& id) const + { + return ((_address < id._address) || ((_address == id._address) && (memcmp(_publicKey.data, id._publicKey.data, ZT_ECC_PUBLIC_KEY_SET_LEN) < 0))); + } + inline bool operator!=(const Identity& id) const + { + return ! (*this == id); + } + inline bool operator>(const Identity& id) const + { + return (id < *this); + } + inline bool operator<=(const Identity& id) const + { + return ! (id < *this); + } + inline bool operator>=(const Identity& id) const + { + return ! (*this < id); + } -private: - Address _address; - C25519::Public _publicKey; - C25519::Private *_privateKey; + private: + Address _address; + ECC::Public _publicKey; + ECC::Private* _privateKey; }; -} // namespace ZeroTier +} // namespace ZeroTier #endif diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index 2537c0fb..2288ac2b 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -11,1489 +11,1479 @@ */ /****/ -#include -#include -#include - -#include "../version.h" -#include "../include/ZeroTierOne.h" - -#include "Constants.hpp" -#include "RuntimeEnvironment.hpp" #include "IncomingPacket.hpp" -#include "Topology.hpp" -#include "Switch.hpp" -#include "Peer.hpp" -#include "NetworkController.hpp" -#include "SelfAwareness.hpp" -#include "Salsa20.hpp" -#include "SHA512.hpp" -#include "World.hpp" -#include "Node.hpp" -#include "CertificateOfMembership.hpp" -#include "Capability.hpp" -#include "Tag.hpp" -#include "Revocation.hpp" -#include "Trace.hpp" -#include "Path.hpp" + +#include "../include/ZeroTierOne.h" +#include "../version.h" #include "Bond.hpp" +#include "Capability.hpp" +#include "CertificateOfMembership.hpp" +#include "Constants.hpp" #include "Metrics.hpp" +#include "NetworkController.hpp" +#include "Node.hpp" #include "PacketMultiplexer.hpp" +#include "Path.hpp" +#include "Peer.hpp" +#include "Revocation.hpp" +#include "RuntimeEnvironment.hpp" +#include "SHA512.hpp" +#include "Salsa20.hpp" +#include "SelfAwareness.hpp" +#include "Switch.hpp" +#include "Tag.hpp" +#include "Topology.hpp" +#include "Trace.hpp" +#include "World.hpp" + +#include +#include +#include namespace ZeroTier { -bool IncomingPacket::tryDecode(const RuntimeEnvironment *RR,void *tPtr,int32_t flowId) +bool IncomingPacket::tryDecode(const RuntimeEnvironment* RR, void* tPtr, int32_t flowId) { - const Address sourceAddress(source()); + const Address sourceAddress(source()); - try { - // Check for trusted paths or unencrypted HELLOs (HELLO is the only packet sent in the clear) - const unsigned int c = cipher(); - if (c == ZT_PROTO_CIPHER_SUITE__NO_CRYPTO_TRUSTED_PATH) { - // If this is marked as a packet via a trusted path, check source address and path ID. - // Obviously if no trusted paths are configured this always returns false and such - // packets are dropped on the floor. - const uint64_t tpid = trustedPathId(); - if (RR->topology->shouldInboundPathBeTrusted(_path->address(),tpid)) { - _authenticated = true; - } else { - RR->t->incomingPacketMessageAuthenticationFailure(tPtr,_path,packetId(),sourceAddress,hops(),"path not trusted"); - return true; - } - } else if ((c == ZT_PROTO_CIPHER_SUITE__C25519_POLY1305_NONE)&&(verb() == Packet::VERB_HELLO)) { - // Only HELLO is allowed in the clear, but will still have a MAC - return _doHELLO(RR,tPtr,false); - } + try { + // Check for trusted paths or unencrypted HELLOs (HELLO is the only packet sent in the clear) + const unsigned int c = cipher(); + if (c == ZT_PROTO_CIPHER_SUITE__NO_CRYPTO_TRUSTED_PATH) { + // If this is marked as a packet via a trusted path, check source address and path ID. + // Obviously if no trusted paths are configured this always returns false and such + // packets are dropped on the floor. + const uint64_t tpid = trustedPathId(); + if (RR->topology->shouldInboundPathBeTrusted(_path->address(), tpid)) { + _authenticated = true; + } + else { + RR->t->incomingPacketMessageAuthenticationFailure(tPtr, _path, packetId(), sourceAddress, hops(), "path not trusted"); + return true; + } + } + else if ((c == ZT_PROTO_CIPHER_SUITE__C25519_POLY1305_NONE) && (verb() == Packet::VERB_HELLO)) { + // Only HELLO is allowed in the clear, but will still have a MAC + return _doHELLO(RR, tPtr, false); + } - const SharedPtr peer(RR->topology->getPeer(tPtr,sourceAddress)); - if (peer) { - if (!_authenticated) { - if (!dearmor(peer->key(), peer->aesKeys())) { - RR->t->incomingPacketMessageAuthenticationFailure(tPtr,_path,packetId(),sourceAddress,hops(),"invalid MAC"); - peer->recordIncomingInvalidPacket(_path); - return true; - } - } + const SharedPtr peer(RR->topology->getPeer(tPtr, sourceAddress)); + if (peer) { + if (! _authenticated) { + if (! dearmor(peer->key(), peer->aesKeys(), RR->identity)) { + RR->t->incomingPacketMessageAuthenticationFailure(tPtr, _path, packetId(), sourceAddress, hops(), "invalid MAC"); + peer->recordIncomingInvalidPacket(_path); + return true; + } + } - if (!uncompress()) { - RR->t->incomingPacketInvalid(tPtr,_path,packetId(),sourceAddress,hops(),Packet::VERB_NOP,"LZ4 decompression failed"); - return true; - } + if (! uncompress()) { + RR->t->incomingPacketInvalid(tPtr, _path, packetId(), sourceAddress, hops(), Packet::VERB_NOP, "LZ4 decompression failed"); + return true; + } - _authenticated = true; - const Packet::Verb v = verb(); + _authenticated = true; + const Packet::Verb v = verb(); - bool r = true; - switch(v) { - //case Packet::VERB_NOP: - default: // ignore unknown verbs, but if they pass auth check they are "received" - Metrics::pkt_nop_in++; - peer->received(tPtr,_path,hops(),packetId(),payloadLength(),v,0,Packet::VERB_NOP,false,0,ZT_QOS_NO_FLOW); - break; - case Packet::VERB_HELLO: - r = _doHELLO(RR, tPtr, true); - break; - case Packet::VERB_ACK: - r = _doACK(RR, tPtr, peer); - break; - case Packet::VERB_QOS_MEASUREMENT: - r = _doQOS_MEASUREMENT(RR, tPtr, peer); - break; - case Packet::VERB_ERROR: - r = _doERROR(RR, tPtr, peer); - break; - case Packet::VERB_OK: - r = _doOK(RR, tPtr, peer); - break; - case Packet::VERB_WHOIS: - r = _doWHOIS(RR, tPtr, peer); - break; - case Packet::VERB_RENDEZVOUS: - r = _doRENDEZVOUS(RR, tPtr, peer); - break; - case Packet::VERB_FRAME: - r = _doFRAME(RR, tPtr, peer, flowId); - break; - case Packet::VERB_EXT_FRAME: - r = _doEXT_FRAME(RR, tPtr, peer, flowId); - break; - case Packet::VERB_ECHO: - r = _doECHO(RR, tPtr, peer); - break; - case Packet::VERB_MULTICAST_LIKE: - r = _doMULTICAST_LIKE(RR, tPtr, peer); - break; - case Packet::VERB_NETWORK_CREDENTIALS: - r = _doNETWORK_CREDENTIALS(RR, tPtr, peer); - break; - case Packet::VERB_NETWORK_CONFIG_REQUEST: - r = _doNETWORK_CONFIG_REQUEST(RR, tPtr, peer); - break; - case Packet::VERB_NETWORK_CONFIG: - r = _doNETWORK_CONFIG(RR, tPtr, peer); - break; - case Packet::VERB_MULTICAST_GATHER: - r = _doMULTICAST_GATHER(RR, tPtr, peer); - break; - case Packet::VERB_MULTICAST_FRAME: - r = _doMULTICAST_FRAME(RR, tPtr, peer); - break; - case Packet::VERB_PUSH_DIRECT_PATHS: - r = _doPUSH_DIRECT_PATHS(RR, tPtr, peer); - break; - case Packet::VERB_USER_MESSAGE: - r = _doUSER_MESSAGE(RR, tPtr, peer); - break; - case Packet::VERB_REMOTE_TRACE: - r = _doREMOTE_TRACE(RR, tPtr, peer); - break; - case Packet::VERB_PATH_NEGOTIATION_REQUEST: - r = _doPATH_NEGOTIATION_REQUEST(RR, tPtr, peer); - break; - } - if (r) { - RR->node->statsLogVerb((unsigned int)v,(unsigned int)size()); - return true; - } - return false; - } else { - RR->sw->requestWhois(tPtr,RR->node->now(),sourceAddress); - return false; - } - } catch ( ... ) { - RR->t->incomingPacketInvalid(tPtr,_path,packetId(),sourceAddress,hops(),verb(),"unexpected exception in tryDecode()"); - return true; - } + bool r = true; + switch (v) { + // case Packet::VERB_NOP: + default: // ignore unknown verbs, but if they pass auth check they are "received" + Metrics::pkt_nop_in++; + peer->received(tPtr, _path, hops(), packetId(), payloadLength(), v, 0, Packet::VERB_NOP, false, 0, ZT_QOS_NO_FLOW); + break; + case Packet::VERB_HELLO: + r = _doHELLO(RR, tPtr, true); + break; + case Packet::VERB_ACK: + r = _doACK(RR, tPtr, peer); + break; + case Packet::VERB_QOS_MEASUREMENT: + r = _doQOS_MEASUREMENT(RR, tPtr, peer); + break; + case Packet::VERB_ERROR: + r = _doERROR(RR, tPtr, peer); + break; + case Packet::VERB_OK: + r = _doOK(RR, tPtr, peer); + break; + case Packet::VERB_WHOIS: + r = _doWHOIS(RR, tPtr, peer); + break; + case Packet::VERB_RENDEZVOUS: + r = _doRENDEZVOUS(RR, tPtr, peer); + break; + case Packet::VERB_FRAME: + r = _doFRAME(RR, tPtr, peer, flowId); + break; + case Packet::VERB_EXT_FRAME: + r = _doEXT_FRAME(RR, tPtr, peer, flowId); + break; + case Packet::VERB_ECHO: + r = _doECHO(RR, tPtr, peer); + break; + case Packet::VERB_MULTICAST_LIKE: + r = _doMULTICAST_LIKE(RR, tPtr, peer); + break; + case Packet::VERB_NETWORK_CREDENTIALS: + r = _doNETWORK_CREDENTIALS(RR, tPtr, peer); + break; + case Packet::VERB_NETWORK_CONFIG_REQUEST: + r = _doNETWORK_CONFIG_REQUEST(RR, tPtr, peer); + break; + case Packet::VERB_NETWORK_CONFIG: + r = _doNETWORK_CONFIG(RR, tPtr, peer); + break; + case Packet::VERB_MULTICAST_GATHER: + r = _doMULTICAST_GATHER(RR, tPtr, peer); + break; + case Packet::VERB_MULTICAST_FRAME: + r = _doMULTICAST_FRAME(RR, tPtr, peer); + break; + case Packet::VERB_PUSH_DIRECT_PATHS: + r = _doPUSH_DIRECT_PATHS(RR, tPtr, peer); + break; + case Packet::VERB_USER_MESSAGE: + r = _doUSER_MESSAGE(RR, tPtr, peer); + break; + case Packet::VERB_REMOTE_TRACE: + r = _doREMOTE_TRACE(RR, tPtr, peer); + break; + case Packet::VERB_PATH_NEGOTIATION_REQUEST: + r = _doPATH_NEGOTIATION_REQUEST(RR, tPtr, peer); + break; + } + if (r) { + RR->node->statsLogVerb((unsigned int)v, (unsigned int)size()); + return true; + } + return false; + } + else { + RR->sw->requestWhois(tPtr, RR->node->now(), sourceAddress); + return false; + } + } + catch (...) { + RR->t->incomingPacketInvalid(tPtr, _path, packetId(), sourceAddress, hops(), verb(), "unexpected exception in tryDecode()"); + return true; + } } -bool IncomingPacket::_doERROR(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer) +bool IncomingPacket::_doERROR(const RuntimeEnvironment* RR, void* tPtr, const SharedPtr& peer) { - const Packet::Verb inReVerb = (Packet::Verb)(*this)[ZT_PROTO_VERB_ERROR_IDX_IN_RE_VERB]; - const uint64_t inRePacketId = at(ZT_PROTO_VERB_ERROR_IDX_IN_RE_PACKET_ID); - const Packet::ErrorCode errorCode = (Packet::ErrorCode)(*this)[ZT_PROTO_VERB_ERROR_IDX_ERROR_CODE]; - uint64_t networkId = 0; + const Packet::Verb inReVerb = (Packet::Verb)(*this)[ZT_PROTO_VERB_ERROR_IDX_IN_RE_VERB]; + const uint64_t inRePacketId = at(ZT_PROTO_VERB_ERROR_IDX_IN_RE_PACKET_ID); + const Packet::ErrorCode errorCode = (Packet::ErrorCode)(*this)[ZT_PROTO_VERB_ERROR_IDX_ERROR_CODE]; + uint64_t networkId = 0; - Metrics::pkt_error_in++; + Metrics::pkt_error_in++; - /* Security note: we do not gate doERROR() with expectingReplyTo() to - * avoid having to log every outgoing packet ID. Instead we put the - * logic to determine whether we should consider an ERROR in each - * error handler. In most cases these are only trusted in specific - * circumstances. */ + /* Security note: we do not gate doERROR() with expectingReplyTo() to + * avoid having to log every outgoing packet ID. Instead we put the + * logic to determine whether we should consider an ERROR in each + * error handler. In most cases these are only trusted in specific + * circumstances. */ - switch(errorCode) { + switch (errorCode) { + case Packet::ERROR_OBJ_NOT_FOUND: + // Object not found, currently only meaningful from network controllers. + if (inReVerb == Packet::VERB_NETWORK_CONFIG_REQUEST) { + const SharedPtr network(RR->node->network(at(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD))); + if ((network) && (network->controller() == peer->address())) { + network->setNotFound(tPtr); + } + } + Metrics::pkt_error_obj_not_found_in++; + break; - case Packet::ERROR_OBJ_NOT_FOUND: - // Object not found, currently only meaningful from network controllers. - if (inReVerb == Packet::VERB_NETWORK_CONFIG_REQUEST) { - const SharedPtr network(RR->node->network(at(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD))); - if ((network)&&(network->controller() == peer->address())) { - network->setNotFound(tPtr); - } - } - Metrics::pkt_error_obj_not_found_in++; - break; + case Packet::ERROR_UNSUPPORTED_OPERATION: + // This can be sent in response to any operation, though right now we only + // consider it meaningful from network controllers. This would indicate + // that the queried node does not support acting as a controller. + if (inReVerb == Packet::VERB_NETWORK_CONFIG_REQUEST) { + const SharedPtr network(RR->node->network(at(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD))); + if ((network) && (network->controller() == peer->address())) { + network->setNotFound(tPtr); + } + } + Metrics::pkt_error_unsupported_op_in++; + break; - case Packet::ERROR_UNSUPPORTED_OPERATION: - // This can be sent in response to any operation, though right now we only - // consider it meaningful from network controllers. This would indicate - // that the queried node does not support acting as a controller. - if (inReVerb == Packet::VERB_NETWORK_CONFIG_REQUEST) { - const SharedPtr network(RR->node->network(at(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD))); - if ((network)&&(network->controller() == peer->address())) { - network->setNotFound(tPtr); - } - } - Metrics::pkt_error_unsupported_op_in++; - break; + case Packet::ERROR_IDENTITY_COLLISION: + // FIXME: for federation this will need a payload with a signature or something. + if (RR->topology->isUpstream(peer->identity())) { + RR->node->postEvent(tPtr, ZT_EVENT_FATAL_ERROR_IDENTITY_COLLISION); + } + Metrics::pkt_error_identity_collision_in++; + break; - case Packet::ERROR_IDENTITY_COLLISION: - // FIXME: for federation this will need a payload with a signature or something. - if (RR->topology->isUpstream(peer->identity())) { - RR->node->postEvent(tPtr,ZT_EVENT_FATAL_ERROR_IDENTITY_COLLISION); - } - Metrics::pkt_error_identity_collision_in++; - break; + case Packet::ERROR_NEED_MEMBERSHIP_CERTIFICATE: { + // Peers can send this in response to frames if they do not have a recent enough COM from us + networkId = at(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD); + const SharedPtr network(RR->node->network(networkId)); + const int64_t now = RR->node->now(); + if ((network) && (network->config().com)) { + network->peerRequestedCredentials(tPtr, peer->address(), now); + } + Metrics::pkt_error_need_membership_cert_in++; + } break; - case Packet::ERROR_NEED_MEMBERSHIP_CERTIFICATE: { - // Peers can send this in response to frames if they do not have a recent enough COM from us - networkId = at(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD); - const SharedPtr network(RR->node->network(networkId)); - const int64_t now = RR->node->now(); - if ((network)&&(network->config().com)) { - network->peerRequestedCredentials(tPtr,peer->address(),now); - } - Metrics::pkt_error_need_membership_cert_in++; - } break; + case Packet::ERROR_NETWORK_ACCESS_DENIED_: { + // Network controller: network access denied. + const SharedPtr network(RR->node->network(at(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD))); + if ((network) && (network->controller() == peer->address())) { + network->setAccessDenied(tPtr); + } + Metrics::pkt_error_network_access_denied_in++; + } break; - case Packet::ERROR_NETWORK_ACCESS_DENIED_: { - // Network controller: network access denied. - const SharedPtr network(RR->node->network(at(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD))); - if ((network)&&(network->controller() == peer->address())) { - network->setAccessDenied(tPtr); - } - Metrics::pkt_error_network_access_denied_in++; - } break; + case Packet::ERROR_UNWANTED_MULTICAST: { + // Members of networks can use this error to indicate that they no longer + // want to receive multicasts on a given channel. + networkId = at(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD); + const SharedPtr network(RR->node->network(networkId)); + if ((network) && (network->gate(tPtr, peer))) { + const MulticastGroup mg(MAC(field(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD + 8, 6), 6), at(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD + 14)); + RR->mc->remove(network->id(), mg, peer->address()); + } + Metrics::pkt_error_unwanted_multicast_in++; + } break; - case Packet::ERROR_UNWANTED_MULTICAST: { - // Members of networks can use this error to indicate that they no longer - // want to receive multicasts on a given channel. - networkId = at(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD); - const SharedPtr network(RR->node->network(networkId)); - if ((network)&&(network->gate(tPtr,peer))) { - const MulticastGroup mg(MAC(field(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD + 8,6),6),at(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD + 14)); - RR->mc->remove(network->id(),mg,peer->address()); - } - Metrics::pkt_error_unwanted_multicast_in++; - } break; + case Packet::ERROR_NETWORK_AUTHENTICATION_REQUIRED: { + // fprintf(stderr, "\nPacket::ERROR_NETWORK_AUTHENTICATION_REQUIRED\n\n"); + const SharedPtr network(RR->node->network(at(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD))); + if ((network) && (network->controller() == peer->address())) { + int s = (int)size() - (ZT_PROTO_VERB_ERROR_IDX_PAYLOAD + 8); + if (s > 2) { + const uint16_t errorDataSize = at(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD + 8); + s -= 2; + if (s >= (int)errorDataSize) { + Dictionary<8192> authInfo(((const char*)this->data()) + (ZT_PROTO_VERB_ERROR_IDX_PAYLOAD + 10), errorDataSize); - case Packet::ERROR_NETWORK_AUTHENTICATION_REQUIRED: { - //fprintf(stderr, "\nPacket::ERROR_NETWORK_AUTHENTICATION_REQUIRED\n\n"); - const SharedPtr network(RR->node->network(at(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD))); - if ((network)&&(network->controller() == peer->address())) { - int s = (int)size() - (ZT_PROTO_VERB_ERROR_IDX_PAYLOAD + 8); - if (s > 2) { - const uint16_t errorDataSize = at(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD + 8); - s -= 2; - if (s >= (int)errorDataSize) { - Dictionary<8192> authInfo(((const char *)this->data()) + (ZT_PROTO_VERB_ERROR_IDX_PAYLOAD + 10), errorDataSize); + uint64_t authVer = authInfo.getUI(ZT_AUTHINFO_DICT_KEY_VERSION, 0ULL); - uint64_t authVer = authInfo.getUI(ZT_AUTHINFO_DICT_KEY_VERSION, 0ULL); + if (authVer == 0) { + char authenticationURL[2048]; - if (authVer == 0) { - char authenticationURL[2048]; + if (authInfo.get(ZT_AUTHINFO_DICT_KEY_AUTHENTICATION_URL, authenticationURL, sizeof(authenticationURL)) > 0) { + authenticationURL[sizeof(authenticationURL) - 1] = 0; // ensure always zero terminated + network->setAuthenticationRequired(tPtr, authenticationURL); + } + } + else if (authVer == 1) { + char issuerURL[2048] = { 0 }; + char centralAuthURL[2048] = { 0 }; + char ssoNonce[64] = { 0 }; + char ssoState[128] = { 0 }; + char ssoClientID[256] = { 0 }; + char ssoProvider[64] = { 0 }; - if (authInfo.get(ZT_AUTHINFO_DICT_KEY_AUTHENTICATION_URL, authenticationURL, sizeof(authenticationURL)) > 0) { - authenticationURL[sizeof(authenticationURL) - 1] = 0; // ensure always zero terminated - network->setAuthenticationRequired(tPtr, authenticationURL); - } - } else if (authVer == 1) { - char issuerURL[2048] = { 0 }; - char centralAuthURL[2048] = { 0 }; - char ssoNonce[64] = { 0 }; - char ssoState[128] = {0}; - char ssoClientID[256] = { 0 }; - char ssoProvider[64] = { 0 }; + if (authInfo.get(ZT_AUTHINFO_DICT_KEY_ISSUER_URL, issuerURL, sizeof(issuerURL)) > 0) { + issuerURL[sizeof(issuerURL) - 1] = 0; + } + if (authInfo.get(ZT_AUTHINFO_DICT_KEY_CENTRAL_ENDPOINT_URL, centralAuthURL, sizeof(centralAuthURL)) > 0) { + centralAuthURL[sizeof(centralAuthURL) - 1] = 0; + } + if (authInfo.get(ZT_AUTHINFO_DICT_KEY_NONCE, ssoNonce, sizeof(ssoNonce)) > 0) { + ssoNonce[sizeof(ssoNonce) - 1] = 0; + } + if (authInfo.get(ZT_AUTHINFO_DICT_KEY_STATE, ssoState, sizeof(ssoState)) > 0) { + ssoState[sizeof(ssoState) - 1] = 0; + } + if (authInfo.get(ZT_AUTHINFO_DICT_KEY_CLIENT_ID, ssoClientID, sizeof(ssoClientID)) > 0) { + ssoClientID[sizeof(ssoClientID) - 1] = 0; + } + if (authInfo.get(ZT_AUTHINFO_DICT_KEY_SSO_PROVIDER, ssoProvider, sizeof(ssoProvider)) > 0) { + ssoProvider[sizeof(ssoProvider) - 1] = 0; + } + else { + strncpy(ssoProvider, "default", sizeof(ssoProvider)); + } - if (authInfo.get(ZT_AUTHINFO_DICT_KEY_ISSUER_URL, issuerURL, sizeof(issuerURL)) > 0) { - issuerURL[sizeof(issuerURL) - 1] = 0; - } - if (authInfo.get(ZT_AUTHINFO_DICT_KEY_CENTRAL_ENDPOINT_URL, centralAuthURL, sizeof(centralAuthURL))>0) { - centralAuthURL[sizeof(centralAuthURL) - 1] = 0; - } - if (authInfo.get(ZT_AUTHINFO_DICT_KEY_NONCE, ssoNonce, sizeof(ssoNonce)) > 0) { - ssoNonce[sizeof(ssoNonce) - 1] = 0; - } - if (authInfo.get(ZT_AUTHINFO_DICT_KEY_STATE, ssoState, sizeof(ssoState)) > 0) { - ssoState[sizeof(ssoState) - 1] = 0; - } - if (authInfo.get(ZT_AUTHINFO_DICT_KEY_CLIENT_ID, ssoClientID, sizeof(ssoClientID)) > 0) { - ssoClientID[sizeof(ssoClientID) - 1] = 0; - } - if (authInfo.get(ZT_AUTHINFO_DICT_KEY_SSO_PROVIDER, ssoProvider, sizeof(ssoProvider)) > 0 ) { - ssoProvider[sizeof(ssoProvider) - 1] = 0; - } else { - strncpy(ssoProvider, "default", sizeof(ssoProvider)); - } + network->setAuthenticationRequired(tPtr, issuerURL, centralAuthURL, ssoClientID, ssoProvider, ssoNonce, ssoState); + } + } + } + else { + network->setAuthenticationRequired(tPtr, ""); + } + } + Metrics::pkt_error_authentication_required_in++; + } break; - network->setAuthenticationRequired(tPtr, issuerURL, centralAuthURL, ssoClientID, ssoProvider, ssoNonce, ssoState); - } - } - } else { - network->setAuthenticationRequired(tPtr, ""); - } - } - Metrics::pkt_error_authentication_required_in++; - } break; + default: + break; + } - default: - break; - } + peer->received(tPtr, _path, hops(), packetId(), payloadLength(), Packet::VERB_ERROR, inRePacketId, inReVerb, false, networkId, ZT_QOS_NO_FLOW); - peer->received(tPtr,_path,hops(),packetId(),payloadLength(),Packet::VERB_ERROR,inRePacketId,inReVerb,false,networkId,ZT_QOS_NO_FLOW); - - return true; + return true; } bool IncomingPacket::_doACK(const RuntimeEnvironment* RR, void* tPtr, const SharedPtr& peer) { - /* - if (! peer->rateGateACK(RR->node->now())) { - return true; - } - int32_t ackedBytes; - if (payloadLength() != sizeof(ackedBytes)) { - return true; // ignore - } - memcpy(&ackedBytes, payload(), sizeof(ackedBytes)); - peer->receivedAck(_path, RR->node->now(), Utils::ntoh(ackedBytes)); - */ - Metrics::pkt_ack_in++; - return true; + /* + if (! peer->rateGateACK(RR->node->now())) { + return true; + } + int32_t ackedBytes; + if (payloadLength() != sizeof(ackedBytes)) { + return true; // ignore + } + memcpy(&ackedBytes, payload(), sizeof(ackedBytes)); + peer->receivedAck(_path, RR->node->now(), Utils::ntoh(ackedBytes)); + */ + Metrics::pkt_ack_in++; + return true; } bool IncomingPacket::_doQOS_MEASUREMENT(const RuntimeEnvironment* RR, void* tPtr, const SharedPtr& peer) { - Metrics::pkt_qos_in++; - if (! peer->rateGateQoS(RR->node->now(), _path)) { - return true; - } - if (payloadLength() > ZT_QOS_MAX_PACKET_SIZE || payloadLength() < ZT_QOS_MIN_PACKET_SIZE) { - return true; // ignore - } - const int64_t now = RR->node->now(); - uint64_t rx_id[ZT_QOS_TABLE_SIZE]; - uint16_t rx_ts[ZT_QOS_TABLE_SIZE]; - char* begin = (char*)payload(); - char* ptr = begin; - int count = 0; - unsigned int len = payloadLength(); - // Read packet IDs and latency compensation intervals for each packet tracked by this QoS packet - while (ptr < (begin + len) && (count < ZT_QOS_TABLE_SIZE)) { - memcpy((void*)&rx_id[count], ptr, sizeof(uint64_t)); - ptr += sizeof(uint64_t); - memcpy((void*)&rx_ts[count], ptr, sizeof(uint16_t)); - ptr += sizeof(uint16_t); - count++; - } - peer->receivedQoS(_path, now, count, rx_id, rx_ts); - return true; + Metrics::pkt_qos_in++; + if (! peer->rateGateQoS(RR->node->now(), _path)) { + return true; + } + if (payloadLength() > ZT_QOS_MAX_PACKET_SIZE || payloadLength() < ZT_QOS_MIN_PACKET_SIZE) { + return true; // ignore + } + const int64_t now = RR->node->now(); + uint64_t rx_id[ZT_QOS_TABLE_SIZE]; + uint16_t rx_ts[ZT_QOS_TABLE_SIZE]; + char* begin = (char*)payload(); + char* ptr = begin; + int count = 0; + unsigned int len = payloadLength(); + // Read packet IDs and latency compensation intervals for each packet tracked by this QoS packet + while (ptr < (begin + len) && (count < ZT_QOS_TABLE_SIZE)) { + memcpy((void*)&rx_id[count], ptr, sizeof(uint64_t)); + ptr += sizeof(uint64_t); + memcpy((void*)&rx_ts[count], ptr, sizeof(uint16_t)); + ptr += sizeof(uint16_t); + count++; + } + peer->receivedQoS(_path, now, count, rx_id, rx_ts); + return true; } -bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,void *tPtr,const bool alreadyAuthenticated) +bool IncomingPacket::_doHELLO(const RuntimeEnvironment* RR, void* tPtr, const bool alreadyAuthenticated) { - Metrics::pkt_hello_in++; - const int64_t now = RR->node->now(); + Metrics::pkt_hello_in++; + const int64_t now = RR->node->now(); - const uint64_t pid = packetId(); - const Address fromAddress(source()); - const unsigned int protoVersion = (*this)[ZT_PROTO_VERB_HELLO_IDX_PROTOCOL_VERSION]; - const unsigned int vMajor = (*this)[ZT_PROTO_VERB_HELLO_IDX_MAJOR_VERSION]; - const unsigned int vMinor = (*this)[ZT_PROTO_VERB_HELLO_IDX_MINOR_VERSION]; - const unsigned int vRevision = at(ZT_PROTO_VERB_HELLO_IDX_REVISION); - const int64_t timestamp = at(ZT_PROTO_VERB_HELLO_IDX_TIMESTAMP); - Identity id; - unsigned int ptr = ZT_PROTO_VERB_HELLO_IDX_IDENTITY + id.deserialize(*this,ZT_PROTO_VERB_HELLO_IDX_IDENTITY); + const uint64_t pid = packetId(); + const Address fromAddress(source()); + const unsigned int protoVersion = (*this)[ZT_PROTO_VERB_HELLO_IDX_PROTOCOL_VERSION]; + const unsigned int vMajor = (*this)[ZT_PROTO_VERB_HELLO_IDX_MAJOR_VERSION]; + const unsigned int vMinor = (*this)[ZT_PROTO_VERB_HELLO_IDX_MINOR_VERSION]; + const unsigned int vRevision = at(ZT_PROTO_VERB_HELLO_IDX_REVISION); + const int64_t timestamp = at(ZT_PROTO_VERB_HELLO_IDX_TIMESTAMP); + Identity id; + unsigned int ptr = ZT_PROTO_VERB_HELLO_IDX_IDENTITY + id.deserialize(*this, ZT_PROTO_VERB_HELLO_IDX_IDENTITY); - if (protoVersion < ZT_PROTO_VERSION_MIN) { - RR->t->incomingPacketDroppedHELLO(tPtr,_path,pid,fromAddress,"protocol version too old"); - return true; - } - if (fromAddress != id.address()) { - RR->t->incomingPacketDroppedHELLO(tPtr,_path,pid,fromAddress,"identity/address mismatch"); - return true; - } + if (protoVersion < ZT_PROTO_VERSION_MIN) { + RR->t->incomingPacketDroppedHELLO(tPtr, _path, pid, fromAddress, "protocol version too old"); + return true; + } + if (fromAddress != id.address()) { + RR->t->incomingPacketDroppedHELLO(tPtr, _path, pid, fromAddress, "identity/address mismatch"); + return true; + } - SharedPtr peer(RR->topology->getPeer(tPtr,id.address())); - if (peer) { - // We already have an identity with this address -- check for collisions - if (!alreadyAuthenticated) { - if (peer->identity() != id) { - // Identity is different from the one we already have -- address collision + SharedPtr peer(RR->topology->getPeer(tPtr, id.address())); + if (peer) { + // We already have an identity with this address -- check for collisions + if (! alreadyAuthenticated) { + if (peer->identity() != id) { + // Identity is different from the one we already have -- address collision - // Check rate limits - if (!RR->node->rateGateIdentityVerification(now,_path->address())) { - return true; - } + // Check rate limits + if (! RR->node->rateGateIdentityVerification(now, _path->address())) { + return true; + } - uint8_t key[ZT_SYMMETRIC_KEY_SIZE]; - if (RR->identity.agree(id,key)) { - if (dearmor(key, peer->aesKeysIfSupported())) { // ensure packet is authentic, otherwise drop - RR->t->incomingPacketDroppedHELLO(tPtr,_path,pid,fromAddress,"address collision"); - Packet outp(id.address(),RR->identity.address(),Packet::VERB_ERROR); - outp.append((uint8_t)Packet::VERB_HELLO); - outp.append((uint64_t)pid); - outp.append((uint8_t)Packet::ERROR_IDENTITY_COLLISION); - outp.armor(key,true,peer->aesKeysIfSupported()); - Metrics::pkt_error_out++; - Metrics::pkt_error_identity_collision_out++; - _path->send(RR,tPtr,outp.data(),outp.size(),RR->node->now()); - } else { - RR->t->incomingPacketMessageAuthenticationFailure(tPtr,_path,pid,fromAddress,hops(),"invalid MAC"); - } - } else { - RR->t->incomingPacketMessageAuthenticationFailure(tPtr,_path,pid,fromAddress,hops(),"invalid identity"); - } + uint8_t key[ZT_SYMMETRIC_KEY_SIZE]; + if (RR->identity.agree(id, key)) { + if (dearmor(key, peer->aesKeysIfSupported(), RR->identity)) { // ensure packet is authentic, otherwise drop + RR->t->incomingPacketDroppedHELLO(tPtr, _path, pid, fromAddress, "address collision"); + Packet outp(id.address(), RR->identity.address(), Packet::VERB_ERROR); + outp.append((uint8_t)Packet::VERB_HELLO); + outp.append((uint64_t)pid); + outp.append((uint8_t)Packet::ERROR_IDENTITY_COLLISION); + outp.armor(key, true, false, peer->aesKeysIfSupported(), peer->identity()); + Metrics::pkt_error_out++; + Metrics::pkt_error_identity_collision_out++; + _path->send(RR, tPtr, outp.data(), outp.size(), RR->node->now()); + } + else { + RR->t->incomingPacketMessageAuthenticationFailure(tPtr, _path, pid, fromAddress, hops(), "invalid MAC"); + } + } + else { + RR->t->incomingPacketMessageAuthenticationFailure(tPtr, _path, pid, fromAddress, hops(), "invalid identity"); + } - return true; - } else { - // Identity is the same as the one we already have -- check packet integrity + return true; + } + else { + // Identity is the same as the one we already have -- check packet integrity - if (!dearmor(peer->key(), peer->aesKeysIfSupported())) { - RR->t->incomingPacketMessageAuthenticationFailure(tPtr,_path,pid,fromAddress,hops(),"invalid MAC"); - return true; - } + if (! dearmor(peer->key(), peer->aesKeysIfSupported(), RR->identity)) { + RR->t->incomingPacketMessageAuthenticationFailure(tPtr, _path, pid, fromAddress, hops(), "invalid MAC"); + return true; + } - // Continue at // VALID - } - } // else if alreadyAuthenticated then continue at // VALID - } else { - // We don't already have an identity with this address -- validate and learn it + // Continue at // VALID + } + } // else if alreadyAuthenticated then continue at // VALID + } + else { + // We don't already have an identity with this address -- validate and learn it - // Sanity check: this basically can't happen - if (alreadyAuthenticated) { - RR->t->incomingPacketDroppedHELLO(tPtr,_path,pid,fromAddress,"illegal alreadyAuthenticated state"); - return true; - } + // Sanity check: this basically can't happen + if (alreadyAuthenticated) { + RR->t->incomingPacketDroppedHELLO(tPtr, _path, pid, fromAddress, "illegal alreadyAuthenticated state"); + return true; + } - // Check rate limits - if (!RR->node->rateGateIdentityVerification(now,_path->address())) { - RR->t->incomingPacketDroppedHELLO(tPtr,_path,pid,fromAddress,"rate limit exceeded"); - return true; - } + // Check rate limits + if (! RR->node->rateGateIdentityVerification(now, _path->address())) { + RR->t->incomingPacketDroppedHELLO(tPtr, _path, pid, fromAddress, "rate limit exceeded"); + return true; + } - // Check packet integrity and MAC (this is faster than locallyValidate() so do it first to filter out total crap) - SharedPtr newPeer(new Peer(RR,RR->identity,id)); - if (!dearmor(newPeer->key(), newPeer->aesKeysIfSupported())) { - RR->t->incomingPacketMessageAuthenticationFailure(tPtr,_path,pid,fromAddress,hops(),"invalid MAC"); - return true; - } + // Check packet integrity and MAC (this is faster than locallyValidate() so do it first to filter out total crap) + SharedPtr newPeer(new Peer(RR, RR->identity, id)); + if (! dearmor(newPeer->key(), newPeer->aesKeysIfSupported(), RR->identity)) { + RR->t->incomingPacketMessageAuthenticationFailure(tPtr, _path, pid, fromAddress, hops(), "invalid MAC"); + return true; + } - // Check that identity's address is valid as per the derivation function - if (!id.locallyValidate()) { - RR->t->incomingPacketDroppedHELLO(tPtr,_path,pid,fromAddress,"invalid identity"); - return true; - } + // Check that identity's address is valid as per the derivation function + if (! id.locallyValidate()) { + RR->t->incomingPacketDroppedHELLO(tPtr, _path, pid, fromAddress, "invalid identity"); + return true; + } - peer = RR->topology->addPeer(tPtr,newPeer); + peer = RR->topology->addPeer(tPtr, newPeer); - // Continue at // VALID - } + // Continue at // VALID + } - // VALID -- if we made it here, packet passed identity and authenticity checks! + // VALID -- if we made it here, packet passed identity and authenticity checks! - // Get external surface address if present (was not in old versions) - InetAddress externalSurfaceAddress; - if (ptr < size()) { - ptr += externalSurfaceAddress.deserialize(*this,ptr); - if ((externalSurfaceAddress)&&(hops() == 0)) { - RR->sa->iam(tPtr,id.address(),_path->localSocket(),_path->address(),externalSurfaceAddress,RR->topology->isUpstream(id),now); - } - } + // Get external surface address if present (was not in old versions) + InetAddress externalSurfaceAddress; + if (ptr < size()) { + ptr += externalSurfaceAddress.deserialize(*this, ptr); + if ((externalSurfaceAddress) && (hops() == 0)) { + RR->sa->iam(tPtr, id.address(), _path->localSocket(), _path->address(), externalSurfaceAddress, RR->topology->isUpstream(id), now); + } + } - // Get primary planet world ID and world timestamp if present - uint64_t planetWorldId = 0; - uint64_t planetWorldTimestamp = 0; - if ((ptr + 16) <= size()) { - planetWorldId = at(ptr); - ptr += 8; - planetWorldTimestamp = at(ptr); - ptr += 8; - } + // Get primary planet world ID and world timestamp if present + uint64_t planetWorldId = 0; + uint64_t planetWorldTimestamp = 0; + if ((ptr + 16) <= size()) { + planetWorldId = at(ptr); + ptr += 8; + planetWorldTimestamp = at(ptr); + ptr += 8; + } - std::vector< std::pair > moonIdsAndTimestamps; - if (ptr < size()) { - // Remainder of packet, if present, is encrypted - cryptField(peer->key(),ptr,size() - ptr); + std::vector > moonIdsAndTimestamps; + if (ptr < size()) { + // Remainder of packet, if present, is encrypted + cryptField(peer->key(), ptr, size() - ptr); - // Get moon IDs and timestamps if present - if ((ptr + 2) <= size()) { - const unsigned int numMoons = at(ptr); - ptr += 2; - for(unsigned int i=0;i(at(ptr),at(ptr + 8))); - } - ptr += 16; - } - } - } + // Get moon IDs and timestamps if present + if ((ptr + 2) <= size()) { + const unsigned int numMoons = at(ptr); + ptr += 2; + for (unsigned int i = 0; i < numMoons; ++i) { + if ((World::Type)(*this)[ptr++] == World::TYPE_MOON) { + moonIdsAndTimestamps.push_back(std::pair(at(ptr), at(ptr + 8))); + } + ptr += 16; + } + } + } - // Send OK(HELLO) with an echo of the packet's timestamp and some of the same - // information about us: version, sent-to address, etc. + // Send OK(HELLO) with an echo of the packet's timestamp and some of the same + // information about us: version, sent-to address, etc. - Packet outp(id.address(),RR->identity.address(),Packet::VERB_OK); - outp.append((unsigned char)Packet::VERB_HELLO); - outp.append((uint64_t)pid); - outp.append((uint64_t)timestamp); - outp.append((unsigned char)ZT_PROTO_VERSION); - outp.append((unsigned char)ZEROTIER_ONE_VERSION_MAJOR); - outp.append((unsigned char)ZEROTIER_ONE_VERSION_MINOR); - outp.append((uint16_t)ZEROTIER_ONE_VERSION_REVISION); + Packet outp(id.address(), RR->identity.address(), Packet::VERB_OK); + outp.append((unsigned char)Packet::VERB_HELLO); + outp.append((uint64_t)pid); + outp.append((uint64_t)timestamp); + outp.append((unsigned char)ZT_PROTO_VERSION); + outp.append((unsigned char)ZEROTIER_ONE_VERSION_MAJOR); + outp.append((unsigned char)ZEROTIER_ONE_VERSION_MINOR); + outp.append((uint16_t)ZEROTIER_ONE_VERSION_REVISION); + _path->address().serialize(outp); + const unsigned int worldUpdateSizeAt = outp.size(); + outp.addSize(2); // make room for 16-bit size field + if ((planetWorldId) && (RR->topology->planetWorldTimestamp() > planetWorldTimestamp) && (planetWorldId == RR->topology->planetWorldId())) { + RR->topology->planet().serialize(outp, false); + } + if (! moonIdsAndTimestamps.empty()) { + std::vector moons(RR->topology->moons()); + for (std::vector::const_iterator m(moons.begin()); m != moons.end(); ++m) { + for (std::vector >::const_iterator i(moonIdsAndTimestamps.begin()); i != moonIdsAndTimestamps.end(); ++i) { + if (i->first == m->id()) { + if (m->timestamp() > i->second) { + m->serialize(outp, false); + } + break; + } + } + } + } + outp.setAt(worldUpdateSizeAt, (uint16_t)(outp.size() - (worldUpdateSizeAt + 2))); - if (protoVersion >= 5) { - _path->address().serialize(outp); - } else { - /* LEGACY COMPATIBILITY HACK: - * - * For a while now (since 1.0.3), ZeroTier has recognized changes in - * its network environment empirically by examining its external network - * address as reported by trusted peers. In versions prior to 1.1.0 - * (protocol version < 5), they did this by saving a snapshot of this - * information (in SelfAwareness.hpp) keyed by reporting device ID and - * address type. - * - * This causes problems when clustering is combined with symmetric NAT. - * Symmetric NAT remaps ports, so different endpoints in a cluster will - * report back different exterior addresses. Since the old code keys - * this by device ID and not sending physical address and compares the - * entire address including port, it constantly thinks its external - * surface is changing and resets connections when talking to a cluster. - * - * In new code we key by sending physical address and device and we also - * take the more conservative position of only interpreting changes in - * IP address (neglecting port) as a change in network topology that - * necessitates a reset. But we can make older clients work here by - * nulling out the port field. Since this info is only used for empirical - * detection of link changes, it doesn't break anything else. - */ - InetAddress tmpa(_path->address()); - tmpa.setPort(0); - tmpa.serialize(outp); - } + outp.armor(peer->key(), true, false, peer->aesKeysIfSupported(), peer->identity()); + peer->recordOutgoingPacket(_path, outp.packetId(), outp.payloadLength(), outp.verb(), ZT_QOS_NO_FLOW, now); + Metrics::pkt_ok_out++; + _path->send(RR, tPtr, outp.data(), outp.size(), now); - const unsigned int worldUpdateSizeAt = outp.size(); - outp.addSize(2); // make room for 16-bit size field - if ((planetWorldId)&&(RR->topology->planetWorldTimestamp() > planetWorldTimestamp)&&(planetWorldId == RR->topology->planetWorldId())) { - RR->topology->planet().serialize(outp,false); - } - if (!moonIdsAndTimestamps.empty()) { - std::vector moons(RR->topology->moons()); - for(std::vector::const_iterator m(moons.begin());m!=moons.end();++m) { - for(std::vector< std::pair >::const_iterator i(moonIdsAndTimestamps.begin());i!=moonIdsAndTimestamps.end();++i) { - if (i->first == m->id()) { - if (m->timestamp() > i->second) { - m->serialize(outp,false); - } - break; - } - } - } - } - outp.setAt(worldUpdateSizeAt,(uint16_t)(outp.size() - (worldUpdateSizeAt + 2))); + peer->setRemoteVersion(protoVersion, vMajor, vMinor, vRevision); // important for this to go first so received() knows the version + peer->received(tPtr, _path, hops(), pid, payloadLength(), Packet::VERB_HELLO, 0, Packet::VERB_NOP, false, 0, ZT_QOS_NO_FLOW); - outp.armor(peer->key(),true,peer->aesKeysIfSupported()); - peer->recordOutgoingPacket(_path,outp.packetId(),outp.payloadLength(),outp.verb(),ZT_QOS_NO_FLOW,now); - Metrics::pkt_ok_out++; - _path->send(RR,tPtr,outp.data(),outp.size(),now); - - peer->setRemoteVersion(protoVersion,vMajor,vMinor,vRevision); // important for this to go first so received() knows the version - peer->received(tPtr,_path,hops(),pid,payloadLength(),Packet::VERB_HELLO,0,Packet::VERB_NOP,false,0,ZT_QOS_NO_FLOW); - - return true; + return true; } -bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer) +bool IncomingPacket::_doOK(const RuntimeEnvironment* RR, void* tPtr, const SharedPtr& peer) { - Metrics::pkt_ok_in++; - const Packet::Verb inReVerb = (Packet::Verb)(*this)[ZT_PROTO_VERB_OK_IDX_IN_RE_VERB]; - const uint64_t inRePacketId = at(ZT_PROTO_VERB_OK_IDX_IN_RE_PACKET_ID); - uint64_t networkId = 0; + Metrics::pkt_ok_in++; + const Packet::Verb inReVerb = (Packet::Verb)(*this)[ZT_PROTO_VERB_OK_IDX_IN_RE_VERB]; + const uint64_t inRePacketId = at(ZT_PROTO_VERB_OK_IDX_IN_RE_PACKET_ID); + uint64_t networkId = 0; - if (!RR->node->expectingReplyTo(inRePacketId)) { - return true; - } + if (! RR->node->expectingReplyTo(inRePacketId)) { + return true; + } - switch(inReVerb) { + switch (inReVerb) { + case Packet::VERB_HELLO: { + const uint64_t latency = RR->node->now() - at(ZT_PROTO_VERB_HELLO__OK__IDX_TIMESTAMP); + const unsigned int vProto = (*this)[ZT_PROTO_VERB_HELLO__OK__IDX_PROTOCOL_VERSION]; + const unsigned int vMajor = (*this)[ZT_PROTO_VERB_HELLO__OK__IDX_MAJOR_VERSION]; + const unsigned int vMinor = (*this)[ZT_PROTO_VERB_HELLO__OK__IDX_MINOR_VERSION]; + const unsigned int vRevision = at(ZT_PROTO_VERB_HELLO__OK__IDX_REVISION); + if (vProto < ZT_PROTO_VERSION_MIN) { + return true; + } - case Packet::VERB_HELLO: { - const uint64_t latency = RR->node->now() - at(ZT_PROTO_VERB_HELLO__OK__IDX_TIMESTAMP); - const unsigned int vProto = (*this)[ZT_PROTO_VERB_HELLO__OK__IDX_PROTOCOL_VERSION]; - const unsigned int vMajor = (*this)[ZT_PROTO_VERB_HELLO__OK__IDX_MAJOR_VERSION]; - const unsigned int vMinor = (*this)[ZT_PROTO_VERB_HELLO__OK__IDX_MINOR_VERSION]; - const unsigned int vRevision = at(ZT_PROTO_VERB_HELLO__OK__IDX_REVISION); - if (vProto < ZT_PROTO_VERSION_MIN) { - return true; - } + InetAddress externalSurfaceAddress; + unsigned int ptr = ZT_PROTO_VERB_HELLO__OK__IDX_REVISION + 2; - InetAddress externalSurfaceAddress; - unsigned int ptr = ZT_PROTO_VERB_HELLO__OK__IDX_REVISION + 2; + // Get reported external surface address if present + if (ptr < size()) { + ptr += externalSurfaceAddress.deserialize(*this, ptr); + } - // Get reported external surface address if present - if (ptr < size()) { - ptr += externalSurfaceAddress.deserialize(*this,ptr); - } + // Handle planet or moon updates if present + if ((ptr + 2) <= size()) { + const unsigned int worldsLen = at(ptr); + ptr += 2; + if (RR->topology->shouldAcceptWorldUpdateFrom(peer->address())) { + const unsigned int endOfWorlds = ptr + worldsLen; + while (ptr < endOfWorlds) { + World w; + ptr += w.deserialize(*this, ptr); + RR->topology->addWorld(tPtr, w, false); + } + } + else { + ptr += worldsLen; + } + } - // Handle planet or moon updates if present - if ((ptr + 2) <= size()) { - const unsigned int worldsLen = at(ptr); - ptr += 2; - if (RR->topology->shouldAcceptWorldUpdateFrom(peer->address())) { - const unsigned int endOfWorlds = ptr + worldsLen; - while (ptr < endOfWorlds) { - World w; - ptr += w.deserialize(*this,ptr); - RR->topology->addWorld(tPtr,w,false); - } - } else { - ptr += worldsLen; - } - } + if (! hops()) { + _path->updateLatency((unsigned int)latency, RR->node->now()); + } - if (!hops()) { - _path->updateLatency((unsigned int)latency,RR->node->now()); - } + peer->setRemoteVersion(vProto, vMajor, vMinor, vRevision); - peer->setRemoteVersion(vProto,vMajor,vMinor,vRevision); + if ((externalSurfaceAddress) && (hops() == 0)) { + RR->sa->iam(tPtr, peer->address(), _path->localSocket(), _path->address(), externalSurfaceAddress, RR->topology->isUpstream(peer->identity()), RR->node->now()); + } + } break; - if ((externalSurfaceAddress)&&(hops() == 0)) { - RR->sa->iam(tPtr,peer->address(),_path->localSocket(),_path->address(),externalSurfaceAddress,RR->topology->isUpstream(peer->identity()),RR->node->now()); - } - } break; + case Packet::VERB_WHOIS: + if (RR->topology->isUpstream(peer->identity())) { + const Identity id(*this, ZT_PROTO_VERB_WHOIS__OK__IDX_IDENTITY); + RR->sw->doAnythingWaitingForPeer(tPtr, RR->topology->addPeer(tPtr, SharedPtr(new Peer(RR, RR->identity, id)))); + } + break; - case Packet::VERB_WHOIS: - if (RR->topology->isUpstream(peer->identity())) { - const Identity id(*this,ZT_PROTO_VERB_WHOIS__OK__IDX_IDENTITY); - RR->sw->doAnythingWaitingForPeer(tPtr,RR->topology->addPeer(tPtr,SharedPtr(new Peer(RR,RR->identity,id)))); - } - break; + case Packet::VERB_NETWORK_CONFIG_REQUEST: { + networkId = at(ZT_PROTO_VERB_OK_IDX_PAYLOAD); + const SharedPtr network(RR->node->network(networkId)); + if (network) { + network->handleConfigChunk(tPtr, packetId(), source(), *this, ZT_PROTO_VERB_OK_IDX_PAYLOAD); + } + } break; - case Packet::VERB_NETWORK_CONFIG_REQUEST: { - networkId = at(ZT_PROTO_VERB_OK_IDX_PAYLOAD); - const SharedPtr network(RR->node->network(networkId)); - if (network) { - network->handleConfigChunk(tPtr,packetId(),source(),*this,ZT_PROTO_VERB_OK_IDX_PAYLOAD); - } - } break; + case Packet::VERB_MULTICAST_GATHER: { + networkId = at(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_NETWORK_ID); + const SharedPtr network(RR->node->network(networkId)); + if (network) { + const MulticastGroup mg(MAC(field(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_MAC, 6), 6), at(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_ADI)); + const unsigned int count = at(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_GATHER_RESULTS + 4); + RR->mc->addMultiple(tPtr, RR->node->now(), networkId, mg, field(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_GATHER_RESULTS + 6, count * 5), count, at(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_GATHER_RESULTS)); + } + } break; - case Packet::VERB_MULTICAST_GATHER: { - networkId = at(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_NETWORK_ID); - const SharedPtr network(RR->node->network(networkId)); - if (network) { - const MulticastGroup mg(MAC(field(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_MAC,6),6),at(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_ADI)); - const unsigned int count = at(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_GATHER_RESULTS + 4); - RR->mc->addMultiple(tPtr,RR->node->now(),networkId,mg,field(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_GATHER_RESULTS + 6,count * 5),count,at(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_GATHER_RESULTS)); - } - } break; + case Packet::VERB_MULTICAST_FRAME: { + const unsigned int flags = (*this)[ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_FLAGS]; + networkId = at(ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_NETWORK_ID); + const MulticastGroup mg(MAC(field(ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_MAC, 6), 6), at(ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_ADI)); - case Packet::VERB_MULTICAST_FRAME: { - const unsigned int flags = (*this)[ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_FLAGS]; - networkId = at(ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_NETWORK_ID); - const MulticastGroup mg(MAC(field(ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_MAC,6),6),at(ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_ADI)); + const SharedPtr network(RR->node->network(networkId)); + if (network) { + unsigned int offset = 0; - const SharedPtr network(RR->node->network(networkId)); - if (network) { - unsigned int offset = 0; + if ((flags & 0x01) != 0) { // deprecated but still used by older peers + CertificateOfMembership com; + offset += com.deserialize(*this, ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_COM_AND_GATHER_RESULTS); + if (com) { + network->addCredential(tPtr, com); + } + } - if ((flags & 0x01) != 0) { // deprecated but still used by older peers - CertificateOfMembership com; - offset += com.deserialize(*this,ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_COM_AND_GATHER_RESULTS); - if (com) { - network->addCredential(tPtr,com); - } - } + if ((flags & 0x02) != 0) { + // OK(MULTICAST_FRAME) includes implicit gather results + offset += ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_COM_AND_GATHER_RESULTS; + unsigned int totalKnown = at(offset); + offset += 4; + unsigned int count = at(offset); + offset += 2; + RR->mc->addMultiple(tPtr, RR->node->now(), networkId, mg, field(offset, count * 5), count, totalKnown); + } + } + } break; - if ((flags & 0x02) != 0) { - // OK(MULTICAST_FRAME) includes implicit gather results - offset += ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_COM_AND_GATHER_RESULTS; - unsigned int totalKnown = at(offset); - offset += 4; - unsigned int count = at(offset); - offset += 2; - RR->mc->addMultiple(tPtr,RR->node->now(),networkId,mg,field(offset,count * 5),count,totalKnown); - } - } - } break; + default: + break; + } - default: - break; - } + peer->received(tPtr, _path, hops(), packetId(), payloadLength(), Packet::VERB_OK, inRePacketId, inReVerb, false, networkId, ZT_QOS_NO_FLOW); - peer->received(tPtr,_path,hops(),packetId(),payloadLength(),Packet::VERB_OK,inRePacketId,inReVerb,false,networkId,ZT_QOS_NO_FLOW); - - return true; + return true; } -bool IncomingPacket::_doWHOIS(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer) +bool IncomingPacket::_doWHOIS(const RuntimeEnvironment* RR, void* tPtr, const SharedPtr& peer) { - if ((!RR->topology->amUpstream())&&(!peer->rateGateInboundWhoisRequest(RR->node->now()))) { - return true; - } + if ((! RR->topology->amUpstream()) && (! peer->rateGateInboundWhoisRequest(RR->node->now()))) { + return true; + } - Metrics::pkt_whois_in++; + Metrics::pkt_whois_in++; - Packet outp(peer->address(),RR->identity.address(),Packet::VERB_OK); - outp.append((unsigned char)Packet::VERB_WHOIS); - outp.append(packetId()); + Packet outp(peer->address(), RR->identity.address(), Packet::VERB_OK); + outp.append((unsigned char)Packet::VERB_WHOIS); + outp.append(packetId()); - unsigned int count = 0; - unsigned int ptr = ZT_PACKET_IDX_PAYLOAD; - while ((ptr + ZT_ADDRESS_LENGTH) <= size()) { - const Address addr(field(ptr,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); - ptr += ZT_ADDRESS_LENGTH; + unsigned int count = 0; + unsigned int ptr = ZT_PACKET_IDX_PAYLOAD; + while ((ptr + ZT_ADDRESS_LENGTH) <= size()) { + const Address addr(field(ptr, ZT_ADDRESS_LENGTH), ZT_ADDRESS_LENGTH); + ptr += ZT_ADDRESS_LENGTH; - const Identity id(RR->topology->getIdentity(tPtr,addr)); - if (id) { - id.serialize(outp,false); - ++count; - } else { - // Request unknown WHOIS from upstream from us (if we have one) - RR->sw->requestWhois(tPtr,RR->node->now(),addr); - } - } + const Identity id(RR->topology->getIdentity(tPtr, addr)); + if (id) { + id.serialize(outp, false); + ++count; + } + else { + // Request unknown WHOIS from upstream from us (if we have one) + RR->sw->requestWhois(tPtr, RR->node->now(), addr); + } + } - if (count > 0) { - Metrics::pkt_ok_out++; - outp.armor(peer->key(),true,peer->aesKeysIfSupported()); - _path->send(RR,tPtr,outp.data(),outp.size(),RR->node->now()); - } + if (count > 0) { + Metrics::pkt_ok_out++; + outp.armor(peer->key(), true, false, peer->aesKeysIfSupported(), RR->identity); + _path->send(RR, tPtr, outp.data(), outp.size(), RR->node->now()); + } - peer->received(tPtr,_path,hops(),packetId(),payloadLength(),Packet::VERB_WHOIS,0,Packet::VERB_NOP,false,0,ZT_QOS_NO_FLOW); + peer->received(tPtr, _path, hops(), packetId(), payloadLength(), Packet::VERB_WHOIS, 0, Packet::VERB_NOP, false, 0, ZT_QOS_NO_FLOW); - return true; + return true; } -bool IncomingPacket::_doRENDEZVOUS(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer) +bool IncomingPacket::_doRENDEZVOUS(const RuntimeEnvironment* RR, void* tPtr, const SharedPtr& peer) { - Metrics::pkt_rendezvous_in++; - if (RR->topology->isUpstream(peer->identity())) { - const Address with(field(ZT_PROTO_VERB_RENDEZVOUS_IDX_ZTADDRESS,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); - const SharedPtr rendezvousWith(RR->topology->getPeer(tPtr,with)); - if (rendezvousWith) { - const unsigned int port = at(ZT_PROTO_VERB_RENDEZVOUS_IDX_PORT); - const unsigned int addrlen = (*this)[ZT_PROTO_VERB_RENDEZVOUS_IDX_ADDRLEN]; - if ((port > 0)&&((addrlen == 4)||(addrlen == 16))) { - InetAddress atAddr(field(ZT_PROTO_VERB_RENDEZVOUS_IDX_ADDRESS,addrlen),addrlen,port); - if (RR->node->shouldUsePathForZeroTierTraffic(tPtr,with,_path->localSocket(),atAddr)) { - const uint64_t junk = RR->node->prng(); - RR->node->putPacket(tPtr,_path->localSocket(),atAddr,&junk,4,2); // send low-TTL junk packet to 'open' local NAT(s) and stateful firewalls - rendezvousWith->attemptToContactAt(tPtr,_path->localSocket(),atAddr,RR->node->now(),false); - } - } - } - } + Metrics::pkt_rendezvous_in++; + if (RR->topology->isUpstream(peer->identity())) { + const Address with(field(ZT_PROTO_VERB_RENDEZVOUS_IDX_ZTADDRESS, ZT_ADDRESS_LENGTH), ZT_ADDRESS_LENGTH); + const SharedPtr rendezvousWith(RR->topology->getPeer(tPtr, with)); + if (rendezvousWith) { + const unsigned int port = at(ZT_PROTO_VERB_RENDEZVOUS_IDX_PORT); + const unsigned int addrlen = (*this)[ZT_PROTO_VERB_RENDEZVOUS_IDX_ADDRLEN]; + if ((port > 0) && ((addrlen == 4) || (addrlen == 16))) { + InetAddress atAddr(field(ZT_PROTO_VERB_RENDEZVOUS_IDX_ADDRESS, addrlen), addrlen, port); + if (RR->node->shouldUsePathForZeroTierTraffic(tPtr, with, _path->localSocket(), atAddr)) { + const uint64_t junk = RR->node->prng(); + RR->node->putPacket(tPtr, _path->localSocket(), atAddr, &junk, 4, 2); // send low-TTL junk packet to 'open' local NAT(s) and stateful firewalls + rendezvousWith->attemptToContactAt(tPtr, _path->localSocket(), atAddr, RR->node->now(), false); + } + } + } + } - peer->received(tPtr,_path,hops(),packetId(),payloadLength(),Packet::VERB_RENDEZVOUS,0,Packet::VERB_NOP,false,0,ZT_QOS_NO_FLOW); + peer->received(tPtr, _path, hops(), packetId(), payloadLength(), Packet::VERB_RENDEZVOUS, 0, Packet::VERB_NOP, false, 0, ZT_QOS_NO_FLOW); - return true; + return true; } // Returns true if packet appears valid; pos and proto will be set -static bool _ipv6GetPayload(const uint8_t *frameData,unsigned int frameLen,unsigned int &pos,unsigned int &proto) +static bool _ipv6GetPayload(const uint8_t* frameData, unsigned int frameLen, unsigned int& pos, unsigned int& proto) { - if (frameLen < 40) { - return false; - } - pos = 40; - proto = frameData[6]; - while (pos <= frameLen) { - switch(proto) { - case 0: // hop-by-hop options - case 43: // routing - case 60: // destination options - case 135: // mobility options - if ((pos + 8) > frameLen) { - return false; // invalid! - } - proto = frameData[pos]; - pos += ((unsigned int)frameData[pos + 1] * 8) + 8; - break; + if (frameLen < 40) { + return false; + } + pos = 40; + proto = frameData[6]; + while (pos <= frameLen) { + switch (proto) { + case 0: // hop-by-hop options + case 43: // routing + case 60: // destination options + case 135: // mobility options + if ((pos + 8) > frameLen) { + return false; // invalid! + } + proto = frameData[pos]; + pos += ((unsigned int)frameData[pos + 1] * 8) + 8; + break; - //case 44: // fragment -- we currently can't parse these and they are deprecated in IPv6 anyway - //case 50: - //case 51: // IPSec ESP and AH -- we have to stop here since this is encrypted stuff - default: - return true; - } - } - return false; // overflow == invalid + // case 44: // fragment -- we currently can't parse these and they are deprecated in IPv6 anyway + // case 50: + // case 51: // IPSec ESP and AH -- we have to stop here since this is encrypted stuff + default: + return true; + } + } + return false; // overflow == invalid } -bool IncomingPacket::_doFRAME(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer,int32_t flowId) +bool IncomingPacket::_doFRAME(const RuntimeEnvironment* RR, void* tPtr, const SharedPtr& peer, int32_t flowId) { - Metrics::pkt_frame_in++; - int32_t _flowId = ZT_QOS_NO_FLOW; + Metrics::pkt_frame_in++; + int32_t _flowId = ZT_QOS_NO_FLOW; - if (size() > ZT_PROTO_VERB_EXT_FRAME_IDX_PAYLOAD) { - const unsigned int etherType = at(ZT_PROTO_VERB_FRAME_IDX_ETHERTYPE); - const unsigned int frameLen = size() - ZT_PROTO_VERB_FRAME_IDX_PAYLOAD; - const uint8_t *const frameData = reinterpret_cast(data()) + ZT_PROTO_VERB_FRAME_IDX_PAYLOAD; + if (size() > ZT_PROTO_VERB_EXT_FRAME_IDX_PAYLOAD) { + const unsigned int etherType = at(ZT_PROTO_VERB_FRAME_IDX_ETHERTYPE); + const unsigned int frameLen = size() - ZT_PROTO_VERB_FRAME_IDX_PAYLOAD; + const uint8_t* const frameData = reinterpret_cast(data()) + ZT_PROTO_VERB_FRAME_IDX_PAYLOAD; - if (etherType == ZT_ETHERTYPE_IPV4 && (frameLen >= 20)) { - uint16_t srcPort = 0; - uint16_t dstPort = 0; - uint8_t proto = (reinterpret_cast(frameData)[9]); - const unsigned int headerLen = 4 * (reinterpret_cast(frameData)[0] & 0xf); - switch(proto) { - case 0x01: // ICMP - //flowId = 0x01; - break; - // All these start with 16-bit source and destination port in that order - case 0x06: // TCP - case 0x11: // UDP - case 0x84: // SCTP - case 0x88: // UDPLite - if (frameLen > (headerLen + 4)) { - unsigned int pos = headerLen + 0; - srcPort = (reinterpret_cast(frameData)[pos++]) << 8; - srcPort |= (reinterpret_cast(frameData)[pos]); - pos++; - dstPort = (reinterpret_cast(frameData)[pos++]) << 8; - dstPort |= (reinterpret_cast(frameData)[pos]); - _flowId = dstPort ^ srcPort ^ proto; - } - break; - } - } + if (etherType == ZT_ETHERTYPE_IPV4 && (frameLen >= 20)) { + uint16_t srcPort = 0; + uint16_t dstPort = 0; + uint8_t proto = (reinterpret_cast(frameData)[9]); + const unsigned int headerLen = 4 * (reinterpret_cast(frameData)[0] & 0xf); + switch (proto) { + case 0x01: // ICMP + // flowId = 0x01; + break; + // All these start with 16-bit source and destination port in that order + case 0x06: // TCP + case 0x11: // UDP + case 0x84: // SCTP + case 0x88: // UDPLite + if (frameLen > (headerLen + 4)) { + unsigned int pos = headerLen + 0; + srcPort = (reinterpret_cast(frameData)[pos++]) << 8; + srcPort |= (reinterpret_cast(frameData)[pos]); + pos++; + dstPort = (reinterpret_cast(frameData)[pos++]) << 8; + dstPort |= (reinterpret_cast(frameData)[pos]); + _flowId = dstPort ^ srcPort ^ proto; + } + break; + } + } - if (etherType == ZT_ETHERTYPE_IPV6 && (frameLen >= 40)) { - uint16_t srcPort = 0; - uint16_t dstPort = 0; - unsigned int pos; - unsigned int proto; - _ipv6GetPayload((const uint8_t *)frameData, frameLen, pos, proto); - switch(proto) { - case 0x3A: // ICMPv6 - //flowId = 0x3A; - break; - // All these start with 16-bit source and destination port in that order - case 0x06: // TCP - case 0x11: // UDP - case 0x84: // SCTP - case 0x88: // UDPLite - if (frameLen > (pos + 4)) { - srcPort = (reinterpret_cast(frameData)[pos++]) << 8; - srcPort |= (reinterpret_cast(frameData)[pos]); - pos++; - dstPort = (reinterpret_cast(frameData)[pos++]) << 8; - dstPort |= (reinterpret_cast(frameData)[pos]); - _flowId = dstPort ^ srcPort ^ proto; - } - break; - default: - break; - } - } - } + if (etherType == ZT_ETHERTYPE_IPV6 && (frameLen >= 40)) { + uint16_t srcPort = 0; + uint16_t dstPort = 0; + unsigned int pos; + unsigned int proto; + _ipv6GetPayload((const uint8_t*)frameData, frameLen, pos, proto); + switch (proto) { + case 0x3A: // ICMPv6 + // flowId = 0x3A; + break; + // All these start with 16-bit source and destination port in that order + case 0x06: // TCP + case 0x11: // UDP + case 0x84: // SCTP + case 0x88: // UDPLite + if (frameLen > (pos + 4)) { + srcPort = (reinterpret_cast(frameData)[pos++]) << 8; + srcPort |= (reinterpret_cast(frameData)[pos]); + pos++; + dstPort = (reinterpret_cast(frameData)[pos++]) << 8; + dstPort |= (reinterpret_cast(frameData)[pos]); + _flowId = dstPort ^ srcPort ^ proto; + } + break; + default: + break; + } + } + } - const uint64_t nwid = at(ZT_PROTO_VERB_FRAME_IDX_NETWORK_ID); - const SharedPtr network(RR->node->network(nwid)); - bool trustEstablished = false; - if (network) { - if (network->gate(tPtr,peer)) { - trustEstablished = true; - if (size() > ZT_PROTO_VERB_FRAME_IDX_PAYLOAD) { - const unsigned int etherType = at(ZT_PROTO_VERB_FRAME_IDX_ETHERTYPE); - const MAC sourceMac(peer->address(),nwid); - const unsigned int frameLen = size() - ZT_PROTO_VERB_FRAME_IDX_PAYLOAD; - const uint8_t *const frameData = reinterpret_cast(data()) + ZT_PROTO_VERB_FRAME_IDX_PAYLOAD; - if (network->filterIncomingPacket(tPtr,peer,RR->identity.address(),sourceMac,network->mac(),frameData,frameLen,etherType,0) > 0) { - RR->pm->putFrame(tPtr,nwid,network->userPtr(),sourceMac,network->mac(),etherType,0,(const void *)frameData,frameLen, _flowId); - } - } - } else { - _sendErrorNeedCredentials(RR,tPtr,peer,nwid); - return false; - } - } - peer->received(tPtr,_path,hops(),packetId(),payloadLength(),Packet::VERB_FRAME,0,Packet::VERB_NOP,trustEstablished,nwid,_flowId); + const uint64_t nwid = at(ZT_PROTO_VERB_FRAME_IDX_NETWORK_ID); + const SharedPtr network(RR->node->network(nwid)); + bool trustEstablished = false; + if (network) { + if (network->gate(tPtr, peer)) { + trustEstablished = true; + if (size() > ZT_PROTO_VERB_FRAME_IDX_PAYLOAD) { + const unsigned int etherType = at(ZT_PROTO_VERB_FRAME_IDX_ETHERTYPE); + const MAC sourceMac(peer->address(), nwid); + const unsigned int frameLen = size() - ZT_PROTO_VERB_FRAME_IDX_PAYLOAD; + const uint8_t* const frameData = reinterpret_cast(data()) + ZT_PROTO_VERB_FRAME_IDX_PAYLOAD; + if (network->filterIncomingPacket(tPtr, peer, RR->identity.address(), sourceMac, network->mac(), frameData, frameLen, etherType, 0) > 0) { + RR->pm->putFrame(tPtr, nwid, network->userPtr(), sourceMac, network->mac(), etherType, 0, (const void*)frameData, frameLen, _flowId); + } + } + } + else { + _sendErrorNeedCredentials(RR, tPtr, peer, nwid); + return false; + } + } + peer->received(tPtr, _path, hops(), packetId(), payloadLength(), Packet::VERB_FRAME, 0, Packet::VERB_NOP, trustEstablished, nwid, _flowId); - return true; + return true; } -bool IncomingPacket::_doEXT_FRAME(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer,int32_t flowId) +bool IncomingPacket::_doEXT_FRAME(const RuntimeEnvironment* RR, void* tPtr, const SharedPtr& peer, int32_t flowId) { - Metrics::pkt_ext_frame_in++; - const uint64_t nwid = at(ZT_PROTO_VERB_EXT_FRAME_IDX_NETWORK_ID); - const SharedPtr network(RR->node->network(nwid)); - if (network) { - const unsigned int flags = (*this)[ZT_PROTO_VERB_EXT_FRAME_IDX_FLAGS]; + Metrics::pkt_ext_frame_in++; + const uint64_t nwid = at(ZT_PROTO_VERB_EXT_FRAME_IDX_NETWORK_ID); + const SharedPtr network(RR->node->network(nwid)); + if (network) { + const unsigned int flags = (*this)[ZT_PROTO_VERB_EXT_FRAME_IDX_FLAGS]; - unsigned int comLen = 0; - if ((flags & 0x01) != 0) { // inline COM with EXT_FRAME is deprecated but still used with old peers - CertificateOfMembership com; - comLen = com.deserialize(*this,ZT_PROTO_VERB_EXT_FRAME_IDX_COM); - if (com) { - network->addCredential(tPtr,com); - } - } + unsigned int comLen = 0; + if ((flags & 0x01) != 0) { // inline COM with EXT_FRAME is deprecated but still used with old peers + CertificateOfMembership com; + comLen = com.deserialize(*this, ZT_PROTO_VERB_EXT_FRAME_IDX_COM); + if (com) { + network->addCredential(tPtr, com); + } + } - if (!network->gate(tPtr,peer)) { - RR->t->incomingNetworkAccessDenied(tPtr,network,_path,packetId(),size(),peer->address(),Packet::VERB_EXT_FRAME,true); - _sendErrorNeedCredentials(RR,tPtr,peer,nwid); - return false; - } + if (! network->gate(tPtr, peer)) { + RR->t->incomingNetworkAccessDenied(tPtr, network, _path, packetId(), size(), peer->address(), Packet::VERB_EXT_FRAME, true); + _sendErrorNeedCredentials(RR, tPtr, peer, nwid); + return false; + } - if (size() > ZT_PROTO_VERB_EXT_FRAME_IDX_PAYLOAD) { - const unsigned int etherType = at(comLen + ZT_PROTO_VERB_EXT_FRAME_IDX_ETHERTYPE); - const MAC to(field(comLen + ZT_PROTO_VERB_EXT_FRAME_IDX_TO,ZT_PROTO_VERB_EXT_FRAME_LEN_TO),ZT_PROTO_VERB_EXT_FRAME_LEN_TO); - const MAC from(field(comLen + ZT_PROTO_VERB_EXT_FRAME_IDX_FROM,ZT_PROTO_VERB_EXT_FRAME_LEN_FROM),ZT_PROTO_VERB_EXT_FRAME_LEN_FROM); - const unsigned int frameLen = size() - (comLen + ZT_PROTO_VERB_EXT_FRAME_IDX_PAYLOAD); - const uint8_t *const frameData = (const uint8_t *)field(comLen + ZT_PROTO_VERB_EXT_FRAME_IDX_PAYLOAD,frameLen); + if (size() > ZT_PROTO_VERB_EXT_FRAME_IDX_PAYLOAD) { + const unsigned int etherType = at(comLen + ZT_PROTO_VERB_EXT_FRAME_IDX_ETHERTYPE); + const MAC to(field(comLen + ZT_PROTO_VERB_EXT_FRAME_IDX_TO, ZT_PROTO_VERB_EXT_FRAME_LEN_TO), ZT_PROTO_VERB_EXT_FRAME_LEN_TO); + const MAC from(field(comLen + ZT_PROTO_VERB_EXT_FRAME_IDX_FROM, ZT_PROTO_VERB_EXT_FRAME_LEN_FROM), ZT_PROTO_VERB_EXT_FRAME_LEN_FROM); + const unsigned int frameLen = size() - (comLen + ZT_PROTO_VERB_EXT_FRAME_IDX_PAYLOAD); + const uint8_t* const frameData = (const uint8_t*)field(comLen + ZT_PROTO_VERB_EXT_FRAME_IDX_PAYLOAD, frameLen); - if ((!from)||(from == network->mac())) { - peer->received(tPtr,_path,hops(),packetId(),payloadLength(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true,nwid,flowId); // trustEstablished because COM is okay - return true; - } + if ((! from) || (from == network->mac())) { + peer->received(tPtr, _path, hops(), packetId(), payloadLength(), Packet::VERB_EXT_FRAME, 0, Packet::VERB_NOP, true, nwid, flowId); // trustEstablished because COM is okay + return true; + } - switch (network->filterIncomingPacket(tPtr,peer,RR->identity.address(),from,to,frameData,frameLen,etherType,0)) { - case 1: - if (from != MAC(peer->address(),nwid)) { - if (network->config().permitsBridging(peer->address())) { - network->learnBridgeRoute(from,peer->address()); - } else { - RR->t->incomingNetworkFrameDropped(tPtr,network,_path,packetId(),size(),peer->address(),Packet::VERB_EXT_FRAME,from,to,"bridging not allowed (remote)"); - peer->received(tPtr,_path,hops(),packetId(),payloadLength(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true,nwid,flowId); // trustEstablished because COM is okay - return true; - } - } else if (to != network->mac()) { - if (to.isMulticast()) { - if (network->config().multicastLimit == 0) { - RR->t->incomingNetworkFrameDropped(tPtr,network,_path,packetId(),size(),peer->address(),Packet::VERB_EXT_FRAME,from,to,"multicast disabled"); - peer->received(tPtr,_path,hops(),packetId(),payloadLength(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true,nwid,flowId); // trustEstablished because COM is okay - return true; - } - } else if (!network->config().permitsBridging(RR->identity.address())) { - RR->t->incomingNetworkFrameDropped(tPtr,network,_path,packetId(),size(),peer->address(),Packet::VERB_EXT_FRAME,from,to,"bridging not allowed (local)"); - peer->received(tPtr,_path,hops(),packetId(),payloadLength(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true,nwid,flowId); // trustEstablished because COM is okay - return true; - } - } - // fall through -- 2 means accept regardless of bridging checks or other restrictions - case 2: - RR->pm->putFrame(tPtr,nwid,network->userPtr(),from,to,etherType,0,(const void *)frameData,frameLen, flowId); - break; - } - } + switch (network->filterIncomingPacket(tPtr, peer, RR->identity.address(), from, to, frameData, frameLen, etherType, 0)) { + case 1: + if (from != MAC(peer->address(), nwid)) { + if (network->config().permitsBridging(peer->address())) { + network->learnBridgeRoute(from, peer->address()); + } + else { + RR->t->incomingNetworkFrameDropped(tPtr, network, _path, packetId(), size(), peer->address(), Packet::VERB_EXT_FRAME, from, to, "bridging not allowed (remote)"); + peer->received(tPtr, _path, hops(), packetId(), payloadLength(), Packet::VERB_EXT_FRAME, 0, Packet::VERB_NOP, true, nwid, flowId); // trustEstablished because COM is okay + return true; + } + } + else if (to != network->mac()) { + if (to.isMulticast()) { + if (network->config().multicastLimit == 0) { + RR->t->incomingNetworkFrameDropped(tPtr, network, _path, packetId(), size(), peer->address(), Packet::VERB_EXT_FRAME, from, to, "multicast disabled"); + peer->received(tPtr, _path, hops(), packetId(), payloadLength(), Packet::VERB_EXT_FRAME, 0, Packet::VERB_NOP, true, nwid, flowId); // trustEstablished because COM is okay + return true; + } + } + else if (! network->config().permitsBridging(RR->identity.address())) { + RR->t->incomingNetworkFrameDropped(tPtr, network, _path, packetId(), size(), peer->address(), Packet::VERB_EXT_FRAME, from, to, "bridging not allowed (local)"); + peer->received(tPtr, _path, hops(), packetId(), payloadLength(), Packet::VERB_EXT_FRAME, 0, Packet::VERB_NOP, true, nwid, flowId); // trustEstablished because COM is okay + return true; + } + } + // fall through -- 2 means accept regardless of bridging checks or other restrictions + case 2: + RR->pm->putFrame(tPtr, nwid, network->userPtr(), from, to, etherType, 0, (const void*)frameData, frameLen, flowId); + break; + } + } - if ((flags & 0x10) != 0) { // ACK requested - Packet outp(peer->address(),RR->identity.address(),Packet::VERB_OK); - outp.append((uint8_t)Packet::VERB_EXT_FRAME); - outp.append((uint64_t)packetId()); - outp.append((uint64_t)nwid); - const int64_t now = RR->node->now(); - outp.armor(peer->key(),true,peer->aesKeysIfSupported()); - peer->recordOutgoingPacket(_path,outp.packetId(),outp.payloadLength(),outp.verb(),ZT_QOS_NO_FLOW,now); - Metrics::pkt_ok_out++; - _path->send(RR,tPtr,outp.data(),outp.size(),RR->node->now()); - } + if ((flags & 0x10) != 0) { // ACK requested + Packet outp(peer->address(), RR->identity.address(), Packet::VERB_OK); + outp.append((uint8_t)Packet::VERB_EXT_FRAME); + outp.append((uint64_t)packetId()); + outp.append((uint64_t)nwid); + const int64_t now = RR->node->now(); + outp.armor(peer->key(), true, false, peer->aesKeysIfSupported(), peer->identity()); + peer->recordOutgoingPacket(_path, outp.packetId(), outp.payloadLength(), outp.verb(), ZT_QOS_NO_FLOW, now); + Metrics::pkt_ok_out++; + _path->send(RR, tPtr, outp.data(), outp.size(), RR->node->now()); + } - peer->received(tPtr,_path,hops(),packetId(),payloadLength(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true,nwid,flowId); - } else { - peer->received(tPtr,_path,hops(),packetId(),payloadLength(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,false,nwid,flowId); - } + peer->received(tPtr, _path, hops(), packetId(), payloadLength(), Packet::VERB_EXT_FRAME, 0, Packet::VERB_NOP, true, nwid, flowId); + } + else { + peer->received(tPtr, _path, hops(), packetId(), payloadLength(), Packet::VERB_EXT_FRAME, 0, Packet::VERB_NOP, false, nwid, flowId); + } - return true; + return true; } -bool IncomingPacket::_doECHO(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer) +bool IncomingPacket::_doECHO(const RuntimeEnvironment* RR, void* tPtr, const SharedPtr& peer) { - Metrics::pkt_echo_in++; - uint64_t now = RR->node->now(); - if (!_path->rateGateEchoRequest(now)) { - return true; - } + Metrics::pkt_echo_in++; + uint64_t now = RR->node->now(); + if (! _path->rateGateEchoRequest(now)) { + return true; + } - const uint64_t pid = packetId(); - Packet outp(peer->address(),RR->identity.address(),Packet::VERB_OK); - outp.append((unsigned char)Packet::VERB_ECHO); - outp.append((uint64_t)pid); - if (size() > ZT_PACKET_IDX_PAYLOAD) { - outp.append(reinterpret_cast(data()) + ZT_PACKET_IDX_PAYLOAD,size() - ZT_PACKET_IDX_PAYLOAD); - } - outp.armor(peer->key(),true,peer->aesKeysIfSupported()); - peer->recordOutgoingPacket(_path,outp.packetId(),outp.payloadLength(),outp.verb(),ZT_QOS_NO_FLOW,now); - Metrics::pkt_ok_out++; - _path->send(RR,tPtr,outp.data(),outp.size(),RR->node->now()); + const uint64_t pid = packetId(); + Packet outp(peer->address(), RR->identity.address(), Packet::VERB_OK); + outp.append((unsigned char)Packet::VERB_ECHO); + outp.append((uint64_t)pid); + if (size() > ZT_PACKET_IDX_PAYLOAD) { + outp.append(reinterpret_cast(data()) + ZT_PACKET_IDX_PAYLOAD, size() - ZT_PACKET_IDX_PAYLOAD); + } + outp.armor(peer->key(), true, false, peer->aesKeysIfSupported(), peer->identity()); + peer->recordOutgoingPacket(_path, outp.packetId(), outp.payloadLength(), outp.verb(), ZT_QOS_NO_FLOW, now); + Metrics::pkt_ok_out++; + _path->send(RR, tPtr, outp.data(), outp.size(), RR->node->now()); - peer->received(tPtr,_path,hops(),pid,payloadLength(),Packet::VERB_ECHO,0,Packet::VERB_NOP,false,0,ZT_QOS_NO_FLOW); + peer->received(tPtr, _path, hops(), pid, payloadLength(), Packet::VERB_ECHO, 0, Packet::VERB_NOP, false, 0, ZT_QOS_NO_FLOW); - return true; + return true; } -bool IncomingPacket::_doMULTICAST_LIKE(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer) +bool IncomingPacket::_doMULTICAST_LIKE(const RuntimeEnvironment* RR, void* tPtr, const SharedPtr& peer) { - Metrics::pkt_multicast_like_in++; - const int64_t now = RR->node->now(); - bool authorized = false; - uint64_t lastNwid = 0; + Metrics::pkt_multicast_like_in++; + const int64_t now = RR->node->now(); + bool authorized = false; + uint64_t lastNwid = 0; - // Packet contains a series of 18-byte network,MAC,ADI tuples - for(unsigned int ptr=ZT_PACKET_IDX_PAYLOAD;ptr(ptr); - if (nwid != lastNwid) { - lastNwid = nwid; - SharedPtr network(RR->node->network(nwid)); - if (network) { - authorized = network->gate(tPtr,peer); - } - if (!authorized) { - authorized = ((RR->topology->amUpstream())||(RR->node->localControllerHasAuthorized(now,nwid,peer->address()))); - } - } - if (authorized) { - RR->mc->add(tPtr,now,nwid,MulticastGroup(MAC(field(ptr + 8,6),6),at(ptr + 14)),peer->address()); - } - } + // Packet contains a series of 18-byte network,MAC,ADI tuples + for (unsigned int ptr = ZT_PACKET_IDX_PAYLOAD; ptr < size(); ptr += 18) { + const uint64_t nwid = at(ptr); + if (nwid != lastNwid) { + lastNwid = nwid; + SharedPtr network(RR->node->network(nwid)); + if (network) { + authorized = network->gate(tPtr, peer); + } + if (! authorized) { + authorized = ((RR->topology->amUpstream()) || (RR->node->localControllerHasAuthorized(now, nwid, peer->address()))); + } + } + if (authorized) { + RR->mc->add(tPtr, now, nwid, MulticastGroup(MAC(field(ptr + 8, 6), 6), at(ptr + 14)), peer->address()); + } + } - peer->received(tPtr,_path,hops(),packetId(),payloadLength(),Packet::VERB_MULTICAST_LIKE,0,Packet::VERB_NOP,false,0,ZT_QOS_NO_FLOW); - return true; + peer->received(tPtr, _path, hops(), packetId(), payloadLength(), Packet::VERB_MULTICAST_LIKE, 0, Packet::VERB_NOP, false, 0, ZT_QOS_NO_FLOW); + return true; } -bool IncomingPacket::_doNETWORK_CREDENTIALS(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer) +bool IncomingPacket::_doNETWORK_CREDENTIALS(const RuntimeEnvironment* RR, void* tPtr, const SharedPtr& peer) { - Metrics::pkt_network_credentials_in++; - if (!peer->rateGateCredentialsReceived(RR->node->now())) { - return true; - } + Metrics::pkt_network_credentials_in++; + if (! peer->rateGateCredentialsReceived(RR->node->now())) { + return true; + } - CertificateOfMembership com; - Capability cap; - Tag tag; - Revocation revocation; - CertificateOfOwnership coo; - bool trustEstablished = false; - SharedPtr network; + CertificateOfMembership com; + Capability cap; + Tag tag; + Revocation revocation; + CertificateOfOwnership coo; + bool trustEstablished = false; + SharedPtr network; - unsigned int p = ZT_PACKET_IDX_PAYLOAD; - while ((p < size())&&((*this)[p] != 0)) { - p += com.deserialize(*this,p); - if (com) { - network = RR->node->network(com.networkId()); - if (network) { - switch (network->addCredential(tPtr,com)) { - case Membership::ADD_REJECTED: - break; - case Membership::ADD_ACCEPTED_NEW: - case Membership::ADD_ACCEPTED_REDUNDANT: - trustEstablished = true; - break; - case Membership::ADD_DEFERRED_FOR_WHOIS: - return false; - } - } - } - } - ++p; // skip trailing 0 after COMs if present + unsigned int p = ZT_PACKET_IDX_PAYLOAD; + while ((p < size()) && ((*this)[p] != 0)) { + p += com.deserialize(*this, p); + if (com) { + network = RR->node->network(com.networkId()); + if (network) { + switch (network->addCredential(tPtr, com)) { + case Membership::ADD_REJECTED: + break; + case Membership::ADD_ACCEPTED_NEW: + case Membership::ADD_ACCEPTED_REDUNDANT: + trustEstablished = true; + break; + case Membership::ADD_DEFERRED_FOR_WHOIS: + return false; + } + } + } + } + ++p; // skip trailing 0 after COMs if present - if (p < size()) { // older ZeroTier versions do not send capabilities, tags, or revocations - const unsigned int numCapabilities = at(p); - p += 2; - for(unsigned int i=0;iid() != cap.networkId())) { - network = RR->node->network(cap.networkId()); - } - if (network) { - switch (network->addCredential(tPtr,cap)) { - case Membership::ADD_REJECTED: - break; - case Membership::ADD_ACCEPTED_NEW: - case Membership::ADD_ACCEPTED_REDUNDANT: - trustEstablished = true; - break; - case Membership::ADD_DEFERRED_FOR_WHOIS: - return false; - } - } - } + if (p < size()) { // older ZeroTier versions do not send capabilities, tags, or revocations + const unsigned int numCapabilities = at(p); + p += 2; + for (unsigned int i = 0; i < numCapabilities; ++i) { + p += cap.deserialize(*this, p); + if ((! network) || (network->id() != cap.networkId())) { + network = RR->node->network(cap.networkId()); + } + if (network) { + switch (network->addCredential(tPtr, cap)) { + case Membership::ADD_REJECTED: + break; + case Membership::ADD_ACCEPTED_NEW: + case Membership::ADD_ACCEPTED_REDUNDANT: + trustEstablished = true; + break; + case Membership::ADD_DEFERRED_FOR_WHOIS: + return false; + } + } + } - if (p >= size()) { - return true; - } + if (p >= size()) { + return true; + } - const unsigned int numTags = at(p); - p += 2; - for(unsigned int i=0;iid() != tag.networkId())) { - network = RR->node->network(tag.networkId()); - } - if (network) { - switch (network->addCredential(tPtr,tag)) { - case Membership::ADD_REJECTED: - break; - case Membership::ADD_ACCEPTED_NEW: - case Membership::ADD_ACCEPTED_REDUNDANT: - trustEstablished = true; - break; - case Membership::ADD_DEFERRED_FOR_WHOIS: - return false; - } - } - } + const unsigned int numTags = at(p); + p += 2; + for (unsigned int i = 0; i < numTags; ++i) { + p += tag.deserialize(*this, p); + if ((! network) || (network->id() != tag.networkId())) { + network = RR->node->network(tag.networkId()); + } + if (network) { + switch (network->addCredential(tPtr, tag)) { + case Membership::ADD_REJECTED: + break; + case Membership::ADD_ACCEPTED_NEW: + case Membership::ADD_ACCEPTED_REDUNDANT: + trustEstablished = true; + break; + case Membership::ADD_DEFERRED_FOR_WHOIS: + return false; + } + } + } - if (p >= size()) { - return true; - } + if (p >= size()) { + return true; + } - const unsigned int numRevocations = at(p); - p += 2; - for(unsigned int i=0;iid() != revocation.networkId())) { - network = RR->node->network(revocation.networkId()); - } - if (network) { - switch(network->addCredential(tPtr,peer->address(),revocation)) { - case Membership::ADD_REJECTED: - break; - case Membership::ADD_ACCEPTED_NEW: - case Membership::ADD_ACCEPTED_REDUNDANT: - trustEstablished = true; - break; - case Membership::ADD_DEFERRED_FOR_WHOIS: - return false; - } - } - } + const unsigned int numRevocations = at(p); + p += 2; + for (unsigned int i = 0; i < numRevocations; ++i) { + p += revocation.deserialize(*this, p); + if ((! network) || (network->id() != revocation.networkId())) { + network = RR->node->network(revocation.networkId()); + } + if (network) { + switch (network->addCredential(tPtr, peer->address(), revocation)) { + case Membership::ADD_REJECTED: + break; + case Membership::ADD_ACCEPTED_NEW: + case Membership::ADD_ACCEPTED_REDUNDANT: + trustEstablished = true; + break; + case Membership::ADD_DEFERRED_FOR_WHOIS: + return false; + } + } + } - if (p >= size()) { - return true; - } + if (p >= size()) { + return true; + } - const unsigned int numCoos = at(p); - p += 2; - for(unsigned int i=0;iid() != coo.networkId())) { - network = RR->node->network(coo.networkId()); - } - if (network) { - switch(network->addCredential(tPtr,coo)) { - case Membership::ADD_REJECTED: - break; - case Membership::ADD_ACCEPTED_NEW: - case Membership::ADD_ACCEPTED_REDUNDANT: - trustEstablished = true; - break; - case Membership::ADD_DEFERRED_FOR_WHOIS: - return false; - } - } - } - } + const unsigned int numCoos = at(p); + p += 2; + for (unsigned int i = 0; i < numCoos; ++i) { + p += coo.deserialize(*this, p); + if ((! network) || (network->id() != coo.networkId())) { + network = RR->node->network(coo.networkId()); + } + if (network) { + switch (network->addCredential(tPtr, coo)) { + case Membership::ADD_REJECTED: + break; + case Membership::ADD_ACCEPTED_NEW: + case Membership::ADD_ACCEPTED_REDUNDANT: + trustEstablished = true; + break; + case Membership::ADD_DEFERRED_FOR_WHOIS: + return false; + } + } + } + } - peer->received(tPtr,_path,hops(),packetId(),payloadLength(),Packet::VERB_NETWORK_CREDENTIALS,0,Packet::VERB_NOP,trustEstablished,(network) ? network->id() : 0,ZT_QOS_NO_FLOW); + peer->received(tPtr, _path, hops(), packetId(), payloadLength(), Packet::VERB_NETWORK_CREDENTIALS, 0, Packet::VERB_NOP, trustEstablished, (network) ? network->id() : 0, ZT_QOS_NO_FLOW); - return true; + return true; } -bool IncomingPacket::_doNETWORK_CONFIG_REQUEST(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer) +bool IncomingPacket::_doNETWORK_CONFIG_REQUEST(const RuntimeEnvironment* RR, void* tPtr, const SharedPtr& peer) { - Metrics::pkt_network_config_request_in++; - const uint64_t nwid = at(ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST_IDX_NETWORK_ID); - const unsigned int hopCount = hops(); - const uint64_t requestPacketId = packetId(); + Metrics::pkt_network_config_request_in++; + const uint64_t nwid = at(ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST_IDX_NETWORK_ID); + const unsigned int hopCount = hops(); + const uint64_t requestPacketId = packetId(); - if (RR->localNetworkController) { - const unsigned int metaDataLength = (ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST_IDX_DICT_LEN <= size()) ? at(ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST_IDX_DICT_LEN) : 0; - const char *metaDataBytes = (metaDataLength != 0) ? (const char *)field(ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST_IDX_DICT,metaDataLength) : (const char *)0; - const Dictionary metaData(metaDataBytes,metaDataLength); - RR->localNetworkController->request(nwid,(hopCount > 0) ? InetAddress() : _path->address(),requestPacketId,peer->identity(),metaData); - } else { - Packet outp(peer->address(),RR->identity.address(),Packet::VERB_ERROR); - outp.append((unsigned char)Packet::VERB_NETWORK_CONFIG_REQUEST); - outp.append(requestPacketId); - outp.append((unsigned char)Packet::ERROR_UNSUPPORTED_OPERATION); - outp.append(nwid); - outp.armor(peer->key(),true,peer->aesKeysIfSupported()); - Metrics::pkt_error_out++; - Metrics::pkt_error_unsupported_op_out++; - _path->send(RR,tPtr,outp.data(),outp.size(),RR->node->now()); - } + if (RR->localNetworkController) { + const unsigned int metaDataLength = (ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST_IDX_DICT_LEN <= size()) ? at(ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST_IDX_DICT_LEN) : 0; + const char* metaDataBytes = (metaDataLength != 0) ? (const char*)field(ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST_IDX_DICT, metaDataLength) : (const char*)0; + const Dictionary metaData(metaDataBytes, metaDataLength); + RR->localNetworkController->request(nwid, (hopCount > 0) ? InetAddress() : _path->address(), requestPacketId, peer->identity(), metaData); + } + else { + Packet outp(peer->address(), RR->identity.address(), Packet::VERB_ERROR); + outp.append((unsigned char)Packet::VERB_NETWORK_CONFIG_REQUEST); + outp.append(requestPacketId); + outp.append((unsigned char)Packet::ERROR_UNSUPPORTED_OPERATION); + outp.append(nwid); + outp.armor(peer->key(), true, false, peer->aesKeysIfSupported(), peer->identity()); + Metrics::pkt_error_out++; + Metrics::pkt_error_unsupported_op_out++; + _path->send(RR, tPtr, outp.data(), outp.size(), RR->node->now()); + } - peer->received(tPtr,_path,hopCount,requestPacketId,payloadLength(),Packet::VERB_NETWORK_CONFIG_REQUEST,0,Packet::VERB_NOP,false,nwid,ZT_QOS_NO_FLOW); + peer->received(tPtr, _path, hopCount, requestPacketId, payloadLength(), Packet::VERB_NETWORK_CONFIG_REQUEST, 0, Packet::VERB_NOP, false, nwid, ZT_QOS_NO_FLOW); - return true; + return true; } -bool IncomingPacket::_doNETWORK_CONFIG(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer) +bool IncomingPacket::_doNETWORK_CONFIG(const RuntimeEnvironment* RR, void* tPtr, const SharedPtr& peer) { - Metrics::pkt_network_config_in++; - const SharedPtr network(RR->node->network(at(ZT_PACKET_IDX_PAYLOAD))); - if (network) { - const uint64_t configUpdateId = network->handleConfigChunk(tPtr,packetId(),source(),*this,ZT_PACKET_IDX_PAYLOAD); - if (configUpdateId) { - Packet outp(peer->address(), RR->identity.address(), Packet::VERB_OK); - outp.append((uint8_t)Packet::VERB_ECHO); - outp.append((uint64_t)packetId()); - outp.append((uint64_t)network->id()); - outp.append((uint64_t)configUpdateId); - const int64_t now = RR->node->now(); - outp.armor(peer->key(),true,peer->aesKeysIfSupported()); - peer->recordOutgoingPacket(_path,outp.packetId(),outp.payloadLength(),outp.verb(),ZT_QOS_NO_FLOW,now); - Metrics::pkt_ok_out++; - _path->send(RR,tPtr,outp.data(),outp.size(),RR->node->now()); - } - } + Metrics::pkt_network_config_in++; + const SharedPtr network(RR->node->network(at(ZT_PACKET_IDX_PAYLOAD))); + if (network) { + const uint64_t configUpdateId = network->handleConfigChunk(tPtr, packetId(), source(), *this, ZT_PACKET_IDX_PAYLOAD); + if (configUpdateId) { + Packet outp(peer->address(), RR->identity.address(), Packet::VERB_OK); + outp.append((uint8_t)Packet::VERB_ECHO); + outp.append((uint64_t)packetId()); + outp.append((uint64_t)network->id()); + outp.append((uint64_t)configUpdateId); + const int64_t now = RR->node->now(); + outp.armor(peer->key(), true, false, peer->aesKeysIfSupported(), peer->identity()); + peer->recordOutgoingPacket(_path, outp.packetId(), outp.payloadLength(), outp.verb(), ZT_QOS_NO_FLOW, now); + Metrics::pkt_ok_out++; + _path->send(RR, tPtr, outp.data(), outp.size(), RR->node->now()); + } + } - peer->received(tPtr,_path,hops(),packetId(),payloadLength(),Packet::VERB_NETWORK_CONFIG,0,Packet::VERB_NOP,false,(network) ? network->id() : 0,ZT_QOS_NO_FLOW); + peer->received(tPtr, _path, hops(), packetId(), payloadLength(), Packet::VERB_NETWORK_CONFIG, 0, Packet::VERB_NOP, false, (network) ? network->id() : 0, ZT_QOS_NO_FLOW); - return true; + return true; } -bool IncomingPacket::_doMULTICAST_GATHER(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer) +bool IncomingPacket::_doMULTICAST_GATHER(const RuntimeEnvironment* RR, void* tPtr, const SharedPtr& peer) { - Metrics::pkt_multicast_gather_in++; - const uint64_t nwid = at(ZT_PROTO_VERB_MULTICAST_GATHER_IDX_NETWORK_ID); - const unsigned int flags = (*this)[ZT_PROTO_VERB_MULTICAST_GATHER_IDX_FLAGS]; - const MulticastGroup mg(MAC(field(ZT_PROTO_VERB_MULTICAST_GATHER_IDX_MAC,6),6),at(ZT_PROTO_VERB_MULTICAST_GATHER_IDX_ADI)); - const unsigned int gatherLimit = at(ZT_PROTO_VERB_MULTICAST_GATHER_IDX_GATHER_LIMIT); + Metrics::pkt_multicast_gather_in++; + const uint64_t nwid = at(ZT_PROTO_VERB_MULTICAST_GATHER_IDX_NETWORK_ID); + const unsigned int flags = (*this)[ZT_PROTO_VERB_MULTICAST_GATHER_IDX_FLAGS]; + const MulticastGroup mg(MAC(field(ZT_PROTO_VERB_MULTICAST_GATHER_IDX_MAC, 6), 6), at(ZT_PROTO_VERB_MULTICAST_GATHER_IDX_ADI)); + const unsigned int gatherLimit = at(ZT_PROTO_VERB_MULTICAST_GATHER_IDX_GATHER_LIMIT); - const SharedPtr network(RR->node->network(nwid)); + const SharedPtr network(RR->node->network(nwid)); - if ((flags & 0x01) != 0) { - try { - CertificateOfMembership com; - com.deserialize(*this,ZT_PROTO_VERB_MULTICAST_GATHER_IDX_COM); - if ((com)&&(network)) { - network->addCredential(tPtr,com); - } - } catch ( ... ) {} // discard invalid COMs - } + if ((flags & 0x01) != 0) { + try { + CertificateOfMembership com; + com.deserialize(*this, ZT_PROTO_VERB_MULTICAST_GATHER_IDX_COM); + if ((com) && (network)) { + network->addCredential(tPtr, com); + } + } + catch (...) { + } // discard invalid COMs + } - const bool trustEstablished = (network) ? network->gate(tPtr,peer) : false; - const int64_t now = RR->node->now(); - if ((gatherLimit > 0)&&((trustEstablished)||(RR->topology->amUpstream())||(RR->node->localControllerHasAuthorized(now,nwid,peer->address())))) { - Packet outp(peer->address(),RR->identity.address(),Packet::VERB_OK); - outp.append((unsigned char)Packet::VERB_MULTICAST_GATHER); - outp.append(packetId()); - outp.append(nwid); - mg.mac().appendTo(outp); - outp.append((uint32_t)mg.adi()); - const unsigned int gatheredLocally = RR->mc->gather(peer->address(),nwid,mg,outp,gatherLimit); - if (gatheredLocally > 0) { - outp.armor(peer->key(),true,peer->aesKeysIfSupported()); - peer->recordOutgoingPacket(_path,outp.packetId(),outp.payloadLength(),outp.verb(),ZT_QOS_NO_FLOW,now); - Metrics::pkt_ok_out++; - _path->send(RR,tPtr,outp.data(),outp.size(),now); - } - } + const bool trustEstablished = (network) ? network->gate(tPtr, peer) : false; + const int64_t now = RR->node->now(); + if ((gatherLimit > 0) && ((trustEstablished) || (RR->topology->amUpstream()) || (RR->node->localControllerHasAuthorized(now, nwid, peer->address())))) { + Packet outp(peer->address(), RR->identity.address(), Packet::VERB_OK); + outp.append((unsigned char)Packet::VERB_MULTICAST_GATHER); + outp.append(packetId()); + outp.append(nwid); + mg.mac().appendTo(outp); + outp.append((uint32_t)mg.adi()); + const unsigned int gatheredLocally = RR->mc->gather(peer->address(), nwid, mg, outp, gatherLimit); + if (gatheredLocally > 0) { + outp.armor(peer->key(), true, false, peer->aesKeysIfSupported(), peer->identity()); + peer->recordOutgoingPacket(_path, outp.packetId(), outp.payloadLength(), outp.verb(), ZT_QOS_NO_FLOW, now); + Metrics::pkt_ok_out++; + _path->send(RR, tPtr, outp.data(), outp.size(), now); + } + } - peer->received(tPtr,_path,hops(),packetId(),payloadLength(),Packet::VERB_MULTICAST_GATHER,0,Packet::VERB_NOP,trustEstablished,nwid,ZT_QOS_NO_FLOW); + peer->received(tPtr, _path, hops(), packetId(), payloadLength(), Packet::VERB_MULTICAST_GATHER, 0, Packet::VERB_NOP, trustEstablished, nwid, ZT_QOS_NO_FLOW); - return true; + return true; } -bool IncomingPacket::_doMULTICAST_FRAME(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer) +bool IncomingPacket::_doMULTICAST_FRAME(const RuntimeEnvironment* RR, void* tPtr, const SharedPtr& peer) { - Metrics::pkt_multicast_frame_in++; - const uint64_t nwid = at(ZT_PROTO_VERB_MULTICAST_FRAME_IDX_NETWORK_ID); - const unsigned int flags = (*this)[ZT_PROTO_VERB_MULTICAST_FRAME_IDX_FLAGS]; + Metrics::pkt_multicast_frame_in++; + const uint64_t nwid = at(ZT_PROTO_VERB_MULTICAST_FRAME_IDX_NETWORK_ID); + const unsigned int flags = (*this)[ZT_PROTO_VERB_MULTICAST_FRAME_IDX_FLAGS]; - const SharedPtr network(RR->node->network(nwid)); - if (network) { - // Offset -- size of optional fields added to position of later fields - unsigned int offset = 0; + const SharedPtr network(RR->node->network(nwid)); + if (network) { + // Offset -- size of optional fields added to position of later fields + unsigned int offset = 0; - if ((flags & 0x01) != 0) { - // This is deprecated but may still be sent by old peers - CertificateOfMembership com; - offset += com.deserialize(*this,ZT_PROTO_VERB_MULTICAST_FRAME_IDX_COM); - if (com) { - network->addCredential(tPtr,com); - } - } + if ((flags & 0x01) != 0) { + // This is deprecated but may still be sent by old peers + CertificateOfMembership com; + offset += com.deserialize(*this, ZT_PROTO_VERB_MULTICAST_FRAME_IDX_COM); + if (com) { + network->addCredential(tPtr, com); + } + } - if (!network->gate(tPtr,peer)) { - _sendErrorNeedCredentials(RR,tPtr,peer,nwid); - return false; - } + if (! network->gate(tPtr, peer)) { + _sendErrorNeedCredentials(RR, tPtr, peer, nwid); + return false; + } - unsigned int gatherLimit = 0; - if ((flags & 0x02) != 0) { - gatherLimit = at(offset + ZT_PROTO_VERB_MULTICAST_FRAME_IDX_GATHER_LIMIT); - offset += 4; - } + unsigned int gatherLimit = 0; + if ((flags & 0x02) != 0) { + gatherLimit = at(offset + ZT_PROTO_VERB_MULTICAST_FRAME_IDX_GATHER_LIMIT); + offset += 4; + } - MAC from; - if ((flags & 0x04) != 0) { - from.setTo(field(offset + ZT_PROTO_VERB_MULTICAST_FRAME_IDX_SOURCE_MAC,6),6); - offset += 6; - } else { - from.fromAddress(peer->address(),nwid); - } + MAC from; + if ((flags & 0x04) != 0) { + from.setTo(field(offset + ZT_PROTO_VERB_MULTICAST_FRAME_IDX_SOURCE_MAC, 6), 6); + offset += 6; + } + else { + from.fromAddress(peer->address(), nwid); + } - const MulticastGroup to(MAC(field(offset + ZT_PROTO_VERB_MULTICAST_FRAME_IDX_DEST_MAC,6),6),at(offset + ZT_PROTO_VERB_MULTICAST_FRAME_IDX_DEST_ADI)); - const unsigned int etherType = at(offset + ZT_PROTO_VERB_MULTICAST_FRAME_IDX_ETHERTYPE); - const unsigned int frameLen = size() - (offset + ZT_PROTO_VERB_MULTICAST_FRAME_IDX_FRAME); + const MulticastGroup to(MAC(field(offset + ZT_PROTO_VERB_MULTICAST_FRAME_IDX_DEST_MAC, 6), 6), at(offset + ZT_PROTO_VERB_MULTICAST_FRAME_IDX_DEST_ADI)); + const unsigned int etherType = at(offset + ZT_PROTO_VERB_MULTICAST_FRAME_IDX_ETHERTYPE); + const unsigned int frameLen = size() - (offset + ZT_PROTO_VERB_MULTICAST_FRAME_IDX_FRAME); - if (network->config().multicastLimit == 0) { - RR->t->incomingNetworkFrameDropped(tPtr,network,_path,packetId(),size(),peer->address(),Packet::VERB_MULTICAST_FRAME,from,to.mac(),"multicast disabled"); - peer->received(tPtr,_path,hops(),packetId(),payloadLength(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,false,nwid,ZT_QOS_NO_FLOW); - return true; - } + if (network->config().multicastLimit == 0) { + RR->t->incomingNetworkFrameDropped(tPtr, network, _path, packetId(), size(), peer->address(), Packet::VERB_MULTICAST_FRAME, from, to.mac(), "multicast disabled"); + peer->received(tPtr, _path, hops(), packetId(), payloadLength(), Packet::VERB_MULTICAST_FRAME, 0, Packet::VERB_NOP, false, nwid, ZT_QOS_NO_FLOW); + return true; + } - if ((frameLen > 0)&&(frameLen <= ZT_MAX_MTU)) { - if (!to.mac().isMulticast()) { - RR->t->incomingPacketInvalid(tPtr,_path,packetId(),source(),hops(),Packet::VERB_MULTICAST_FRAME,"destination not multicast"); - peer->received(tPtr,_path,hops(),packetId(),payloadLength(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,true,nwid,ZT_QOS_NO_FLOW); // trustEstablished because COM is okay - return true; - } - if ((!from)||(from.isMulticast())||(from == network->mac())) { - RR->t->incomingPacketInvalid(tPtr,_path,packetId(),source(),hops(),Packet::VERB_MULTICAST_FRAME,"invalid source MAC"); - peer->received(tPtr,_path,hops(),packetId(),payloadLength(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,true,nwid,ZT_QOS_NO_FLOW); // trustEstablished because COM is okay - return true; - } + if ((frameLen > 0) && (frameLen <= ZT_MAX_MTU)) { + if (! to.mac().isMulticast()) { + RR->t->incomingPacketInvalid(tPtr, _path, packetId(), source(), hops(), Packet::VERB_MULTICAST_FRAME, "destination not multicast"); + peer->received(tPtr, _path, hops(), packetId(), payloadLength(), Packet::VERB_MULTICAST_FRAME, 0, Packet::VERB_NOP, true, nwid, ZT_QOS_NO_FLOW); // trustEstablished because COM is okay + return true; + } + if ((! from) || (from.isMulticast()) || (from == network->mac())) { + RR->t->incomingPacketInvalid(tPtr, _path, packetId(), source(), hops(), Packet::VERB_MULTICAST_FRAME, "invalid source MAC"); + peer->received(tPtr, _path, hops(), packetId(), payloadLength(), Packet::VERB_MULTICAST_FRAME, 0, Packet::VERB_NOP, true, nwid, ZT_QOS_NO_FLOW); // trustEstablished because COM is okay + return true; + } - const uint8_t *const frameData = (const uint8_t *)field(offset + ZT_PROTO_VERB_MULTICAST_FRAME_IDX_FRAME,frameLen); + const uint8_t* const frameData = (const uint8_t*)field(offset + ZT_PROTO_VERB_MULTICAST_FRAME_IDX_FRAME, frameLen); - if ((flags & 0x08)&&(network->config().isMulticastReplicator(RR->identity.address()))) { - RR->mc->send(tPtr,RR->node->now(),network,peer->address(),to,from,etherType,frameData,frameLen); - } + if ((flags & 0x08) && (network->config().isMulticastReplicator(RR->identity.address()))) { + RR->mc->send(tPtr, RR->node->now(), network, peer->address(), to, from, etherType, frameData, frameLen); + } - if (from != MAC(peer->address(),nwid)) { - if (network->config().permitsBridging(peer->address())) { - network->learnBridgeRoute(from,peer->address()); - } else { - RR->t->incomingNetworkFrameDropped(tPtr,network,_path,packetId(),size(),peer->address(),Packet::VERB_MULTICAST_FRAME,from,to.mac(),"bridging not allowed (remote)"); - peer->received(tPtr,_path,hops(),packetId(),payloadLength(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,true,nwid,ZT_QOS_NO_FLOW); // trustEstablished because COM is okay - return true; - } - } + if (from != MAC(peer->address(), nwid)) { + if (network->config().permitsBridging(peer->address())) { + network->learnBridgeRoute(from, peer->address()); + } + else { + RR->t->incomingNetworkFrameDropped(tPtr, network, _path, packetId(), size(), peer->address(), Packet::VERB_MULTICAST_FRAME, from, to.mac(), "bridging not allowed (remote)"); + peer->received(tPtr, _path, hops(), packetId(), payloadLength(), Packet::VERB_MULTICAST_FRAME, 0, Packet::VERB_NOP, true, nwid, ZT_QOS_NO_FLOW); // trustEstablished because COM is okay + return true; + } + } - if (network->filterIncomingPacket(tPtr,peer,RR->identity.address(),from,to.mac(),frameData,frameLen,etherType,0) > 0) { - RR->node->putFrame(tPtr,nwid,network->userPtr(),from,to.mac(),etherType,0,(const void *)frameData,frameLen); - } - } + if (network->filterIncomingPacket(tPtr, peer, RR->identity.address(), from, to.mac(), frameData, frameLen, etherType, 0) > 0) { + RR->node->putFrame(tPtr, nwid, network->userPtr(), from, to.mac(), etherType, 0, (const void*)frameData, frameLen); + } + } - if (gatherLimit) { - Packet outp(source(),RR->identity.address(),Packet::VERB_OK); - outp.append((unsigned char)Packet::VERB_MULTICAST_FRAME); - outp.append(packetId()); - outp.append(nwid); - to.mac().appendTo(outp); - outp.append((uint32_t)to.adi()); - outp.append((unsigned char)0x02); // flag 0x02 = contains gather results - if (RR->mc->gather(peer->address(),nwid,to,outp,gatherLimit)) { - const int64_t now = RR->node->now(); - outp.armor(peer->key(),true,peer->aesKeysIfSupported()); - peer->recordOutgoingPacket(_path,outp.packetId(),outp.payloadLength(),outp.verb(),ZT_QOS_NO_FLOW,now); - Metrics::pkt_ok_out++; - _path->send(RR,tPtr,outp.data(),outp.size(),RR->node->now()); - } - } + if (gatherLimit) { + Packet outp(source(), RR->identity.address(), Packet::VERB_OK); + outp.append((unsigned char)Packet::VERB_MULTICAST_FRAME); + outp.append(packetId()); + outp.append(nwid); + to.mac().appendTo(outp); + outp.append((uint32_t)to.adi()); + outp.append((unsigned char)0x02); // flag 0x02 = contains gather results + if (RR->mc->gather(peer->address(), nwid, to, outp, gatherLimit)) { + const int64_t now = RR->node->now(); + outp.armor(peer->key(), true, false, peer->aesKeysIfSupported(), peer->identity()); + peer->recordOutgoingPacket(_path, outp.packetId(), outp.payloadLength(), outp.verb(), ZT_QOS_NO_FLOW, now); + Metrics::pkt_ok_out++; + _path->send(RR, tPtr, outp.data(), outp.size(), RR->node->now()); + } + } - peer->received(tPtr,_path,hops(),packetId(),payloadLength(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,true,nwid,ZT_QOS_NO_FLOW); - } + peer->received(tPtr, _path, hops(), packetId(), payloadLength(), Packet::VERB_MULTICAST_FRAME, 0, Packet::VERB_NOP, true, nwid, ZT_QOS_NO_FLOW); + } - return true; + return true; } -bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer) +bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment* RR, void* tPtr, const SharedPtr& peer) { - Metrics::pkt_push_direct_paths_in++; - const int64_t now = RR->node->now(); + Metrics::pkt_push_direct_paths_in++; + const int64_t now = RR->node->now(); - if (!peer->rateGatePushDirectPaths(now)) { - peer->received(tPtr,_path,hops(),packetId(),payloadLength(),Packet::VERB_PUSH_DIRECT_PATHS,0,Packet::VERB_NOP,false,0,ZT_QOS_NO_FLOW); - return true; - } + if (! peer->rateGatePushDirectPaths(now)) { + peer->received(tPtr, _path, hops(), packetId(), payloadLength(), Packet::VERB_PUSH_DIRECT_PATHS, 0, Packet::VERB_NOP, false, 0, ZT_QOS_NO_FLOW); + return true; + } - // Second, limit addresses by scope and type - uint8_t countPerScope[ZT_INETADDRESS_MAX_SCOPE+1][2]; // [][0] is v4, [][1] is v6 - memset(countPerScope,0,sizeof(countPerScope)); + // Second, limit addresses by scope and type + uint8_t countPerScope[ZT_INETADDRESS_MAX_SCOPE + 1][2]; // [][0] is v4, [][1] is v6 + memset(countPerScope, 0, sizeof(countPerScope)); - unsigned int count = at(ZT_PACKET_IDX_PAYLOAD); - unsigned int ptr = ZT_PACKET_IDX_PAYLOAD + 2; + unsigned int count = at(ZT_PACKET_IDX_PAYLOAD); + unsigned int ptr = ZT_PACKET_IDX_PAYLOAD + 2; - while (count--) { // if ptr overflows Buffer will throw - unsigned int flags = (*this)[ptr++]; - unsigned int extLen = at(ptr); - ptr += 2; - ptr += extLen; // unused right now - unsigned int addrType = (*this)[ptr++]; - unsigned int addrLen = (*this)[ptr++]; + while (count--) { // if ptr overflows Buffer will throw + unsigned int flags = (*this)[ptr++]; + unsigned int extLen = at(ptr); + ptr += 2; + ptr += extLen; // unused right now + unsigned int addrType = (*this)[ptr++]; + unsigned int addrLen = (*this)[ptr++]; - switch(addrType) { - case 4: { - const InetAddress a(field(ptr,4),4,at(ptr + 4)); - if ( - ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_FORGET_PATH) == 0) && // not being told to forget - (!( ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_CLUSTER_REDIRECT) == 0) && (peer->hasActivePathTo(now,a)) )) && // not already known - (RR->node->shouldUsePathForZeroTierTraffic(tPtr,peer->address(),_path->localSocket(),a)) ) // should use path - { - if ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_CLUSTER_REDIRECT) != 0) { - peer->clusterRedirect(tPtr,_path,a,now); - } else if (++countPerScope[(int)a.ipScope()][0] <= ZT_PUSH_DIRECT_PATHS_MAX_PER_SCOPE_AND_FAMILY) { - peer->attemptToContactAt(tPtr,InetAddress(),a,now,false); - } - } - } break; - case 6: { + switch (addrType) { + case 4: { + const InetAddress a(field(ptr, 4), 4, at(ptr + 4)); + if (((flags & ZT_PUSH_DIRECT_PATHS_FLAG_FORGET_PATH) == 0) && // not being told to forget + (! (((flags & ZT_PUSH_DIRECT_PATHS_FLAG_CLUSTER_REDIRECT) == 0) && (peer->hasActivePathTo(now, a)))) && // not already known + (RR->node->shouldUsePathForZeroTierTraffic(tPtr, peer->address(), _path->localSocket(), a))) // should use path + { + if ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_CLUSTER_REDIRECT) != 0) { + peer->clusterRedirect(tPtr, _path, a, now); + } + else if (++countPerScope[(int)a.ipScope()][0] <= ZT_PUSH_DIRECT_PATHS_MAX_PER_SCOPE_AND_FAMILY) { + peer->attemptToContactAt(tPtr, InetAddress(), a, now, false); + } + } + } break; + case 6: { + const InetAddress a(field(ptr, 16), 16, at(ptr + 16)); + if (((flags & ZT_PUSH_DIRECT_PATHS_FLAG_FORGET_PATH) == 0) && // not being told to forget + (! (((flags & ZT_PUSH_DIRECT_PATHS_FLAG_CLUSTER_REDIRECT) == 0) && (peer->hasActivePathTo(now, a)))) && // not already known + (RR->node->shouldUsePathForZeroTierTraffic(tPtr, peer->address(), _path->localSocket(), a))) // should use path + { + if ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_CLUSTER_REDIRECT) != 0) { + peer->clusterRedirect(tPtr, _path, a, now); + } + else if (++countPerScope[(int)a.ipScope()][1] <= ZT_PUSH_DIRECT_PATHS_MAX_PER_SCOPE_AND_FAMILY) { + peer->attemptToContactAt(tPtr, InetAddress(), a, now, false); + } + } + } break; + } + ptr += addrLen; + } - const InetAddress a(field(ptr,16),16,at(ptr + 16)); - if ( - ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_FORGET_PATH) == 0) && // not being told to forget - (!( ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_CLUSTER_REDIRECT) == 0) && (peer->hasActivePathTo(now,a)) )) && // not already known - (RR->node->shouldUsePathForZeroTierTraffic(tPtr,peer->address(),_path->localSocket(),a)) ) // should use path - { - if ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_CLUSTER_REDIRECT) != 0) { - peer->clusterRedirect(tPtr,_path,a,now); - } else if (++countPerScope[(int)a.ipScope()][1] <= ZT_PUSH_DIRECT_PATHS_MAX_PER_SCOPE_AND_FAMILY) { - peer->attemptToContactAt(tPtr,InetAddress(),a,now,false); - } - } - } break; - } - ptr += addrLen; - } + peer->received(tPtr, _path, hops(), packetId(), payloadLength(), Packet::VERB_PUSH_DIRECT_PATHS, 0, Packet::VERB_NOP, false, 0, ZT_QOS_NO_FLOW); - peer->received(tPtr,_path,hops(),packetId(),payloadLength(),Packet::VERB_PUSH_DIRECT_PATHS,0,Packet::VERB_NOP,false,0,ZT_QOS_NO_FLOW); - - return true; + return true; } -bool IncomingPacket::_doUSER_MESSAGE(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer) +bool IncomingPacket::_doUSER_MESSAGE(const RuntimeEnvironment* RR, void* tPtr, const SharedPtr& peer) { - Metrics::pkt_user_message_in++; - if (likely(size() >= (ZT_PACKET_IDX_PAYLOAD + 8))) { - ZT_UserMessage um; - um.origin = peer->address().toInt(); - um.typeId = at(ZT_PACKET_IDX_PAYLOAD); - um.data = reinterpret_cast(reinterpret_cast(data()) + ZT_PACKET_IDX_PAYLOAD + 8); - um.length = size() - (ZT_PACKET_IDX_PAYLOAD + 8); - RR->node->postEvent(tPtr,ZT_EVENT_USER_MESSAGE,reinterpret_cast(&um)); - } + Metrics::pkt_user_message_in++; + if (likely(size() >= (ZT_PACKET_IDX_PAYLOAD + 8))) { + ZT_UserMessage um; + um.origin = peer->address().toInt(); + um.typeId = at(ZT_PACKET_IDX_PAYLOAD); + um.data = reinterpret_cast(reinterpret_cast(data()) + ZT_PACKET_IDX_PAYLOAD + 8); + um.length = size() - (ZT_PACKET_IDX_PAYLOAD + 8); + RR->node->postEvent(tPtr, ZT_EVENT_USER_MESSAGE, reinterpret_cast(&um)); + } - peer->received(tPtr,_path,hops(),packetId(),payloadLength(),Packet::VERB_USER_MESSAGE,0,Packet::VERB_NOP,false,0,ZT_QOS_NO_FLOW); + peer->received(tPtr, _path, hops(), packetId(), payloadLength(), Packet::VERB_USER_MESSAGE, 0, Packet::VERB_NOP, false, 0, ZT_QOS_NO_FLOW); - return true; + return true; } -bool IncomingPacket::_doREMOTE_TRACE(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer) +bool IncomingPacket::_doREMOTE_TRACE(const RuntimeEnvironment* RR, void* tPtr, const SharedPtr& peer) { - Metrics::pkt_remote_trace_in++; - ZT_RemoteTrace rt; - const char *ptr = reinterpret_cast(data()) + ZT_PACKET_IDX_PAYLOAD; - const char *const eof = reinterpret_cast(data()) + size(); - rt.origin = peer->address().toInt(); - rt.data = const_cast(ptr); // start of first string - while (ptr < eof) { - if (!*ptr) { // end of string - rt.len = (unsigned int)(ptr - rt.data); - if ((rt.len > 0)&&(rt.len <= ZT_MAX_REMOTE_TRACE_SIZE)) { - RR->node->postEvent(tPtr,ZT_EVENT_REMOTE_TRACE,&rt); - } - rt.data = const_cast(++ptr); // start of next string, if any - } else { - ++ptr; - } - } + Metrics::pkt_remote_trace_in++; + ZT_RemoteTrace rt; + const char* ptr = reinterpret_cast(data()) + ZT_PACKET_IDX_PAYLOAD; + const char* const eof = reinterpret_cast(data()) + size(); + rt.origin = peer->address().toInt(); + rt.data = const_cast(ptr); // start of first string + while (ptr < eof) { + if (! *ptr) { // end of string + rt.len = (unsigned int)(ptr - rt.data); + if ((rt.len > 0) && (rt.len <= ZT_MAX_REMOTE_TRACE_SIZE)) { + RR->node->postEvent(tPtr, ZT_EVENT_REMOTE_TRACE, &rt); + } + rt.data = const_cast(++ptr); // start of next string, if any + } + else { + ++ptr; + } + } - peer->received(tPtr,_path,hops(),packetId(),payloadLength(),Packet::VERB_REMOTE_TRACE,0,Packet::VERB_NOP,false,0,ZT_QOS_NO_FLOW); + peer->received(tPtr, _path, hops(), packetId(), payloadLength(), Packet::VERB_REMOTE_TRACE, 0, Packet::VERB_NOP, false, 0, ZT_QOS_NO_FLOW); - return true; + return true; } -bool IncomingPacket::_doPATH_NEGOTIATION_REQUEST(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer) +bool IncomingPacket::_doPATH_NEGOTIATION_REQUEST(const RuntimeEnvironment* RR, void* tPtr, const SharedPtr& peer) { - Metrics::pkt_path_negotiation_request_in++; - uint64_t now = RR->node->now(); - if (!peer->rateGatePathNegotiation(now, _path)) { - return true; - } - if (payloadLength() != sizeof(int16_t)) { - return true; - } - int16_t remoteUtility = 0; - memcpy(&remoteUtility, payload(), sizeof(int16_t)); - peer->processIncomingPathNegotiationRequest(now, _path, Utils::ntoh(remoteUtility)); - return true; + Metrics::pkt_path_negotiation_request_in++; + uint64_t now = RR->node->now(); + if (! peer->rateGatePathNegotiation(now, _path)) { + return true; + } + if (payloadLength() != sizeof(int16_t)) { + return true; + } + int16_t remoteUtility = 0; + memcpy(&remoteUtility, payload(), sizeof(int16_t)); + peer->processIncomingPathNegotiationRequest(now, _path, Utils::ntoh(remoteUtility)); + return true; } -void IncomingPacket::_sendErrorNeedCredentials(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer,const uint64_t nwid) +void IncomingPacket::_sendErrorNeedCredentials(const RuntimeEnvironment* RR, void* tPtr, const SharedPtr& peer, const uint64_t nwid) { - Packet outp(source(),RR->identity.address(),Packet::VERB_ERROR); - outp.append((uint8_t)verb()); - outp.append(packetId()); - outp.append((uint8_t)Packet::ERROR_NEED_MEMBERSHIP_CERTIFICATE); - outp.append(nwid); - outp.armor(peer->key(),true,peer->aesKeysIfSupported()); - Metrics::pkt_error_out++; - Metrics::pkt_error_need_membership_cert_out++; - _path->send(RR,tPtr,outp.data(),outp.size(),RR->node->now()); + Packet outp(source(), RR->identity.address(), Packet::VERB_ERROR); + outp.append((uint8_t)verb()); + outp.append(packetId()); + outp.append((uint8_t)Packet::ERROR_NEED_MEMBERSHIP_CERTIFICATE); + outp.append(nwid); + outp.armor(peer->key(), true, false, peer->aesKeysIfSupported(), peer->identity()); + Metrics::pkt_error_out++; + Metrics::pkt_error_need_membership_cert_out++; + _path->send(RR, tPtr, outp.data(), outp.size(), RR->node->now()); } -} // namespace ZeroTier +} // namespace ZeroTier diff --git a/node/IncomingPacket.hpp b/node/IncomingPacket.hpp index aa5936ff..c58624aa 100644 --- a/node/IncomingPacket.hpp +++ b/node/IncomingPacket.hpp @@ -14,13 +14,13 @@ #ifndef ZT_INCOMINGPACKET_HPP #define ZT_INCOMINGPACKET_HPP -#include - +#include "MulticastGroup.hpp" #include "Packet.hpp" #include "Path.hpp" -#include "Utils.hpp" -#include "MulticastGroup.hpp" #include "Peer.hpp" +#include "Utils.hpp" + +#include /* * The big picture: @@ -46,102 +46,96 @@ class Network; /** * Subclass of packet that handles the decoding of it */ -class IncomingPacket : public Packet -{ -public: - IncomingPacket() : - Packet(), - _receiveTime(0), - _path(), - _authenticated(false) - { - } +class IncomingPacket : public Packet { + public: + IncomingPacket() : Packet(), _receiveTime(0), _path(), _authenticated(false) + { + } - /** - * Create a new packet-in-decode - * - * @param data Packet data - * @param len Packet length - * @param path Path over which packet arrived - * @param now Current time - * @throws std::out_of_range Range error processing packet - */ - IncomingPacket(const void *data,unsigned int len,const SharedPtr &path,int64_t now) : - Packet(data,len), - _receiveTime(now), - _path(path), - _authenticated(false) - { - } + /** + * Create a new packet-in-decode + * + * @param data Packet data + * @param len Packet length + * @param path Path over which packet arrived + * @param now Current time + * @throws std::out_of_range Range error processing packet + */ + IncomingPacket(const void* data, unsigned int len, const SharedPtr& path, int64_t now) : Packet(data, len), _receiveTime(now), _path(path), _authenticated(false) + { + } - /** - * Init packet-in-decode in place - * - * @param data Packet data - * @param len Packet length - * @param path Path over which packet arrived - * @param now Current time - * @throws std::out_of_range Range error processing packet - */ - inline void init(const void *data,unsigned int len,const SharedPtr &path,int64_t now) - { - copyFrom(data,len); - _receiveTime = now; - _path = path; - _authenticated = false; - } + /** + * Init packet-in-decode in place + * + * @param data Packet data + * @param len Packet length + * @param path Path over which packet arrived + * @param now Current time + * @throws std::out_of_range Range error processing packet + */ + inline void init(const void* data, unsigned int len, const SharedPtr& path, int64_t now) + { + copyFrom(data, len); + _receiveTime = now; + _path = path; + _authenticated = false; + } - /** - * Attempt to decode this packet - * - * Note that this returns 'true' if processing is complete. This says nothing - * about whether the packet was valid. A rejection is 'complete.' - * - * Once true is returned, this must not be called again. The packet's state - * may no longer be valid. - * - * @param RR Runtime environment - * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call - * @return True if decoding and processing is complete, false if caller should try again - */ - bool tryDecode(const RuntimeEnvironment *RR,void *tPtr,int32_t flowId); + /** + * Attempt to decode this packet + * + * Note that this returns 'true' if processing is complete. This says nothing + * about whether the packet was valid. A rejection is 'complete.' + * + * Once true is returned, this must not be called again. The packet's state + * may no longer be valid. + * + * @param RR Runtime environment + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call + * @return True if decoding and processing is complete, false if caller should try again + */ + bool tryDecode(const RuntimeEnvironment* RR, void* tPtr, int32_t flowId); - /** - * @return Time of packet receipt / start of decode - */ - inline uint64_t receiveTime() const { return _receiveTime; } + /** + * @return Time of packet receipt / start of decode + */ + inline uint64_t receiveTime() const + { + return _receiveTime; + } -private: - // These are called internally to handle packet contents once it has - // been authenticated, decrypted, decompressed, and classified. - bool _doERROR(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer); - bool _doHELLO(const RuntimeEnvironment *RR,void *tPtr,const bool alreadyAuthenticated); - bool _doACK(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer); - bool _doQOS_MEASUREMENT(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer); - bool _doOK(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer); - bool _doWHOIS(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer); - bool _doRENDEZVOUS(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer); - bool _doFRAME(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer,int32_t flowId); - bool _doEXT_FRAME(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer,int32_t flowId); - bool _doECHO(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer); - bool _doMULTICAST_LIKE(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer); - bool _doNETWORK_CREDENTIALS(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer); - bool _doNETWORK_CONFIG_REQUEST(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer); - bool _doNETWORK_CONFIG(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer); - bool _doMULTICAST_GATHER(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer); - bool _doMULTICAST_FRAME(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer); - bool _doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer); - bool _doUSER_MESSAGE(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer); - bool _doREMOTE_TRACE(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer); - bool _doPATH_NEGOTIATION_REQUEST(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer); + private: + // These are called internally to handle packet contents once it has + // been authenticated, decrypted, decompressed, and classified. + bool _doERROR(const RuntimeEnvironment* RR, void* tPtr, const SharedPtr& peer); + bool _doHELLO(const RuntimeEnvironment* RR, void* tPtr, const bool alreadyAuthenticated); + bool _doACK(const RuntimeEnvironment* RR, void* tPtr, const SharedPtr& peer); + bool _doQOS_MEASUREMENT(const RuntimeEnvironment* RR, void* tPtr, const SharedPtr& peer); + bool _doOK(const RuntimeEnvironment* RR, void* tPtr, const SharedPtr& peer); + bool _doWHOIS(const RuntimeEnvironment* RR, void* tPtr, const SharedPtr& peer); + bool _doRENDEZVOUS(const RuntimeEnvironment* RR, void* tPtr, const SharedPtr& peer); + bool _doFRAME(const RuntimeEnvironment* RR, void* tPtr, const SharedPtr& peer, int32_t flowId); + bool _doEXT_FRAME(const RuntimeEnvironment* RR, void* tPtr, const SharedPtr& peer, int32_t flowId); + bool _doECHO(const RuntimeEnvironment* RR, void* tPtr, const SharedPtr& peer); + bool _doMULTICAST_LIKE(const RuntimeEnvironment* RR, void* tPtr, const SharedPtr& peer); + bool _doNETWORK_CREDENTIALS(const RuntimeEnvironment* RR, void* tPtr, const SharedPtr& peer); + bool _doNETWORK_CONFIG_REQUEST(const RuntimeEnvironment* RR, void* tPtr, const SharedPtr& peer); + bool _doNETWORK_CONFIG(const RuntimeEnvironment* RR, void* tPtr, const SharedPtr& peer); + bool _doMULTICAST_GATHER(const RuntimeEnvironment* RR, void* tPtr, const SharedPtr& peer); + bool _doMULTICAST_FRAME(const RuntimeEnvironment* RR, void* tPtr, const SharedPtr& peer); + bool _doPUSH_DIRECT_PATHS(const RuntimeEnvironment* RR, void* tPtr, const SharedPtr& peer); + bool _doUSER_MESSAGE(const RuntimeEnvironment* RR, void* tPtr, const SharedPtr& peer); + bool _doREMOTE_TRACE(const RuntimeEnvironment* RR, void* tPtr, const SharedPtr& peer); + bool _doPATH_NEGOTIATION_REQUEST(const RuntimeEnvironment* RR, void* tPtr, const SharedPtr& peer); - void _sendErrorNeedCredentials(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr &peer,const uint64_t nwid); + void _sendErrorNeedCredentials(const RuntimeEnvironment* RR, void* tPtr, const SharedPtr& peer, const uint64_t nwid); - uint64_t _receiveTime; - SharedPtr _path; - bool _authenticated; + uint64_t _receiveTime; + SharedPtr _path; + bool _authenticated; }; -} // namespace ZeroTier +} // namespace ZeroTier #endif diff --git a/node/InetAddress.cpp b/node/InetAddress.cpp index 31100d64..02823cfd 100644 --- a/node/InetAddress.cpp +++ b/node/InetAddress.cpp @@ -11,523 +11,532 @@ */ /****/ -#include -#include -#include - -#include +#include "InetAddress.hpp" #include "Constants.hpp" -#include "InetAddress.hpp" #include "Utils.hpp" +#include +#include +#include +#include + namespace ZeroTier { -const InetAddress InetAddress::LO4((const void *)("\x7f\x00\x00\x01"),4,0); -const InetAddress InetAddress::LO6((const void *)("\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01"),16,0); +const InetAddress InetAddress::LO4((const void*)("\x7f\x00\x00\x01"), 4, 0); +const InetAddress InetAddress::LO6((const void*)("\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01"), 16, 0); InetAddress::IpScope InetAddress::ipScope() const { - switch(ss_family) { + switch (ss_family) { + case AF_INET: { + const uint32_t ip = Utils::ntoh((uint32_t)reinterpret_cast(this)->sin_addr.s_addr); + switch (ip >> 24) { + case 0x00: + return IP_SCOPE_NONE; // 0.0.0.0/8 (reserved, never used) + case 0x06: + return IP_SCOPE_PSEUDOPRIVATE; // 6.0.0.0/8 (US Army) + case 0x0a: + return IP_SCOPE_PRIVATE; // 10.0.0.0/8 + case 0x0b: + return IP_SCOPE_PSEUDOPRIVATE; // 11.0.0.0/8 (US DoD) + case 0x15: + return IP_SCOPE_PSEUDOPRIVATE; // 21.0.0.0/8 (US DDN-RVN) + case 0x16: + return IP_SCOPE_PSEUDOPRIVATE; // 22.0.0.0/8 (US DISA) + case 0x19: + return IP_SCOPE_PSEUDOPRIVATE; // 25.0.0.0/8 (UK Ministry of Defense) + case 0x1a: + return IP_SCOPE_PSEUDOPRIVATE; // 26.0.0.0/8 (US DISA) + case 0x1c: + return IP_SCOPE_PSEUDOPRIVATE; // 28.0.0.0/8 (US DSI-North) + case 0x1d: + return IP_SCOPE_PSEUDOPRIVATE; // 29.0.0.0/8 (US DISA) + case 0x1e: + return IP_SCOPE_PSEUDOPRIVATE; // 30.0.0.0/8 (US DISA) + case 0x33: + return IP_SCOPE_PSEUDOPRIVATE; // 51.0.0.0/8 (UK Department of Social Security) + case 0x37: + return IP_SCOPE_PSEUDOPRIVATE; // 55.0.0.0/8 (US DoD) + case 0x38: + return IP_SCOPE_PSEUDOPRIVATE; // 56.0.0.0/8 (US Postal Service) + case 0x64: + if ((ip & 0xffc00000) == 0x64400000) { + return IP_SCOPE_PRIVATE; // 100.64.0.0/10 + } + break; + case 0x7f: + return IP_SCOPE_LOOPBACK; // 127.0.0.0/8 + case 0xa9: + if ((ip & 0xffff0000) == 0xa9fe0000) { + return IP_SCOPE_LINK_LOCAL; // 169.254.0.0/16 + } + break; + case 0xac: + if ((ip & 0xfff00000) == 0xac100000) { + return IP_SCOPE_PRIVATE; // 172.16.0.0/12 + } + break; + case 0xc0: + if ((ip & 0xffff0000) == 0xc0a80000) { + return IP_SCOPE_PRIVATE; // 192.168.0.0/16 + } + if ((ip & 0xffffff00) == 0xc0000200) { + return IP_SCOPE_PRIVATE; // 192.0.2.0/24 + } + break; + case 0xc6: + if ((ip & 0xfffe0000) == 0xc6120000) { + return IP_SCOPE_PRIVATE; // 198.18.0.0/15 + } + if ((ip & 0xffffff00) == 0xc6336400) { + return IP_SCOPE_PRIVATE; // 198.51.100.0/24 + } + break; + case 0xcb: + if ((ip & 0xffffff00) == 0xcb007100) { + return IP_SCOPE_PRIVATE; // 203.0.113.0/24 + } + break; + case 0xff: + return IP_SCOPE_NONE; // 255.0.0.0/8 (broadcast, or unused/unusable) + } + switch (ip >> 28) { + case 0xe: + return IP_SCOPE_MULTICAST; // 224.0.0.0/4 + case 0xf: + return IP_SCOPE_PSEUDOPRIVATE; // 240.0.0.0/4 ("reserved," usually unusable) + } + return IP_SCOPE_GLOBAL; + } break; - case AF_INET: { - const uint32_t ip = Utils::ntoh((uint32_t)reinterpret_cast(this)->sin_addr.s_addr); - switch(ip >> 24) { - case 0x00: - return IP_SCOPE_NONE; // 0.0.0.0/8 (reserved, never used) - case 0x06: - return IP_SCOPE_PSEUDOPRIVATE; // 6.0.0.0/8 (US Army) - case 0x0a: - return IP_SCOPE_PRIVATE; // 10.0.0.0/8 - case 0x0b: - return IP_SCOPE_PSEUDOPRIVATE; // 11.0.0.0/8 (US DoD) - case 0x15: - return IP_SCOPE_PSEUDOPRIVATE; // 21.0.0.0/8 (US DDN-RVN) - case 0x16: - return IP_SCOPE_PSEUDOPRIVATE; // 22.0.0.0/8 (US DISA) - case 0x19: - return IP_SCOPE_PSEUDOPRIVATE; // 25.0.0.0/8 (UK Ministry of Defense) - case 0x1a: - return IP_SCOPE_PSEUDOPRIVATE; // 26.0.0.0/8 (US DISA) - case 0x1c: - return IP_SCOPE_PSEUDOPRIVATE; // 28.0.0.0/8 (US DSI-North) - case 0x1d: - return IP_SCOPE_PSEUDOPRIVATE; // 29.0.0.0/8 (US DISA) - case 0x1e: - return IP_SCOPE_PSEUDOPRIVATE; // 30.0.0.0/8 (US DISA) - case 0x33: - return IP_SCOPE_PSEUDOPRIVATE; // 51.0.0.0/8 (UK Department of Social Security) - case 0x37: - return IP_SCOPE_PSEUDOPRIVATE; // 55.0.0.0/8 (US DoD) - case 0x38: - return IP_SCOPE_PSEUDOPRIVATE; // 56.0.0.0/8 (US Postal Service) - case 0x64: - if ((ip & 0xffc00000) == 0x64400000) { - return IP_SCOPE_PRIVATE; // 100.64.0.0/10 - } - break; - case 0x7f: - return IP_SCOPE_LOOPBACK; // 127.0.0.0/8 - case 0xa9: - if ((ip & 0xffff0000) == 0xa9fe0000) { - return IP_SCOPE_LINK_LOCAL; // 169.254.0.0/16 - } - break; - case 0xac: - if ((ip & 0xfff00000) == 0xac100000) { - return IP_SCOPE_PRIVATE; // 172.16.0.0/12 - } - break; - case 0xc0: - if ((ip & 0xffff0000) == 0xc0a80000) { - return IP_SCOPE_PRIVATE; // 192.168.0.0/16 - } - if ((ip & 0xffffff00) == 0xc0000200) { - return IP_SCOPE_PRIVATE; // 192.0.2.0/24 - } - break; - case 0xc6: - if ((ip & 0xfffe0000) == 0xc6120000) { - return IP_SCOPE_PRIVATE; // 198.18.0.0/15 - } - if ((ip & 0xffffff00) == 0xc6336400) { - return IP_SCOPE_PRIVATE; // 198.51.100.0/24 - } - break; - case 0xcb: - if ((ip & 0xffffff00) == 0xcb007100) { - return IP_SCOPE_PRIVATE; // 203.0.113.0/24 - } - break; - case 0xff: - return IP_SCOPE_NONE; // 255.0.0.0/8 (broadcast, or unused/unusable) - } - switch(ip >> 28) { - case 0xe: - return IP_SCOPE_MULTICAST; // 224.0.0.0/4 - case 0xf: - return IP_SCOPE_PSEUDOPRIVATE; // 240.0.0.0/4 ("reserved," usually unusable) - } - return IP_SCOPE_GLOBAL; - } break; + case AF_INET6: { + const unsigned char* ip = reinterpret_cast(reinterpret_cast(this)->sin6_addr.s6_addr); + if ((ip[0] & 0xf0) == 0xf0) { + if (ip[0] == 0xff) { + return IP_SCOPE_MULTICAST; // ff00::/8 + } + if ((ip[0] == 0xfe) && ((ip[1] & 0xc0) == 0x80)) { + unsigned int k = 2; + while ((! ip[k]) && (k < 15)) { + ++k; + } + if ((k == 15) && (ip[15] == 0x01)) { + return IP_SCOPE_LOOPBACK; // fe80::1/128 + } + else { + return IP_SCOPE_LINK_LOCAL; // fe80::/10 + } + } + if ((ip[0] & 0xfe) == 0xfc) { + return IP_SCOPE_PRIVATE; // fc00::/7 + } + } - case AF_INET6: { - const unsigned char *ip = reinterpret_cast(reinterpret_cast(this)->sin6_addr.s6_addr); - if ((ip[0] & 0xf0) == 0xf0) { - if (ip[0] == 0xff) { - return IP_SCOPE_MULTICAST; // ff00::/8 - } - if ((ip[0] == 0xfe)&&((ip[1] & 0xc0) == 0x80)) { - unsigned int k = 2; - while ((!ip[k])&&(k < 15)) { - ++k; - } - if ((k == 15)&&(ip[15] == 0x01)) { - return IP_SCOPE_LOOPBACK; // fe80::1/128 - } else { - return IP_SCOPE_LINK_LOCAL; // fe80::/10 - } - } - if ((ip[0] & 0xfe) == 0xfc) { - return IP_SCOPE_PRIVATE; // fc00::/7 - } - } + // :::ffff:127.0.0.1 + // 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, 0x7f, 0, 0, 1 + unsigned int k = 0; + while ((! ip[k]) && (k < 9)) { + ++k; + } + if (k == 9) { + if (ip[10] == 0xff && ip[11] == 0xff && ip[12] == 0x7f) { + return IP_SCOPE_LOOPBACK; + } + } - // :::ffff:127.0.0.1 - // 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, 0x7f, 0, 0, 1 - unsigned int k = 0; - while ((!ip[k])&&(k < 9)) { - ++k; - } - if (k == 9) { - if (ip[10] == 0xff && ip[11] == 0xff && ip[12] == 0x7f) { - return IP_SCOPE_LOOPBACK; - } - } + k = 0; + while ((! ip[k]) && (k < 15)) { + ++k; + } + if (k == 15) { // all 0's except last byte + if (ip[15] == 0x01) { + return IP_SCOPE_LOOPBACK; // ::1/128 + } + if (ip[15] == 0x00) { + return IP_SCOPE_NONE; // ::/128 + } + } + return IP_SCOPE_GLOBAL; + } break; + } - k = 0; - while ((!ip[k])&&(k < 15)) { - ++k; - } - if (k == 15) { // all 0's except last byte - if (ip[15] == 0x01) { - return IP_SCOPE_LOOPBACK; // ::1/128 - } - if (ip[15] == 0x00) { - return IP_SCOPE_NONE; // ::/128 - } - } - return IP_SCOPE_GLOBAL; - } break; - - } - - return IP_SCOPE_NONE; + return IP_SCOPE_NONE; } -void InetAddress::set(const void *ipBytes,unsigned int ipLen,unsigned int port) +void InetAddress::set(const void* ipBytes, unsigned int ipLen, unsigned int port) { - memset(this,0,sizeof(InetAddress)); - if (ipLen == 4) { - uint32_t ipb[1]; - memcpy(ipb,ipBytes,4); - ss_family = AF_INET; - reinterpret_cast(this)->sin_addr.s_addr = ipb[0]; - reinterpret_cast(this)->sin_port = Utils::hton((uint16_t)port); - } else if (ipLen == 16) { - ss_family = AF_INET6; - memcpy(reinterpret_cast(this)->sin6_addr.s6_addr,ipBytes,16); - reinterpret_cast(this)->sin6_port = Utils::hton((uint16_t)port); - } + memset(this, 0, sizeof(InetAddress)); + if (ipLen == 4) { + uint32_t ipb[1]; + memcpy(ipb, ipBytes, 4); + ss_family = AF_INET; + reinterpret_cast(this)->sin_addr.s_addr = ipb[0]; + reinterpret_cast(this)->sin_port = Utils::hton((uint16_t)port); + } + else if (ipLen == 16) { + ss_family = AF_INET6; + memcpy(reinterpret_cast(this)->sin6_addr.s6_addr, ipBytes, 16); + reinterpret_cast(this)->sin6_port = Utils::hton((uint16_t)port); + } } -char *InetAddress::toString(char buf[64]) const +char* InetAddress::toString(char buf[64]) const { - char *p = toIpString(buf); - if (*p) { - while (*p) { - ++p; - } - *(p++) = '/'; - Utils::decimal(port(),p); - } - return buf; + char* p = toIpString(buf); + if (*p) { + while (*p) { + ++p; + } + *(p++) = '/'; + Utils::decimal(port(), p); + } + return buf; } -char *InetAddress::toIpString(char buf[64]) const +char* InetAddress::toIpString(char buf[64]) const { - buf[0] = (char)0; - switch(ss_family) { - case AF_INET: { + buf[0] = (char)0; + switch (ss_family) { + case AF_INET: { #ifdef _WIN32 - inet_ntop(AF_INET, (void*)&reinterpret_cast(this)->sin_addr.s_addr, buf, INET_ADDRSTRLEN); + inet_ntop(AF_INET, (void*)&reinterpret_cast(this)->sin_addr.s_addr, buf, INET_ADDRSTRLEN); #else - inet_ntop(AF_INET, &reinterpret_cast(this)->sin_addr.s_addr, buf, INET_ADDRSTRLEN); + inet_ntop(AF_INET, &reinterpret_cast(this)->sin_addr.s_addr, buf, INET_ADDRSTRLEN); #endif - } break; + } break; - case AF_INET6: { + case AF_INET6: { #ifdef _WIN32 - inet_ntop(AF_INET6, (void*)reinterpret_cast(this)->sin6_addr.s6_addr, buf, INET6_ADDRSTRLEN); + inet_ntop(AF_INET6, (void*)reinterpret_cast(this)->sin6_addr.s6_addr, buf, INET6_ADDRSTRLEN); #else - inet_ntop(AF_INET6, reinterpret_cast(this)->sin6_addr.s6_addr, buf, INET6_ADDRSTRLEN); + inet_ntop(AF_INET6, reinterpret_cast(this)->sin6_addr.s6_addr, buf, INET6_ADDRSTRLEN); #endif - } break; - } - return buf; + } break; + } + return buf; } -bool InetAddress::fromString(const char *ipSlashPort) +bool InetAddress::fromString(const char* ipSlashPort) { - char buf[64]; + char buf[64]; - memset(this,0,sizeof(InetAddress)); + memset(this, 0, sizeof(InetAddress)); - if (!*ipSlashPort) { - return true; - } - if (!Utils::scopy(buf,sizeof(buf),ipSlashPort)) { - return false; - } + if (! *ipSlashPort) { + return true; + } + if (! Utils::scopy(buf, sizeof(buf), ipSlashPort)) { + return false; + } - char *portAt = buf; - while ((*portAt)&&(*portAt != '/')) { - ++portAt; - } - unsigned int port = 0; - if (*portAt) { - *(portAt++) = (char)0; - port = Utils::strToUInt(portAt) & 0xffff; - } + char* portAt = buf; + while ((*portAt) && (*portAt != '/')) { + ++portAt; + } + unsigned int port = 0; + if (*portAt) { + *(portAt++) = (char)0; + port = Utils::strToUInt(portAt) & 0xffff; + } - if (strchr(buf,':')) { - struct sockaddr_in6 *const in6 = reinterpret_cast(this); - inet_pton(AF_INET6, buf, &in6->sin6_addr.s6_addr); - in6->sin6_family = AF_INET6; - in6->sin6_port = Utils::hton((uint16_t)port); - return true; - } else if (strchr(buf,'.')) { - struct sockaddr_in *const in = reinterpret_cast(this); - inet_pton(AF_INET, buf, &in->sin_addr.s_addr); - in->sin_family = AF_INET; - in->sin_port = Utils::hton((uint16_t)port); - return true; - } else { - return false; - } + if (strchr(buf, ':')) { + struct sockaddr_in6* const in6 = reinterpret_cast(this); + inet_pton(AF_INET6, buf, &in6->sin6_addr.s6_addr); + in6->sin6_family = AF_INET6; + in6->sin6_port = Utils::hton((uint16_t)port); + return true; + } + else if (strchr(buf, '.')) { + struct sockaddr_in* const in = reinterpret_cast(this); + inet_pton(AF_INET, buf, &in->sin_addr.s_addr); + in->sin_family = AF_INET; + in->sin_port = Utils::hton((uint16_t)port); + return true; + } + else { + return false; + } } InetAddress InetAddress::netmask() const { - InetAddress r(*this); - switch(r.ss_family) { - case AF_INET: - reinterpret_cast(&r)->sin_addr.s_addr = Utils::hton((uint32_t)(0xffffffff << (32 - netmaskBits()))); - break; - case AF_INET6: { - uint64_t nm[2]; - const unsigned int bits = netmaskBits(); - if(bits) { - nm[0] = Utils::hton((uint64_t)((bits >= 64) ? 0xffffffffffffffffULL : (0xffffffffffffffffULL << (64 - bits)))); - nm[1] = Utils::hton((uint64_t)((bits <= 64) ? 0ULL : (0xffffffffffffffffULL << (128 - bits)))); - } else { - nm[0] = 0; - nm[1] = 0; - } - memcpy(reinterpret_cast(&r)->sin6_addr.s6_addr,nm,16); - } break; - } - return r; + InetAddress r(*this); + switch (r.ss_family) { + case AF_INET: + reinterpret_cast(&r)->sin_addr.s_addr = Utils::hton((uint32_t)(0xffffffff << (32 - netmaskBits()))); + break; + case AF_INET6: { + uint64_t nm[2]; + const unsigned int bits = netmaskBits(); + if (bits) { + nm[0] = Utils::hton((uint64_t)((bits >= 64) ? 0xffffffffffffffffULL : (0xffffffffffffffffULL << (64 - bits)))); + nm[1] = Utils::hton((uint64_t)((bits <= 64) ? 0ULL : (0xffffffffffffffffULL << (128 - bits)))); + } + else { + nm[0] = 0; + nm[1] = 0; + } + memcpy(reinterpret_cast(&r)->sin6_addr.s6_addr, nm, 16); + } break; + } + return r; } InetAddress InetAddress::broadcast() const { - if (ss_family == AF_INET) { - InetAddress r(*this); - reinterpret_cast(&r)->sin_addr.s_addr |= Utils::hton((uint32_t)(0xffffffff >> netmaskBits())); - return r; - } - return InetAddress(); + if (ss_family == AF_INET) { + InetAddress r(*this); + reinterpret_cast(&r)->sin_addr.s_addr |= Utils::hton((uint32_t)(0xffffffff >> netmaskBits())); + return r; + } + return InetAddress(); } InetAddress InetAddress::network() const { - InetAddress r(*this); - switch(r.ss_family) { - case AF_INET: - reinterpret_cast(&r)->sin_addr.s_addr &= Utils::hton((uint32_t)(0xffffffff << (32 - netmaskBits()))); - break; - case AF_INET6: { - uint64_t nm[2]; - const unsigned int bits = netmaskBits(); - memcpy(nm,reinterpret_cast(&r)->sin6_addr.s6_addr,16); - nm[0] &= Utils::hton((uint64_t)((bits >= 64) ? 0xffffffffffffffffULL : (0xffffffffffffffffULL << (64 - bits)))); - nm[1] &= Utils::hton((uint64_t)((bits <= 64) ? 0ULL : (0xffffffffffffffffULL << (128 - bits)))); - memcpy(reinterpret_cast(&r)->sin6_addr.s6_addr,nm,16); - } break; - } - return r; + InetAddress r(*this); + switch (r.ss_family) { + case AF_INET: + reinterpret_cast(&r)->sin_addr.s_addr &= Utils::hton((uint32_t)(0xffffffff << (32 - netmaskBits()))); + break; + case AF_INET6: { + uint64_t nm[2]; + const unsigned int bits = netmaskBits(); + memcpy(nm, reinterpret_cast(&r)->sin6_addr.s6_addr, 16); + nm[0] &= Utils::hton((uint64_t)((bits >= 64) ? 0xffffffffffffffffULL : (0xffffffffffffffffULL << (64 - bits)))); + nm[1] &= Utils::hton((uint64_t)((bits <= 64) ? 0ULL : (0xffffffffffffffffULL << (128 - bits)))); + memcpy(reinterpret_cast(&r)->sin6_addr.s6_addr, nm, 16); + } break; + } + return r; } -bool InetAddress::isEqualPrefix(const InetAddress &addr) const +bool InetAddress::isEqualPrefix(const InetAddress& addr) const { - if (addr.ss_family == ss_family) { - switch(ss_family) { - case AF_INET6: { - const InetAddress mask(netmask()); - InetAddress addr_mask(addr.netmask()); - const uint8_t *n = reinterpret_cast(reinterpret_cast(&addr_mask)->sin6_addr.s6_addr); - const uint8_t *m = reinterpret_cast(reinterpret_cast(&mask)->sin6_addr.s6_addr); - const uint8_t *a = reinterpret_cast(reinterpret_cast(&addr)->sin6_addr.s6_addr); - const uint8_t *b = reinterpret_cast(reinterpret_cast(this)->sin6_addr.s6_addr); - for(unsigned int i=0;i<16;++i) { - if ((a[i] & m[i]) != (b[i] & n[i])) { - return false; - } - } - return true; - } - } - } - return false; + if (addr.ss_family == ss_family) { + switch (ss_family) { + case AF_INET6: { + const InetAddress mask(netmask()); + InetAddress addr_mask(addr.netmask()); + const uint8_t* n = reinterpret_cast(reinterpret_cast(&addr_mask)->sin6_addr.s6_addr); + const uint8_t* m = reinterpret_cast(reinterpret_cast(&mask)->sin6_addr.s6_addr); + const uint8_t* a = reinterpret_cast(reinterpret_cast(&addr)->sin6_addr.s6_addr); + const uint8_t* b = reinterpret_cast(reinterpret_cast(this)->sin6_addr.s6_addr); + for (unsigned int i = 0; i < 16; ++i) { + if ((a[i] & m[i]) != (b[i] & n[i])) { + return false; + } + } + return true; + } + } + } + return false; } -bool InetAddress::containsAddress(const InetAddress &addr) const +bool InetAddress::containsAddress(const InetAddress& addr) const { - if (addr.ss_family == ss_family) { - switch(ss_family) { - case AF_INET: { - const unsigned int bits = netmaskBits(); - if (bits == 0) { - return true; - } - return ( (Utils::ntoh((uint32_t)reinterpret_cast(&addr)->sin_addr.s_addr) >> (32 - bits)) == (Utils::ntoh((uint32_t)reinterpret_cast(this)->sin_addr.s_addr) >> (32 - bits)) ); - } - case AF_INET6: { - const InetAddress mask(netmask()); - const uint8_t *m = reinterpret_cast(reinterpret_cast(&mask)->sin6_addr.s6_addr); - const uint8_t *a = reinterpret_cast(reinterpret_cast(&addr)->sin6_addr.s6_addr); - const uint8_t *b = reinterpret_cast(reinterpret_cast(this)->sin6_addr.s6_addr); - for(unsigned int i=0;i<16;++i) { - if ((a[i] & m[i]) != b[i]) { - return false; - } - } - return true; - } - } - } - return false; + if (addr.ss_family == ss_family) { + switch (ss_family) { + case AF_INET: { + const unsigned int bits = netmaskBits(); + if (bits == 0) { + return true; + } + return ( + (Utils::ntoh((uint32_t)reinterpret_cast(&addr)->sin_addr.s_addr) >> (32 - bits)) == (Utils::ntoh((uint32_t)reinterpret_cast(this)->sin_addr.s_addr) >> (32 - bits))); + } + case AF_INET6: { + const InetAddress mask(netmask()); + const uint8_t* m = reinterpret_cast(reinterpret_cast(&mask)->sin6_addr.s6_addr); + const uint8_t* a = reinterpret_cast(reinterpret_cast(&addr)->sin6_addr.s6_addr); + const uint8_t* b = reinterpret_cast(reinterpret_cast(this)->sin6_addr.s6_addr); + for (unsigned int i = 0; i < 16; ++i) { + if ((a[i] & m[i]) != b[i]) { + return false; + } + } + return true; + } + } + } + return false; } bool InetAddress::isNetwork() const { - switch(ss_family) { - case AF_INET: { - unsigned int bits = netmaskBits(); - if (bits <= 0) { - return false; - } - if (bits >= 32) { - return false; - } - uint32_t ip = Utils::ntoh((uint32_t)reinterpret_cast(this)->sin_addr.s_addr); - return ((ip & (0xffffffff >> bits)) == 0); - } - case AF_INET6: { - unsigned int bits = netmaskBits(); - if (bits <= 0) { - return false; - } - if (bits >= 128) { - return false; - } - const unsigned char *ip = reinterpret_cast(reinterpret_cast(this)->sin6_addr.s6_addr); - unsigned int p = bits / 8; - if ((ip[p++] & (0xff >> (bits % 8))) != 0) { - return false; - } - while (p < 16) { - if (ip[p++]) { - return false; - } - } - return true; - } - } - return false; + switch (ss_family) { + case AF_INET: { + unsigned int bits = netmaskBits(); + if (bits <= 0) { + return false; + } + if (bits >= 32) { + return false; + } + uint32_t ip = Utils::ntoh((uint32_t)reinterpret_cast(this)->sin_addr.s_addr); + return ((ip & (0xffffffff >> bits)) == 0); + } + case AF_INET6: { + unsigned int bits = netmaskBits(); + if (bits <= 0) { + return false; + } + if (bits >= 128) { + return false; + } + const unsigned char* ip = reinterpret_cast(reinterpret_cast(this)->sin6_addr.s6_addr); + unsigned int p = bits / 8; + if ((ip[p++] & (0xff >> (bits % 8))) != 0) { + return false; + } + while (p < 16) { + if (ip[p++]) { + return false; + } + } + return true; + } + } + return false; } -bool InetAddress::operator==(const InetAddress &a) const +bool InetAddress::operator==(const InetAddress& a) const { - if (ss_family == a.ss_family) { - switch(ss_family) { - case AF_INET: - return ( - (reinterpret_cast(this)->sin_port == reinterpret_cast(&a)->sin_port)&& - (reinterpret_cast(this)->sin_addr.s_addr == reinterpret_cast(&a)->sin_addr.s_addr)); - break; - case AF_INET6: - return ( - (reinterpret_cast(this)->sin6_port == reinterpret_cast(&a)->sin6_port)&& - (reinterpret_cast(this)->sin6_flowinfo == reinterpret_cast(&a)->sin6_flowinfo)&& - (memcmp(reinterpret_cast(this)->sin6_addr.s6_addr,reinterpret_cast(&a)->sin6_addr.s6_addr,16) == 0)&& - (reinterpret_cast(this)->sin6_scope_id == reinterpret_cast(&a)->sin6_scope_id)); - break; - default: - return (memcmp(this,&a,sizeof(InetAddress)) == 0); - } - } - return false; + if (ss_family == a.ss_family) { + switch (ss_family) { + case AF_INET: + return ( + (reinterpret_cast(this)->sin_port == reinterpret_cast(&a)->sin_port) + && (reinterpret_cast(this)->sin_addr.s_addr == reinterpret_cast(&a)->sin_addr.s_addr)); + break; + case AF_INET6: + return ( + (reinterpret_cast(this)->sin6_port == reinterpret_cast(&a)->sin6_port) + && (reinterpret_cast(this)->sin6_flowinfo == reinterpret_cast(&a)->sin6_flowinfo) + && (memcmp(reinterpret_cast(this)->sin6_addr.s6_addr, reinterpret_cast(&a)->sin6_addr.s6_addr, 16) == 0) + && (reinterpret_cast(this)->sin6_scope_id == reinterpret_cast(&a)->sin6_scope_id)); + break; + default: + return (memcmp(this, &a, sizeof(InetAddress)) == 0); + } + } + return false; } -bool InetAddress::operator<(const InetAddress &a) const +bool InetAddress::operator<(const InetAddress& a) const { - if (ss_family < a.ss_family) { - return true; - } else if (ss_family == a.ss_family) { - switch(ss_family) { - case AF_INET: - if (reinterpret_cast(this)->sin_port < reinterpret_cast(&a)->sin_port) { - return true; - } else if (reinterpret_cast(this)->sin_port == reinterpret_cast(&a)->sin_port) { - if (reinterpret_cast(this)->sin_addr.s_addr < reinterpret_cast(&a)->sin_addr.s_addr) { - return true; - } - } - break; - case AF_INET6: - if (reinterpret_cast(this)->sin6_port < reinterpret_cast(&a)->sin6_port) { - return true; - } else if (reinterpret_cast(this)->sin6_port == reinterpret_cast(&a)->sin6_port) { - if (reinterpret_cast(this)->sin6_flowinfo < reinterpret_cast(&a)->sin6_flowinfo) { - return true; - } else if (reinterpret_cast(this)->sin6_flowinfo == reinterpret_cast(&a)->sin6_flowinfo) { - if (memcmp(reinterpret_cast(this)->sin6_addr.s6_addr,reinterpret_cast(&a)->sin6_addr.s6_addr,16) < 0) { - return true; - } else if (memcmp(reinterpret_cast(this)->sin6_addr.s6_addr,reinterpret_cast(&a)->sin6_addr.s6_addr,16) == 0) { - if (reinterpret_cast(this)->sin6_scope_id < reinterpret_cast(&a)->sin6_scope_id) { - return true; - } - } - } - } - break; - default: - return (memcmp(this,&a,sizeof(InetAddress)) < 0); - } - } - return false; + if (ss_family < a.ss_family) { + return true; + } + else if (ss_family == a.ss_family) { + switch (ss_family) { + case AF_INET: + if (reinterpret_cast(this)->sin_port < reinterpret_cast(&a)->sin_port) { + return true; + } + else if (reinterpret_cast(this)->sin_port == reinterpret_cast(&a)->sin_port) { + if (reinterpret_cast(this)->sin_addr.s_addr < reinterpret_cast(&a)->sin_addr.s_addr) { + return true; + } + } + break; + case AF_INET6: + if (reinterpret_cast(this)->sin6_port < reinterpret_cast(&a)->sin6_port) { + return true; + } + else if (reinterpret_cast(this)->sin6_port == reinterpret_cast(&a)->sin6_port) { + if (reinterpret_cast(this)->sin6_flowinfo < reinterpret_cast(&a)->sin6_flowinfo) { + return true; + } + else if (reinterpret_cast(this)->sin6_flowinfo == reinterpret_cast(&a)->sin6_flowinfo) { + if (memcmp(reinterpret_cast(this)->sin6_addr.s6_addr, reinterpret_cast(&a)->sin6_addr.s6_addr, 16) < 0) { + return true; + } + else if (memcmp(reinterpret_cast(this)->sin6_addr.s6_addr, reinterpret_cast(&a)->sin6_addr.s6_addr, 16) == 0) { + if (reinterpret_cast(this)->sin6_scope_id < reinterpret_cast(&a)->sin6_scope_id) { + return true; + } + } + } + } + break; + default: + return (memcmp(this, &a, sizeof(InetAddress)) < 0); + } + } + return false; } -InetAddress InetAddress::makeIpv6LinkLocal(const MAC &mac) +InetAddress InetAddress::makeIpv6LinkLocal(const MAC& mac) { - struct sockaddr_in6 sin6; - sin6.sin6_family = AF_INET6; - sin6.sin6_addr.s6_addr[0] = 0xfe; - sin6.sin6_addr.s6_addr[1] = 0x80; - sin6.sin6_addr.s6_addr[2] = 0x00; - sin6.sin6_addr.s6_addr[3] = 0x00; - sin6.sin6_addr.s6_addr[4] = 0x00; - sin6.sin6_addr.s6_addr[5] = 0x00; - sin6.sin6_addr.s6_addr[6] = 0x00; - sin6.sin6_addr.s6_addr[7] = 0x00; - sin6.sin6_addr.s6_addr[8] = mac[0] & 0xfd; - sin6.sin6_addr.s6_addr[9] = mac[1]; - sin6.sin6_addr.s6_addr[10] = mac[2]; - sin6.sin6_addr.s6_addr[11] = 0xff; - sin6.sin6_addr.s6_addr[12] = 0xfe; - sin6.sin6_addr.s6_addr[13] = mac[3]; - sin6.sin6_addr.s6_addr[14] = mac[4]; - sin6.sin6_addr.s6_addr[15] = mac[5]; - sin6.sin6_port = Utils::hton((uint16_t)64); - return InetAddress(sin6); + struct sockaddr_in6 sin6; + sin6.sin6_family = AF_INET6; + sin6.sin6_addr.s6_addr[0] = 0xfe; + sin6.sin6_addr.s6_addr[1] = 0x80; + sin6.sin6_addr.s6_addr[2] = 0x00; + sin6.sin6_addr.s6_addr[3] = 0x00; + sin6.sin6_addr.s6_addr[4] = 0x00; + sin6.sin6_addr.s6_addr[5] = 0x00; + sin6.sin6_addr.s6_addr[6] = 0x00; + sin6.sin6_addr.s6_addr[7] = 0x00; + sin6.sin6_addr.s6_addr[8] = mac[0] & 0xfd; + sin6.sin6_addr.s6_addr[9] = mac[1]; + sin6.sin6_addr.s6_addr[10] = mac[2]; + sin6.sin6_addr.s6_addr[11] = 0xff; + sin6.sin6_addr.s6_addr[12] = 0xfe; + sin6.sin6_addr.s6_addr[13] = mac[3]; + sin6.sin6_addr.s6_addr[14] = mac[4]; + sin6.sin6_addr.s6_addr[15] = mac[5]; + sin6.sin6_port = Utils::hton((uint16_t)64); + return InetAddress(sin6); } -InetAddress InetAddress::makeIpv6rfc4193(uint64_t nwid,uint64_t zeroTierAddress) +InetAddress InetAddress::makeIpv6rfc4193(uint64_t nwid, uint64_t zeroTierAddress) { - InetAddress r; - struct sockaddr_in6 *const sin6 = reinterpret_cast(&r); - sin6->sin6_family = AF_INET6; - sin6->sin6_addr.s6_addr[0] = 0xfd; - sin6->sin6_addr.s6_addr[1] = (uint8_t)(nwid >> 56); - sin6->sin6_addr.s6_addr[2] = (uint8_t)(nwid >> 48); - sin6->sin6_addr.s6_addr[3] = (uint8_t)(nwid >> 40); - sin6->sin6_addr.s6_addr[4] = (uint8_t)(nwid >> 32); - sin6->sin6_addr.s6_addr[5] = (uint8_t)(nwid >> 24); - sin6->sin6_addr.s6_addr[6] = (uint8_t)(nwid >> 16); - sin6->sin6_addr.s6_addr[7] = (uint8_t)(nwid >> 8); - sin6->sin6_addr.s6_addr[8] = (uint8_t)nwid; - sin6->sin6_addr.s6_addr[9] = 0x99; - sin6->sin6_addr.s6_addr[10] = 0x93; - sin6->sin6_addr.s6_addr[11] = (uint8_t)(zeroTierAddress >> 32); - sin6->sin6_addr.s6_addr[12] = (uint8_t)(zeroTierAddress >> 24); - sin6->sin6_addr.s6_addr[13] = (uint8_t)(zeroTierAddress >> 16); - sin6->sin6_addr.s6_addr[14] = (uint8_t)(zeroTierAddress >> 8); - sin6->sin6_addr.s6_addr[15] = (uint8_t)zeroTierAddress; - sin6->sin6_port = Utils::hton((uint16_t)88); // /88 includes 0xfd + network ID, discriminating by device ID below that - return r; + InetAddress r; + struct sockaddr_in6* const sin6 = reinterpret_cast(&r); + sin6->sin6_family = AF_INET6; + sin6->sin6_addr.s6_addr[0] = 0xfd; + sin6->sin6_addr.s6_addr[1] = (uint8_t)(nwid >> 56); + sin6->sin6_addr.s6_addr[2] = (uint8_t)(nwid >> 48); + sin6->sin6_addr.s6_addr[3] = (uint8_t)(nwid >> 40); + sin6->sin6_addr.s6_addr[4] = (uint8_t)(nwid >> 32); + sin6->sin6_addr.s6_addr[5] = (uint8_t)(nwid >> 24); + sin6->sin6_addr.s6_addr[6] = (uint8_t)(nwid >> 16); + sin6->sin6_addr.s6_addr[7] = (uint8_t)(nwid >> 8); + sin6->sin6_addr.s6_addr[8] = (uint8_t)nwid; + sin6->sin6_addr.s6_addr[9] = 0x99; + sin6->sin6_addr.s6_addr[10] = 0x93; + sin6->sin6_addr.s6_addr[11] = (uint8_t)(zeroTierAddress >> 32); + sin6->sin6_addr.s6_addr[12] = (uint8_t)(zeroTierAddress >> 24); + sin6->sin6_addr.s6_addr[13] = (uint8_t)(zeroTierAddress >> 16); + sin6->sin6_addr.s6_addr[14] = (uint8_t)(zeroTierAddress >> 8); + sin6->sin6_addr.s6_addr[15] = (uint8_t)zeroTierAddress; + sin6->sin6_port = Utils::hton((uint16_t)88); // /88 includes 0xfd + network ID, discriminating by device ID below that + return r; } -InetAddress InetAddress::makeIpv66plane(uint64_t nwid,uint64_t zeroTierAddress) +InetAddress InetAddress::makeIpv66plane(uint64_t nwid, uint64_t zeroTierAddress) { - nwid ^= (nwid >> 32); - InetAddress r; - struct sockaddr_in6 *const sin6 = reinterpret_cast(&r); - sin6->sin6_family = AF_INET6; - sin6->sin6_addr.s6_addr[0] = 0xfc; - sin6->sin6_addr.s6_addr[1] = (uint8_t)(nwid >> 24); - sin6->sin6_addr.s6_addr[2] = (uint8_t)(nwid >> 16); - sin6->sin6_addr.s6_addr[3] = (uint8_t)(nwid >> 8); - sin6->sin6_addr.s6_addr[4] = (uint8_t)nwid; - sin6->sin6_addr.s6_addr[5] = (uint8_t)(zeroTierAddress >> 32); - sin6->sin6_addr.s6_addr[6] = (uint8_t)(zeroTierAddress >> 24); - sin6->sin6_addr.s6_addr[7] = (uint8_t)(zeroTierAddress >> 16); - sin6->sin6_addr.s6_addr[8] = (uint8_t)(zeroTierAddress >> 8); - sin6->sin6_addr.s6_addr[9] = (uint8_t)zeroTierAddress; - sin6->sin6_addr.s6_addr[15] = 0x01; - sin6->sin6_port = Utils::hton((uint16_t)40); - return r; + nwid ^= (nwid >> 32); + InetAddress r; + struct sockaddr_in6* const sin6 = reinterpret_cast(&r); + sin6->sin6_family = AF_INET6; + sin6->sin6_addr.s6_addr[0] = 0xfc; + sin6->sin6_addr.s6_addr[1] = (uint8_t)(nwid >> 24); + sin6->sin6_addr.s6_addr[2] = (uint8_t)(nwid >> 16); + sin6->sin6_addr.s6_addr[3] = (uint8_t)(nwid >> 8); + sin6->sin6_addr.s6_addr[4] = (uint8_t)nwid; + sin6->sin6_addr.s6_addr[5] = (uint8_t)(zeroTierAddress >> 32); + sin6->sin6_addr.s6_addr[6] = (uint8_t)(zeroTierAddress >> 24); + sin6->sin6_addr.s6_addr[7] = (uint8_t)(zeroTierAddress >> 16); + sin6->sin6_addr.s6_addr[8] = (uint8_t)(zeroTierAddress >> 8); + sin6->sin6_addr.s6_addr[9] = (uint8_t)zeroTierAddress; + sin6->sin6_addr.s6_addr[15] = 0x01; + sin6->sin6_port = Utils::hton((uint16_t)40); + return r; } -} // namespace ZeroTier +} // namespace ZeroTier diff --git a/node/InetAddress.hpp b/node/InetAddress.hpp index 7e2a15db..58732ddc 100644 --- a/node/InetAddress.hpp +++ b/node/InetAddress.hpp @@ -14,15 +14,15 @@ #ifndef ZT_INETADDRESS_HPP #define ZT_INETADDRESS_HPP +#include "../include/ZeroTierOne.h" +#include "Buffer.hpp" +#include "Constants.hpp" +#include "MAC.hpp" +#include "Utils.hpp" + +#include #include #include -#include - -#include "Constants.hpp" -#include "../include/ZeroTierOne.h" -#include "Utils.hpp" -#include "MAC.hpp" -#include "Buffer.hpp" namespace ZeroTier { @@ -39,643 +39,716 @@ namespace ZeroTier { * sockaddr_storage and used interchangeably. DO NOT change this by e.g. * adding non-static fields, since much code depends on this identity. */ -struct InetAddress : public sockaddr_storage -{ - /** - * Loopback IPv4 address (no port) - */ - static const InetAddress LO4; +struct InetAddress : public sockaddr_storage { + /** + * Loopback IPv4 address (no port) + */ + static const InetAddress LO4; - /** - * Loopback IPV6 address (no port) - */ - static const InetAddress LO6; + /** + * Loopback IPV6 address (no port) + */ + static const InetAddress LO6; - /** - * IP address scope - * - * Note that these values are in ascending order of path preference and - * MUST remain that way or Path must be changed to reflect. Also be sure - * to change ZT_INETADDRESS_MAX_SCOPE if the max changes. - */ - enum IpScope - { - IP_SCOPE_NONE = 0, // NULL or not an IP address - IP_SCOPE_MULTICAST = 1, // 224.0.0.0 and other V4/V6 multicast IPs - IP_SCOPE_LOOPBACK = 2, // 127.0.0.1, ::1, etc. - IP_SCOPE_PSEUDOPRIVATE = 3, // 28.x.x.x, etc. -- unofficially unrouted IPv4 blocks often "bogarted" - IP_SCOPE_GLOBAL = 4, // globally routable IP address (all others) - IP_SCOPE_LINK_LOCAL = 5, // 169.254.x.x, IPv6 LL - IP_SCOPE_SHARED = 6, // currently unused, formerly used for carrier-grade NAT ranges - IP_SCOPE_PRIVATE = 7 // 10.x.x.x, 192.168.x.x, etc. - }; + /** + * IP address scope + * + * Note that these values are in ascending order of path preference and + * MUST remain that way or Path must be changed to reflect. Also be sure + * to change ZT_INETADDRESS_MAX_SCOPE if the max changes. + */ + enum IpScope { + IP_SCOPE_NONE = 0, // NULL or not an IP address + IP_SCOPE_MULTICAST = 1, // 224.0.0.0 and other V4/V6 multicast IPs + IP_SCOPE_LOOPBACK = 2, // 127.0.0.1, ::1, etc. + IP_SCOPE_PSEUDOPRIVATE = 3, // 28.x.x.x, etc. -- unofficially unrouted IPv4 blocks often "bogarted" + IP_SCOPE_GLOBAL = 4, // globally routable IP address (all others) + IP_SCOPE_LINK_LOCAL = 5, // 169.254.x.x, IPv6 LL + IP_SCOPE_SHARED = 6, // currently unused, formerly used for carrier-grade NAT ranges + IP_SCOPE_PRIVATE = 7 // 10.x.x.x, 192.168.x.x, etc. + }; - // Can be used with the unordered maps and sets in c++11. We don't use C++11 in the core - // but this is safe to put here. - struct Hasher - { - inline std::size_t operator()(const InetAddress &a) const { return (std::size_t)a.hashCode(); } - }; + // Can be used with the unordered maps and sets in c++11. We don't use C++11 in the core + // but this is safe to put here. + struct Hasher { + inline std::size_t operator()(const InetAddress& a) const + { + return (std::size_t)a.hashCode(); + } + }; - InetAddress() { memset(this,0,sizeof(InetAddress)); } - InetAddress(const InetAddress &a) { memcpy(this,&a,sizeof(InetAddress)); } - InetAddress(const InetAddress *a) { memcpy(this,a,sizeof(InetAddress)); } - InetAddress(const struct sockaddr_storage &ss) { *this = ss; } - InetAddress(const struct sockaddr_storage *ss) { *this = ss; } - InetAddress(const struct sockaddr &sa) { *this = sa; } - InetAddress(const struct sockaddr *sa) { *this = sa; } - InetAddress(const struct sockaddr_in &sa) { *this = sa; } - InetAddress(const struct sockaddr_in *sa) { *this = sa; } - InetAddress(const struct sockaddr_in6 &sa) { *this = sa; } - InetAddress(const struct sockaddr_in6 *sa) { *this = sa; } - InetAddress(const void *ipBytes,unsigned int ipLen,unsigned int port) { this->set(ipBytes,ipLen,port); } - InetAddress(const uint32_t ipv4,unsigned int port) { this->set(&ipv4,4,port); } - InetAddress(const char *ipSlashPort) { this->fromString(ipSlashPort); } + InetAddress() + { + memset(this, 0, sizeof(InetAddress)); + } + InetAddress(const InetAddress& a) + { + memcpy(this, &a, sizeof(InetAddress)); + } + InetAddress(const InetAddress* a) + { + memcpy(this, a, sizeof(InetAddress)); + } + InetAddress(const struct sockaddr_storage& ss) + { + *this = ss; + } + InetAddress(const struct sockaddr_storage* ss) + { + *this = ss; + } + InetAddress(const struct sockaddr& sa) + { + *this = sa; + } + InetAddress(const struct sockaddr* sa) + { + *this = sa; + } + InetAddress(const struct sockaddr_in& sa) + { + *this = sa; + } + InetAddress(const struct sockaddr_in* sa) + { + *this = sa; + } + InetAddress(const struct sockaddr_in6& sa) + { + *this = sa; + } + InetAddress(const struct sockaddr_in6* sa) + { + *this = sa; + } + InetAddress(const void* ipBytes, unsigned int ipLen, unsigned int port) + { + this->set(ipBytes, ipLen, port); + } + InetAddress(const uint32_t ipv4, unsigned int port) + { + this->set(&ipv4, 4, port); + } + InetAddress(const char* ipSlashPort) + { + this->fromString(ipSlashPort); + } - inline InetAddress &operator=(const InetAddress &a) - { - if (&a != this) { - memcpy(this,&a,sizeof(InetAddress)); - } - return *this; - } + inline InetAddress& operator=(const InetAddress& a) + { + if (&a != this) { + memcpy(this, &a, sizeof(InetAddress)); + } + return *this; + } - inline InetAddress &operator=(const InetAddress *a) - { - if (a != this) { - memcpy(this,a,sizeof(InetAddress)); - } - return *this; - } + inline InetAddress& operator=(const InetAddress* a) + { + if (a != this) { + memcpy(this, a, sizeof(InetAddress)); + } + return *this; + } - inline InetAddress &operator=(const struct sockaddr_storage &ss) - { - if (reinterpret_cast(&ss) != this) { - memcpy(this,&ss,sizeof(InetAddress)); - } - return *this; - } + inline InetAddress& operator=(const struct sockaddr_storage& ss) + { + if (reinterpret_cast(&ss) != this) { + memcpy(this, &ss, sizeof(InetAddress)); + } + return *this; + } - inline InetAddress &operator=(const struct sockaddr_storage *ss) - { - if (reinterpret_cast(ss) != this) { - memcpy(this,ss,sizeof(InetAddress)); - } - return *this; - } + inline InetAddress& operator=(const struct sockaddr_storage* ss) + { + if (reinterpret_cast(ss) != this) { + memcpy(this, ss, sizeof(InetAddress)); + } + return *this; + } - inline InetAddress &operator=(const struct sockaddr_in &sa) - { - if (reinterpret_cast(&sa) != this) { - memset(this,0,sizeof(InetAddress)); - memcpy(this,&sa,sizeof(struct sockaddr_in)); - } - return *this; - } + inline InetAddress& operator=(const struct sockaddr_in& sa) + { + if (reinterpret_cast(&sa) != this) { + memset(this, 0, sizeof(InetAddress)); + memcpy(this, &sa, sizeof(struct sockaddr_in)); + } + return *this; + } - inline InetAddress &operator=(const struct sockaddr_in *sa) - { - if (reinterpret_cast(sa) != this) { - memset(this,0,sizeof(InetAddress)); - memcpy(this,sa,sizeof(struct sockaddr_in)); - } - return *this; - } + inline InetAddress& operator=(const struct sockaddr_in* sa) + { + if (reinterpret_cast(sa) != this) { + memset(this, 0, sizeof(InetAddress)); + memcpy(this, sa, sizeof(struct sockaddr_in)); + } + return *this; + } - inline InetAddress &operator=(const struct sockaddr_in6 &sa) - { - if (reinterpret_cast(&sa) != this) { - memset(this,0,sizeof(InetAddress)); - memcpy(this,&sa,sizeof(struct sockaddr_in6)); - } - return *this; - } + inline InetAddress& operator=(const struct sockaddr_in6& sa) + { + if (reinterpret_cast(&sa) != this) { + memset(this, 0, sizeof(InetAddress)); + memcpy(this, &sa, sizeof(struct sockaddr_in6)); + } + return *this; + } - inline InetAddress &operator=(const struct sockaddr_in6 *sa) - { - if (reinterpret_cast(sa) != this) { - memset(this,0,sizeof(InetAddress)); - memcpy(this,sa,sizeof(struct sockaddr_in6)); - } - return *this; - } + inline InetAddress& operator=(const struct sockaddr_in6* sa) + { + if (reinterpret_cast(sa) != this) { + memset(this, 0, sizeof(InetAddress)); + memcpy(this, sa, sizeof(struct sockaddr_in6)); + } + return *this; + } - inline InetAddress &operator=(const struct sockaddr &sa) - { - if (reinterpret_cast(&sa) != this) { - memset(this,0,sizeof(InetAddress)); - switch(sa.sa_family) { - case AF_INET: - memcpy(this,&sa,sizeof(struct sockaddr_in)); - break; - case AF_INET6: - memcpy(this,&sa,sizeof(struct sockaddr_in6)); - break; - } - } - return *this; - } + inline InetAddress& operator=(const struct sockaddr& sa) + { + if (reinterpret_cast(&sa) != this) { + memset(this, 0, sizeof(InetAddress)); + switch (sa.sa_family) { + case AF_INET: + memcpy(this, &sa, sizeof(struct sockaddr_in)); + break; + case AF_INET6: + memcpy(this, &sa, sizeof(struct sockaddr_in6)); + break; + } + } + return *this; + } - inline InetAddress &operator=(const struct sockaddr *sa) - { - if (reinterpret_cast(sa) != this) { - memset(this,0,sizeof(InetAddress)); - switch(sa->sa_family) { - case AF_INET: - memcpy(this,sa,sizeof(struct sockaddr_in)); - break; - case AF_INET6: - memcpy(this,sa,sizeof(struct sockaddr_in6)); - break; - } - } - return *this; - } + inline InetAddress& operator=(const struct sockaddr* sa) + { + if (reinterpret_cast(sa) != this) { + memset(this, 0, sizeof(InetAddress)); + switch (sa->sa_family) { + case AF_INET: + memcpy(this, sa, sizeof(struct sockaddr_in)); + break; + case AF_INET6: + memcpy(this, sa, sizeof(struct sockaddr_in6)); + break; + } + } + return *this; + } - /** - * @return IP scope classification (e.g. loopback, link-local, private, global) - */ - IpScope ipScope() const; + /** + * @return IP scope classification (e.g. loopback, link-local, private, global) + */ + IpScope ipScope() const; - /** - * Set from a raw IP and port number - * - * @param ipBytes Bytes of IP address in network byte order - * @param ipLen Length of IP address: 4 or 16 - * @param port Port number or 0 for none - */ - void set(const void *ipBytes,unsigned int ipLen,unsigned int port); + /** + * Set from a raw IP and port number + * + * @param ipBytes Bytes of IP address in network byte order + * @param ipLen Length of IP address: 4 or 16 + * @param port Port number or 0 for none + */ + void set(const void* ipBytes, unsigned int ipLen, unsigned int port); - /** - * Set the port component - * - * @param port Port, 0 to 65535 - */ - inline void setPort(unsigned int port) - { - switch(ss_family) { - case AF_INET: - reinterpret_cast(this)->sin_port = Utils::hton((uint16_t)port); - break; - case AF_INET6: - reinterpret_cast(this)->sin6_port = Utils::hton((uint16_t)port); - break; - } - } + /** + * Set the port component + * + * @param port Port, 0 to 65535 + */ + inline void setPort(unsigned int port) + { + switch (ss_family) { + case AF_INET: + reinterpret_cast(this)->sin_port = Utils::hton((uint16_t)port); + break; + case AF_INET6: + reinterpret_cast(this)->sin6_port = Utils::hton((uint16_t)port); + break; + } + } - /** - * @return True if this network/netmask route describes a default route (e.g. 0.0.0.0/0) - */ - inline bool isDefaultRoute() const - { - switch(ss_family) { - case AF_INET: - return ( (reinterpret_cast(this)->sin_addr.s_addr == 0) && (reinterpret_cast(this)->sin_port == 0) ); - case AF_INET6: - const uint8_t *ipb = reinterpret_cast(reinterpret_cast(this)->sin6_addr.s6_addr); - for(int i=0;i<16;++i) { - if (ipb[i]) { - return false; - } - } - return (reinterpret_cast(this)->sin6_port == 0); - } - return false; - } + /** + * @return True if this network/netmask route describes a default route (e.g. 0.0.0.0/0) + */ + inline bool isDefaultRoute() const + { + switch (ss_family) { + case AF_INET: + return ((reinterpret_cast(this)->sin_addr.s_addr == 0) && (reinterpret_cast(this)->sin_port == 0)); + case AF_INET6: + const uint8_t* ipb = reinterpret_cast(reinterpret_cast(this)->sin6_addr.s6_addr); + for (int i = 0; i < 16; ++i) { + if (ipb[i]) { + return false; + } + } + return (reinterpret_cast(this)->sin6_port == 0); + } + return false; + } - /** - * @return ASCII IP/port format representation - */ - char *toString(char buf[64]) const; + /** + * @return ASCII IP/port format representation + */ + char* toString(char buf[64]) const; - /** - * @return IP portion only, in ASCII string format - */ - char *toIpString(char buf[64]) const; + /** + * @return IP portion only, in ASCII string format + */ + char* toIpString(char buf[64]) const; - /** - * @param ipSlashPort IP/port (port is optional, will be 0 if not included) - * @return True if address appeared to be valid - */ - bool fromString(const char *ipSlashPort); + /** + * @param ipSlashPort IP/port (port is optional, will be 0 if not included) + * @return True if address appeared to be valid + */ + bool fromString(const char* ipSlashPort); - /** - * @return Port or 0 if no port component defined - */ - inline unsigned int port() const - { - switch(ss_family) { - case AF_INET: - return Utils::ntoh((uint16_t)(reinterpret_cast(this)->sin_port)); - case AF_INET6: - return Utils::ntoh((uint16_t)(reinterpret_cast(this)->sin6_port)); - default: - return 0; - } - } + /** + * @return Port or 0 if no port component defined + */ + inline unsigned int port() const + { + switch (ss_family) { + case AF_INET: + return Utils::ntoh((uint16_t)(reinterpret_cast(this)->sin_port)); + case AF_INET6: + return Utils::ntoh((uint16_t)(reinterpret_cast(this)->sin6_port)); + default: + return 0; + } + } - /** - * Alias for port() - * - * This just aliases port() to make code more readable when netmask bits - * are stuffed there, as they are in Network, EthernetTap, and a few other - * spots. - * - * @return Netmask bits - */ - inline unsigned int netmaskBits() const { return port(); } + /** + * Alias for port() + * + * This just aliases port() to make code more readable when netmask bits + * are stuffed there, as they are in Network, EthernetTap, and a few other + * spots. + * + * @return Netmask bits + */ + inline unsigned int netmaskBits() const + { + return port(); + } - /** - * @return True if netmask bits is valid for the address type - */ - inline bool netmaskBitsValid() const - { - const unsigned int n = port(); - switch(ss_family) { - case AF_INET: - return (n <= 32); - case AF_INET6: - return (n <= 128); - } - return false; - } + /** + * @return True if netmask bits is valid for the address type + */ + inline bool netmaskBitsValid() const + { + const unsigned int n = port(); + switch (ss_family) { + case AF_INET: + return (n <= 32); + case AF_INET6: + return (n <= 128); + } + return false; + } - /** - * Alias for port() - * - * This just aliases port() because for gateways we use this field to - * store the gateway metric. - * - * @return Gateway metric - */ - inline unsigned int metric() const { return port(); } + /** + * Alias for port() + * + * This just aliases port() because for gateways we use this field to + * store the gateway metric. + * + * @return Gateway metric + */ + inline unsigned int metric() const + { + return port(); + } - /** - * Construct a full netmask as an InetAddress - * - * @return Netmask such as 255.255.255.0 if this address is /24 (port field will be unchanged) - */ - InetAddress netmask() const; + /** + * Construct a full netmask as an InetAddress + * + * @return Netmask such as 255.255.255.0 if this address is /24 (port field will be unchanged) + */ + InetAddress netmask() const; - /** - * Constructs a broadcast address from a network/netmask address - * - * This is only valid for IPv4 and will return a NULL InetAddress for other - * address families. - * - * @return Broadcast address (only IP portion is meaningful) - */ - InetAddress broadcast() const; + /** + * Constructs a broadcast address from a network/netmask address + * + * This is only valid for IPv4 and will return a NULL InetAddress for other + * address families. + * + * @return Broadcast address (only IP portion is meaningful) + */ + InetAddress broadcast() const; - /** - * Return the network -- a.k.a. the IP ANDed with the netmask - * - * @return Network e.g. 10.0.1.0/24 from 10.0.1.200/24 - */ - InetAddress network() const; + /** + * Return the network -- a.k.a. the IP ANDed with the netmask + * + * @return Network e.g. 10.0.1.0/24 from 10.0.1.200/24 + */ + InetAddress network() const; - /** - * Test whether this IPv6 prefix matches the prefix of a given IPv6 address - * - * @param addr Address to check - * @return True if this IPv6 prefix matches the prefix of a given IPv6 address - */ - bool isEqualPrefix(const InetAddress &addr) const; + /** + * Test whether this IPv6 prefix matches the prefix of a given IPv6 address + * + * @param addr Address to check + * @return True if this IPv6 prefix matches the prefix of a given IPv6 address + */ + bool isEqualPrefix(const InetAddress& addr) const; - /** - * Test whether this IP/netmask contains this address - * - * @param addr Address to check - * @return True if this IP/netmask (route) contains this address - */ - bool containsAddress(const InetAddress &addr) const; + /** + * Test whether this IP/netmask contains this address + * + * @param addr Address to check + * @return True if this IP/netmask (route) contains this address + */ + bool containsAddress(const InetAddress& addr) const; - /** - * @return True if this is an IPv4 address - */ - inline bool isV4() const { return (ss_family == AF_INET); } + /** + * @return True if this is an IPv4 address + */ + inline bool isV4() const + { + return (ss_family == AF_INET); + } - /** - * @return True if this is an IPv6 address - */ - inline bool isV6() const { return (ss_family == AF_INET6); } + /** + * @return True if this is an IPv6 address + */ + inline bool isV6() const + { + return (ss_family == AF_INET6); + } - /** - * @return pointer to raw address bytes or NULL if not available - */ - inline const void *rawIpData() const - { - switch(ss_family) { - case AF_INET: - return (const void *)&(reinterpret_cast(this)->sin_addr.s_addr); - case AF_INET6: - return (const void *)(reinterpret_cast(this)->sin6_addr.s6_addr); - default: - return 0; - } - } + /** + * @return pointer to raw address bytes or NULL if not available + */ + inline const void* rawIpData() const + { + switch (ss_family) { + case AF_INET: + return (const void*)&(reinterpret_cast(this)->sin_addr.s_addr); + case AF_INET6: + return (const void*)(reinterpret_cast(this)->sin6_addr.s6_addr); + default: + return 0; + } + } - /** - * @return InetAddress containing only the IP portion of this address and a zero port, or NULL if not IPv4 or IPv6 - */ - inline InetAddress ipOnly() const - { - InetAddress r; - switch(ss_family) { - case AF_INET: - r.ss_family = AF_INET; - reinterpret_cast(&r)->sin_addr.s_addr = reinterpret_cast(this)->sin_addr.s_addr; - break; - case AF_INET6: - r.ss_family = AF_INET6; - memcpy(reinterpret_cast(&r)->sin6_addr.s6_addr,reinterpret_cast(this)->sin6_addr.s6_addr,16); - break; - } - return r; - } + /** + * @return InetAddress containing only the IP portion of this address and a zero port, or NULL if not IPv4 or IPv6 + */ + inline InetAddress ipOnly() const + { + InetAddress r; + switch (ss_family) { + case AF_INET: + r.ss_family = AF_INET; + reinterpret_cast(&r)->sin_addr.s_addr = reinterpret_cast(this)->sin_addr.s_addr; + break; + case AF_INET6: + r.ss_family = AF_INET6; + memcpy(reinterpret_cast(&r)->sin6_addr.s6_addr, reinterpret_cast(this)->sin6_addr.s6_addr, 16); + break; + } + return r; + } - /** - * Performs an IP-only comparison or, if that is impossible, a memcmp() - * - * @param a InetAddress to compare again - * @return True if only IP portions are equal (false for non-IP or null addresses) - */ - inline bool ipsEqual(const InetAddress &a) const - { - if (ss_family == a.ss_family) { - if (ss_family == AF_INET) { - return (reinterpret_cast(this)->sin_addr.s_addr == reinterpret_cast(&a)->sin_addr.s_addr); - } - if (ss_family == AF_INET6) { - return (memcmp(reinterpret_cast(this)->sin6_addr.s6_addr,reinterpret_cast(&a)->sin6_addr.s6_addr,16) == 0); - } - return (memcmp(this,&a,sizeof(InetAddress)) == 0); - } - return false; - } + /** + * Performs an IP-only comparison or, if that is impossible, a memcmp() + * + * @param a InetAddress to compare again + * @return True if only IP portions are equal (false for non-IP or null addresses) + */ + inline bool ipsEqual(const InetAddress& a) const + { + if (ss_family == a.ss_family) { + if (ss_family == AF_INET) { + return (reinterpret_cast(this)->sin_addr.s_addr == reinterpret_cast(&a)->sin_addr.s_addr); + } + if (ss_family == AF_INET6) { + return (memcmp(reinterpret_cast(this)->sin6_addr.s6_addr, reinterpret_cast(&a)->sin6_addr.s6_addr, 16) == 0); + } + return (memcmp(this, &a, sizeof(InetAddress)) == 0); + } + return false; + } - /** - * Performs an IP-only comparison or, if that is impossible, a memcmp() - * - * This version compares only the first 64 bits of IPv6 addresses. - * - * @param a InetAddress to compare again - * @return True if only IP portions are equal (false for non-IP or null addresses) - */ - inline bool ipsEqual2(const InetAddress &a) const - { - if (ss_family == a.ss_family) { - if (ss_family == AF_INET) { - return (reinterpret_cast(this)->sin_addr.s_addr == reinterpret_cast(&a)->sin_addr.s_addr); - } - if (ss_family == AF_INET6) { - return (memcmp(reinterpret_cast(this)->sin6_addr.s6_addr, reinterpret_cast(&a)->sin6_addr.s6_addr, 8) == 0); - } - return (memcmp(this,&a,sizeof(InetAddress)) == 0); - } - return false; - } + /** + * Performs an IP-only comparison or, if that is impossible, a memcmp() + * + * This version compares only the first 64 bits of IPv6 addresses. + * + * @param a InetAddress to compare again + * @return True if only IP portions are equal (false for non-IP or null addresses) + */ + inline bool ipsEqual2(const InetAddress& a) const + { + if (ss_family == a.ss_family) { + if (ss_family == AF_INET) { + return (reinterpret_cast(this)->sin_addr.s_addr == reinterpret_cast(&a)->sin_addr.s_addr); + } + if (ss_family == AF_INET6) { + return (memcmp(reinterpret_cast(this)->sin6_addr.s6_addr, reinterpret_cast(&a)->sin6_addr.s6_addr, 8) == 0); + } + return (memcmp(this, &a, sizeof(InetAddress)) == 0); + } + return false; + } - inline unsigned long hashCode() const - { - if (ss_family == AF_INET) { - return ((unsigned long)reinterpret_cast(this)->sin_addr.s_addr + (unsigned long)reinterpret_cast(this)->sin_port); - } else if (ss_family == AF_INET6) { - unsigned long tmp = reinterpret_cast(this)->sin6_port; - const uint8_t *a = reinterpret_cast(reinterpret_cast(this)->sin6_addr.s6_addr); - for(long i=0;i<16;++i) { - reinterpret_cast(&tmp)[i % sizeof(tmp)] ^= a[i]; - } - return tmp; - } else { - unsigned long tmp = reinterpret_cast(this)->sin6_port; - const uint8_t *a = reinterpret_cast(this); - for(long i=0;i<(long)sizeof(InetAddress);++i) { - reinterpret_cast(&tmp)[i % sizeof(tmp)] ^= a[i]; - } - return tmp; - } - } + inline unsigned long hashCode() const + { + if (ss_family == AF_INET) { + return ((unsigned long)reinterpret_cast(this)->sin_addr.s_addr + (unsigned long)reinterpret_cast(this)->sin_port); + } + else if (ss_family == AF_INET6) { + unsigned long tmp = reinterpret_cast(this)->sin6_port; + const uint8_t* a = reinterpret_cast(reinterpret_cast(this)->sin6_addr.s6_addr); + for (long i = 0; i < 16; ++i) { + reinterpret_cast(&tmp)[i % sizeof(tmp)] ^= a[i]; + } + return tmp; + } + else { + unsigned long tmp = reinterpret_cast(this)->sin6_port; + const uint8_t* a = reinterpret_cast(this); + for (long i = 0; i < (long)sizeof(InetAddress); ++i) { + reinterpret_cast(&tmp)[i % sizeof(tmp)] ^= a[i]; + } + return tmp; + } + } - /** - * Set to null/zero - */ - inline void zero() { memset(this,0,sizeof(InetAddress)); } + /** + * Set to null/zero + */ + inline void zero() + { + memset(this, 0, sizeof(InetAddress)); + } - /** - * Check whether this is a network/route rather than an IP assignment - * - * A network is an IP/netmask where everything after the netmask is - * zero e.g. 10.0.0.0/8. - * - * @return True if everything after netmask bits is zero - */ - bool isNetwork() const; + /** + * Check whether this is a network/route rather than an IP assignment + * + * A network is an IP/netmask where everything after the netmask is + * zero e.g. 10.0.0.0/8. + * + * @return True if everything after netmask bits is zero + */ + bool isNetwork() const; - /** - * Find the total number of prefix bits that match between this IP and another - * - * @param b Second IP to compare with - * @return Number of matching prefix bits or 0 if none match or IPs are of different families (e.g. v4 and v6) - */ - inline unsigned int matchingPrefixBits(const InetAddress &b) const - { - unsigned int c = 0; - if (ss_family == b.ss_family) { - switch(ss_family) { - case AF_INET: { - uint32_t ip0 = Utils::ntoh((uint32_t)reinterpret_cast(this)->sin_addr.s_addr); - uint32_t ip1 = Utils::ntoh((uint32_t)reinterpret_cast(&b)->sin_addr.s_addr); - while ((ip0 >> 31) == (ip1 >> 31)) { - ip0 <<= 1; - ip1 <<= 1; - if (++c == 32) { - break; - } - } - } break; - case AF_INET6: { - const uint8_t *ip0 = reinterpret_cast(reinterpret_cast(this)->sin6_addr.s6_addr); - const uint8_t *ip1 = reinterpret_cast(reinterpret_cast(&b)->sin6_addr.s6_addr); - for(unsigned int i=0;i<16;++i) { - if (ip0[i] == ip1[i]) { - c += 8; - } else { - uint8_t ip0b = ip0[i]; - uint8_t ip1b = ip1[i]; - uint8_t bit = 0x80; - while (bit != 0) { - if ((ip0b & bit) != (ip1b & bit)) { - break; - } - ++c; - bit >>= 1; - } - break; - } - } - } break; - } - } - return c; - } + /** + * Find the total number of prefix bits that match between this IP and another + * + * @param b Second IP to compare with + * @return Number of matching prefix bits or 0 if none match or IPs are of different families (e.g. v4 and v6) + */ + inline unsigned int matchingPrefixBits(const InetAddress& b) const + { + unsigned int c = 0; + if (ss_family == b.ss_family) { + switch (ss_family) { + case AF_INET: { + uint32_t ip0 = Utils::ntoh((uint32_t)reinterpret_cast(this)->sin_addr.s_addr); + uint32_t ip1 = Utils::ntoh((uint32_t)reinterpret_cast(&b)->sin_addr.s_addr); + while ((ip0 >> 31) == (ip1 >> 31)) { + ip0 <<= 1; + ip1 <<= 1; + if (++c == 32) { + break; + } + } + } break; + case AF_INET6: { + const uint8_t* ip0 = reinterpret_cast(reinterpret_cast(this)->sin6_addr.s6_addr); + const uint8_t* ip1 = reinterpret_cast(reinterpret_cast(&b)->sin6_addr.s6_addr); + for (unsigned int i = 0; i < 16; ++i) { + if (ip0[i] == ip1[i]) { + c += 8; + } + else { + uint8_t ip0b = ip0[i]; + uint8_t ip1b = ip1[i]; + uint8_t bit = 0x80; + while (bit != 0) { + if ((ip0b & bit) != (ip1b & bit)) { + break; + } + ++c; + bit >>= 1; + } + break; + } + } + } break; + } + } + return c; + } - /** - * @return 14-bit (0-16383) hash of this IP's first 24 or 48 bits (for V4 or V6) for rate limiting code, or 0 if non-IP - */ - inline unsigned long rateGateHash() const - { - unsigned long h = 0; - switch(ss_family) { - case AF_INET: - h = (Utils::ntoh((uint32_t)reinterpret_cast(this)->sin_addr.s_addr) & 0xffffff00) >> 8; - h ^= (h >> 14); - break; - case AF_INET6: { - const uint8_t *ip = reinterpret_cast(reinterpret_cast(this)->sin6_addr.s6_addr); - h = ((unsigned long)ip[0]); - h <<= 1; - h += ((unsigned long)ip[1]); - h <<= 1; - h += ((unsigned long)ip[2]); - h <<= 1; - h += ((unsigned long)ip[3]); - h <<= 1; - h += ((unsigned long)ip[4]); - h <<= 1; - h += ((unsigned long)ip[5]); - } break; - } - return (h & 0x3fff); - } + /** + * @return 14-bit (0-16383) hash of this IP's first 24 or 48 bits (for V4 or V6) for rate limiting code, or 0 if non-IP + */ + inline unsigned long rateGateHash() const + { + unsigned long h = 0; + switch (ss_family) { + case AF_INET: + h = (Utils::ntoh((uint32_t)reinterpret_cast(this)->sin_addr.s_addr) & 0xffffff00) >> 8; + h ^= (h >> 14); + break; + case AF_INET6: { + const uint8_t* ip = reinterpret_cast(reinterpret_cast(this)->sin6_addr.s6_addr); + h = ((unsigned long)ip[0]); + h <<= 1; + h += ((unsigned long)ip[1]); + h <<= 1; + h += ((unsigned long)ip[2]); + h <<= 1; + h += ((unsigned long)ip[3]); + h <<= 1; + h += ((unsigned long)ip[4]); + h <<= 1; + h += ((unsigned long)ip[5]); + } break; + } + return (h & 0x3fff); + } - /** - * @return True if address family is non-zero - */ - inline operator bool() const { return (ss_family != 0); } + /** + * @return True if address family is non-zero + */ + inline operator bool() const + { + return (ss_family != 0); + } - template - inline void serialize(Buffer &b) const - { - // This is used in the protocol and must be the same as describe in places - // like VERB_HELLO in Packet.hpp. - switch(ss_family) { - case AF_INET: - b.append((uint8_t)0x04); - b.append(&(reinterpret_cast(this)->sin_addr.s_addr),4); - b.append((uint16_t)port()); // just in case sin_port != uint16_t - return; - case AF_INET6: - b.append((uint8_t)0x06); - b.append(reinterpret_cast(this)->sin6_addr.s6_addr,16); - b.append((uint16_t)port()); // just in case sin_port != uint16_t - return; - default: - b.append((uint8_t)0); - return; - } - } + template inline void serialize(Buffer& b) const + { + // This is used in the protocol and must be the same as describe in places + // like VERB_HELLO in Packet.hpp. + switch (ss_family) { + case AF_INET: + b.append((uint8_t)0x04); + b.append(&(reinterpret_cast(this)->sin_addr.s_addr), 4); + b.append((uint16_t)port()); // just in case sin_port != uint16_t + return; + case AF_INET6: + b.append((uint8_t)0x06); + b.append(reinterpret_cast(this)->sin6_addr.s6_addr, 16); + b.append((uint16_t)port()); // just in case sin_port != uint16_t + return; + default: + b.append((uint8_t)0); + return; + } + } - template - inline unsigned int deserialize(const Buffer &b,unsigned int startAt = 0) - { - memset(this,0,sizeof(InetAddress)); - unsigned int p = startAt; - switch(b[p++]) { - case 0: - return 1; - case 0x01: - // TODO: Ethernet address (but accept for forward compatibility) - return 7; - case 0x02: - // TODO: Bluetooth address (but accept for forward compatibility) - return 7; - case 0x03: - // TODO: Other address types (but accept for forward compatibility) - // These could be extended/optional things like AF_UNIX, LTE Direct, shared memory, etc. - return (unsigned int)(b.template at(p) + 3); // other addresses begin with 16-bit non-inclusive length - case 0x04: - ss_family = AF_INET; - memcpy(&(reinterpret_cast(this)->sin_addr.s_addr),b.field(p,4),4); - p += 4; - reinterpret_cast(this)->sin_port = Utils::hton(b.template at(p)); - p += 2; - break; - case 0x06: - ss_family = AF_INET6; - memcpy(reinterpret_cast(this)->sin6_addr.s6_addr,b.field(p,16),16); - p += 16; - reinterpret_cast(this)->sin_port = Utils::hton(b.template at(p)); - p += 2; - break; - default: - throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_BAD_ENCODING; - } - return (p - startAt); - } + template inline unsigned int deserialize(const Buffer& b, unsigned int startAt = 0) + { + memset(this, 0, sizeof(InetAddress)); + unsigned int p = startAt; + switch (b[p++]) { + case 0: + return 1; + case 0x01: + // TODO: Ethernet address (but accept for forward compatibility) + return 7; + case 0x02: + // TODO: Bluetooth address (but accept for forward compatibility) + return 7; + case 0x03: + // TODO: Other address types (but accept for forward compatibility) + // These could be extended/optional things like AF_UNIX, LTE Direct, shared memory, etc. + return (unsigned int)(b.template at(p) + 3); // other addresses begin with 16-bit non-inclusive length + case 0x04: + ss_family = AF_INET; + memcpy(&(reinterpret_cast(this)->sin_addr.s_addr), b.field(p, 4), 4); + p += 4; + reinterpret_cast(this)->sin_port = Utils::hton(b.template at(p)); + p += 2; + break; + case 0x06: + ss_family = AF_INET6; + memcpy(reinterpret_cast(this)->sin6_addr.s6_addr, b.field(p, 16), 16); + p += 16; + reinterpret_cast(this)->sin_port = Utils::hton(b.template at(p)); + p += 2; + break; + default: + throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_BAD_ENCODING; + } + return (p - startAt); + } - bool operator==(const InetAddress &a) const; - bool operator<(const InetAddress &a) const; - inline bool operator!=(const InetAddress &a) const { return !(*this == a); } - inline bool operator>(const InetAddress &a) const { return (a < *this); } - inline bool operator<=(const InetAddress &a) const { return !(a < *this); } - inline bool operator>=(const InetAddress &a) const { return !(*this < a); } + bool operator==(const InetAddress& a) const; + bool operator<(const InetAddress& a) const; + inline bool operator!=(const InetAddress& a) const + { + return ! (*this == a); + } + inline bool operator>(const InetAddress& a) const + { + return (a < *this); + } + inline bool operator<=(const InetAddress& a) const + { + return ! (a < *this); + } + inline bool operator>=(const InetAddress& a) const + { + return ! (*this < a); + } - /** - * @param mac MAC address seed - * @return IPv6 link-local address - */ - static InetAddress makeIpv6LinkLocal(const MAC &mac); + /** + * @param mac MAC address seed + * @return IPv6 link-local address + */ + static InetAddress makeIpv6LinkLocal(const MAC& mac); - /** - * Compute private IPv6 unicast address from network ID and ZeroTier address - * - * This generates a private unicast IPv6 address that is mostly compliant - * with the letter of RFC4193 and certainly compliant in spirit. - * - * RFC4193 specifies a format of: - * - * | 7 bits |1| 40 bits | 16 bits | 64 bits | - * | Prefix |L| Global ID | Subnet ID | Interface ID | - * - * The 'L' bit is set to 1, yielding an address beginning with 0xfd. Then - * the network ID is filled into the global ID, subnet ID, and first byte - * of the "interface ID" field. Since the first 40 bits of the network ID - * is the unique ZeroTier address of its controller, this makes a very - * good random global ID. Since network IDs have 24 more bits, we let it - * overflow into the interface ID. - * - * After that we pad with two bytes: 0x99, 0x93, namely the default ZeroTier - * port in hex. - * - * Finally we fill the remaining 40 bits of the interface ID field with - * the 40-bit unique ZeroTier device ID of the network member. - * - * This yields a valid RFC4193 address with a random global ID, a - * meaningful subnet ID, and a unique interface ID, all mappable back onto - * ZeroTier space. - * - * This in turn could allow us, on networks numbered this way, to emulate - * IPv6 NDP and eliminate all multicast. This could be beneficial for - * small devices and huge networks, e.g. IoT applications. - * - * The returned address is given an odd prefix length of /88, since within - * a given network only the last 40 bits (device ID) are variable. This - * is a bit unusual but as far as we know should not cause any problems with - * any non-braindead IPv6 stack. - * - * @param nwid 64-bit network ID - * @param zeroTierAddress 40-bit device address (in least significant 40 bits, highest 24 bits ignored) - * @return IPv6 private unicast address with /88 netmask - */ - static InetAddress makeIpv6rfc4193(uint64_t nwid,uint64_t zeroTierAddress); + /** + * Compute private IPv6 unicast address from network ID and ZeroTier address + * + * This generates a private unicast IPv6 address that is mostly compliant + * with the letter of RFC4193 and certainly compliant in spirit. + * + * RFC4193 specifies a format of: + * + * | 7 bits |1| 40 bits | 16 bits | 64 bits | + * | Prefix |L| Global ID | Subnet ID | Interface ID | + * + * The 'L' bit is set to 1, yielding an address beginning with 0xfd. Then + * the network ID is filled into the global ID, subnet ID, and first byte + * of the "interface ID" field. Since the first 40 bits of the network ID + * is the unique ZeroTier address of its controller, this makes a very + * good random global ID. Since network IDs have 24 more bits, we let it + * overflow into the interface ID. + * + * After that we pad with two bytes: 0x99, 0x93, namely the default ZeroTier + * port in hex. + * + * Finally we fill the remaining 40 bits of the interface ID field with + * the 40-bit unique ZeroTier device ID of the network member. + * + * This yields a valid RFC4193 address with a random global ID, a + * meaningful subnet ID, and a unique interface ID, all mappable back onto + * ZeroTier space. + * + * This in turn could allow us, on networks numbered this way, to emulate + * IPv6 NDP and eliminate all multicast. This could be beneficial for + * small devices and huge networks, e.g. IoT applications. + * + * The returned address is given an odd prefix length of /88, since within + * a given network only the last 40 bits (device ID) are variable. This + * is a bit unusual but as far as we know should not cause any problems with + * any non-braindead IPv6 stack. + * + * @param nwid 64-bit network ID + * @param zeroTierAddress 40-bit device address (in least significant 40 bits, highest 24 bits ignored) + * @return IPv6 private unicast address with /88 netmask + */ + static InetAddress makeIpv6rfc4193(uint64_t nwid, uint64_t zeroTierAddress); - /** - * Compute a private IPv6 "6plane" unicast address from network ID and ZeroTier address - */ - static InetAddress makeIpv66plane(uint64_t nwid,uint64_t zeroTierAddress); + /** + * Compute a private IPv6 "6plane" unicast address from network ID and ZeroTier address + */ + static InetAddress makeIpv66plane(uint64_t nwid, uint64_t zeroTierAddress); }; -} // namespace ZeroTier +} // namespace ZeroTier #endif diff --git a/node/MAC.hpp b/node/MAC.hpp index 4520adc0..e0948129 100644 --- a/node/MAC.hpp +++ b/node/MAC.hpp @@ -14,230 +14,282 @@ #ifndef ZT_MAC_HPP #define ZT_MAC_HPP -#include -#include -#include - -#include "Constants.hpp" -#include "Utils.hpp" #include "Address.hpp" #include "Buffer.hpp" +#include "Constants.hpp" +#include "Utils.hpp" + +#include +#include +#include namespace ZeroTier { /** * 48-byte Ethernet MAC address */ -class MAC -{ -public: - MAC() : _m(0ULL) {} - MAC(const MAC &m) : _m(m._m) {} +class MAC { + public: + MAC() : _m(0ULL) + { + } + MAC(const MAC& m) : _m(m._m) + { + } - MAC(const unsigned char a,const unsigned char b,const unsigned char c,const unsigned char d,const unsigned char e,const unsigned char f) : - _m( ((((uint64_t)a) & 0xffULL) << 40) | - ((((uint64_t)b) & 0xffULL) << 32) | - ((((uint64_t)c) & 0xffULL) << 24) | - ((((uint64_t)d) & 0xffULL) << 16) | - ((((uint64_t)e) & 0xffULL) << 8) | - (((uint64_t)f) & 0xffULL) ) {} - MAC(const void *bits,unsigned int len) { setTo(bits,len); } - MAC(const Address &ztaddr,uint64_t nwid) { fromAddress(ztaddr,nwid); } - MAC(const uint64_t m) : _m(m & 0xffffffffffffULL) {} + MAC(const unsigned char a, const unsigned char b, const unsigned char c, const unsigned char d, const unsigned char e, const unsigned char f) + : _m(((((uint64_t)a) & 0xffULL) << 40) | ((((uint64_t)b) & 0xffULL) << 32) | ((((uint64_t)c) & 0xffULL) << 24) | ((((uint64_t)d) & 0xffULL) << 16) | ((((uint64_t)e) & 0xffULL) << 8) | (((uint64_t)f) & 0xffULL)) + { + } + MAC(const void* bits, unsigned int len) + { + setTo(bits, len); + } + MAC(const Address& ztaddr, uint64_t nwid) + { + fromAddress(ztaddr, nwid); + } + MAC(const uint64_t m) : _m(m & 0xffffffffffffULL) + { + } - /** - * @return MAC in 64-bit integer - */ - inline uint64_t toInt() const { return _m; } + /** + * @return MAC in 64-bit integer + */ + inline uint64_t toInt() const + { + return _m; + } - /** - * Set MAC to zero - */ - inline void zero() { _m = 0ULL; } + /** + * Set MAC to zero + */ + inline void zero() + { + _m = 0ULL; + } - /** - * @return True if MAC is non-zero - */ - inline operator bool() const { return (_m != 0ULL); } + /** + * @return True if MAC is non-zero + */ + inline operator bool() const + { + return (_m != 0ULL); + } - /** - * @param bits Raw MAC in big-endian byte order - * @param len Length, must be >= 6 or result is zero - */ - inline void setTo(const void *bits,unsigned int len) - { - if (len < 6) { - _m = 0ULL; - return; - } - const unsigned char *b = (const unsigned char *)bits; - _m = ((((uint64_t)*b) & 0xff) << 40); - ++b; - _m |= ((((uint64_t)*b) & 0xff) << 32); - ++b; - _m |= ((((uint64_t)*b) & 0xff) << 24); - ++b; - _m |= ((((uint64_t)*b) & 0xff) << 16); - ++b; - _m |= ((((uint64_t)*b) & 0xff) << 8); - ++b; - _m |= (((uint64_t)*b) & 0xff); - } + /** + * @param bits Raw MAC in big-endian byte order + * @param len Length, must be >= 6 or result is zero + */ + inline void setTo(const void* bits, unsigned int len) + { + if (len < 6) { + _m = 0ULL; + return; + } + const unsigned char* b = (const unsigned char*)bits; + _m = ((((uint64_t)*b) & 0xff) << 40); + ++b; + _m |= ((((uint64_t)*b) & 0xff) << 32); + ++b; + _m |= ((((uint64_t)*b) & 0xff) << 24); + ++b; + _m |= ((((uint64_t)*b) & 0xff) << 16); + ++b; + _m |= ((((uint64_t)*b) & 0xff) << 8); + ++b; + _m |= (((uint64_t)*b) & 0xff); + } - /** - * @param buf Destination buffer for MAC in big-endian byte order - * @param len Length of buffer, must be >= 6 or nothing is copied - */ - inline void copyTo(void *buf,unsigned int len) const - { - if (len < 6) { - return; - } - unsigned char *b = (unsigned char *)buf; - *(b++) = (unsigned char)((_m >> 40) & 0xff); - *(b++) = (unsigned char)((_m >> 32) & 0xff); - *(b++) = (unsigned char)((_m >> 24) & 0xff); - *(b++) = (unsigned char)((_m >> 16) & 0xff); - *(b++) = (unsigned char)((_m >> 8) & 0xff); - *b = (unsigned char)(_m & 0xff); - } + /** + * @param buf Destination buffer for MAC in big-endian byte order + * @param len Length of buffer, must be >= 6 or nothing is copied + */ + inline void copyTo(void* buf, unsigned int len) const + { + if (len < 6) { + return; + } + unsigned char* b = (unsigned char*)buf; + *(b++) = (unsigned char)((_m >> 40) & 0xff); + *(b++) = (unsigned char)((_m >> 32) & 0xff); + *(b++) = (unsigned char)((_m >> 24) & 0xff); + *(b++) = (unsigned char)((_m >> 16) & 0xff); + *(b++) = (unsigned char)((_m >> 8) & 0xff); + *b = (unsigned char)(_m & 0xff); + } - /** - * Append to a buffer in big-endian byte order - * - * @param b Buffer to append to - */ - template - inline void appendTo(Buffer &b) const - { - unsigned char *p = (unsigned char *)b.appendField(6); - *(p++) = (unsigned char)((_m >> 40) & 0xff); - *(p++) = (unsigned char)((_m >> 32) & 0xff); - *(p++) = (unsigned char)((_m >> 24) & 0xff); - *(p++) = (unsigned char)((_m >> 16) & 0xff); - *(p++) = (unsigned char)((_m >> 8) & 0xff); - *p = (unsigned char)(_m & 0xff); - } + /** + * Append to a buffer in big-endian byte order + * + * @param b Buffer to append to + */ + template inline void appendTo(Buffer& b) const + { + unsigned char* p = (unsigned char*)b.appendField(6); + *(p++) = (unsigned char)((_m >> 40) & 0xff); + *(p++) = (unsigned char)((_m >> 32) & 0xff); + *(p++) = (unsigned char)((_m >> 24) & 0xff); + *(p++) = (unsigned char)((_m >> 16) & 0xff); + *(p++) = (unsigned char)((_m >> 8) & 0xff); + *p = (unsigned char)(_m & 0xff); + } - /** - * @return True if this is broadcast (all 0xff) - */ - inline bool isBroadcast() const { return (_m == 0xffffffffffffULL); } + /** + * @return True if this is broadcast (all 0xff) + */ + inline bool isBroadcast() const + { + return (_m == 0xffffffffffffULL); + } - /** - * @return True if this is a multicast MAC - */ - inline bool isMulticast() const { return ((_m & 0x010000000000ULL) != 0ULL); } + /** + * @return True if this is a multicast MAC + */ + inline bool isMulticast() const + { + return ((_m & 0x010000000000ULL) != 0ULL); + } - /** - * @param True if this is a locally-administered MAC - */ - inline bool isLocallyAdministered() const { return ((_m & 0x020000000000ULL) != 0ULL); } + /** + * @param True if this is a locally-administered MAC + */ + inline bool isLocallyAdministered() const + { + return ((_m & 0x020000000000ULL) != 0ULL); + } - /** - * Set this MAC to a MAC derived from an address and a network ID - * - * @param ztaddr ZeroTier address - * @param nwid 64-bit network ID - */ - inline void fromAddress(const Address &ztaddr,uint64_t nwid) - { - uint64_t m = ((uint64_t)firstOctetForNetwork(nwid)) << 40; - m |= ztaddr.toInt(); // a is 40 bits - m ^= ((nwid >> 8) & 0xff) << 32; - m ^= ((nwid >> 16) & 0xff) << 24; - m ^= ((nwid >> 24) & 0xff) << 16; - m ^= ((nwid >> 32) & 0xff) << 8; - m ^= (nwid >> 40) & 0xff; - _m = m; - } + /** + * Set this MAC to a MAC derived from an address and a network ID + * + * @param ztaddr ZeroTier address + * @param nwid 64-bit network ID + */ + inline void fromAddress(const Address& ztaddr, uint64_t nwid) + { + uint64_t m = ((uint64_t)firstOctetForNetwork(nwid)) << 40; + m |= ztaddr.toInt(); // a is 40 bits + m ^= ((nwid >> 8) & 0xff) << 32; + m ^= ((nwid >> 16) & 0xff) << 24; + m ^= ((nwid >> 24) & 0xff) << 16; + m ^= ((nwid >> 32) & 0xff) << 8; + m ^= (nwid >> 40) & 0xff; + _m = m; + } - /** - * Get the ZeroTier address for this MAC on this network (assuming no bridging of course, basic unicast) - * - * This just XORs the next-least-significant 5 bytes of the network ID again to unmask. - * - * @param nwid Network ID - */ - inline Address toAddress(uint64_t nwid) const - { - uint64_t a = _m & 0xffffffffffULL; // least significant 40 bits of MAC are formed from address - a ^= ((nwid >> 8) & 0xff) << 32; // ... XORed with bits 8-48 of the nwid in little-endian byte order, so unmask it - a ^= ((nwid >> 16) & 0xff) << 24; - a ^= ((nwid >> 24) & 0xff) << 16; - a ^= ((nwid >> 32) & 0xff) << 8; - a ^= (nwid >> 40) & 0xff; - return Address(a); - } + /** + * Get the ZeroTier address for this MAC on this network (assuming no bridging of course, basic unicast) + * + * This just XORs the next-least-significant 5 bytes of the network ID again to unmask. + * + * @param nwid Network ID + */ + inline Address toAddress(uint64_t nwid) const + { + uint64_t a = _m & 0xffffffffffULL; // least significant 40 bits of MAC are formed from address + a ^= ((nwid >> 8) & 0xff) << 32; // ... XORed with bits 8-48 of the nwid in little-endian byte order, so unmask it + a ^= ((nwid >> 16) & 0xff) << 24; + a ^= ((nwid >> 24) & 0xff) << 16; + a ^= ((nwid >> 32) & 0xff) << 8; + a ^= (nwid >> 40) & 0xff; + return Address(a); + } - /** - * @param nwid Network ID - * @return First octet of MAC for this network - */ - static inline unsigned char firstOctetForNetwork(uint64_t nwid) - { - unsigned char a = ((unsigned char)(nwid & 0xfe) | 0x02); // locally administered, not multicast, from LSB of network ID - return ((a == 0x52) ? 0x32 : a); // blacklist 0x52 since it's used by KVM, libvirt, and other popular virtualization engines... seems de-facto standard on Linux - } + /** + * @param nwid Network ID + * @return First octet of MAC for this network + */ + static inline unsigned char firstOctetForNetwork(uint64_t nwid) + { + unsigned char a = ((unsigned char)(nwid & 0xfe) | 0x02); // locally administered, not multicast, from LSB of network ID + return ((a == 0x52) ? 0x32 : a); // blacklist 0x52 since it's used by KVM, libvirt, and other popular virtualization engines... seems de-facto standard on Linux + } - /** - * @param i Value from 0 to 5 (inclusive) - * @return Byte at said position (address interpreted in big-endian order) - */ - inline unsigned char operator[](unsigned int i) const { return (unsigned char)((_m >> (40 - (i * 8))) & 0xff); } + /** + * @param i Value from 0 to 5 (inclusive) + * @return Byte at said position (address interpreted in big-endian order) + */ + inline unsigned char operator[](unsigned int i) const + { + return (unsigned char)((_m >> (40 - (i * 8))) & 0xff); + } - /** - * @return 6, which is the number of bytes in a MAC, for container compliance - */ - inline unsigned int size() const { return 6; } + /** + * @return 6, which is the number of bytes in a MAC, for container compliance + */ + inline unsigned int size() const + { + return 6; + } - inline unsigned long hashCode() const { return (unsigned long)_m; } + inline unsigned long hashCode() const + { + return (unsigned long)_m; + } - inline char *toString(char buf[18]) const - { - buf[0] = Utils::HEXCHARS[(_m >> 44) & 0xf]; - buf[1] = Utils::HEXCHARS[(_m >> 40) & 0xf]; - buf[2] = ':'; - buf[3] = Utils::HEXCHARS[(_m >> 36) & 0xf]; - buf[4] = Utils::HEXCHARS[(_m >> 32) & 0xf]; - buf[5] = ':'; - buf[6] = Utils::HEXCHARS[(_m >> 28) & 0xf]; - buf[7] = Utils::HEXCHARS[(_m >> 24) & 0xf]; - buf[8] = ':'; - buf[9] = Utils::HEXCHARS[(_m >> 20) & 0xf]; - buf[10] = Utils::HEXCHARS[(_m >> 16) & 0xf]; - buf[11] = ':'; - buf[12] = Utils::HEXCHARS[(_m >> 12) & 0xf]; - buf[13] = Utils::HEXCHARS[(_m >> 8) & 0xf]; - buf[14] = ':'; - buf[15] = Utils::HEXCHARS[(_m >> 4) & 0xf]; - buf[16] = Utils::HEXCHARS[_m & 0xf]; - buf[17] = (char)0; - return buf; - } + inline char* toString(char buf[18]) const + { + buf[0] = Utils::HEXCHARS[(_m >> 44) & 0xf]; + buf[1] = Utils::HEXCHARS[(_m >> 40) & 0xf]; + buf[2] = ':'; + buf[3] = Utils::HEXCHARS[(_m >> 36) & 0xf]; + buf[4] = Utils::HEXCHARS[(_m >> 32) & 0xf]; + buf[5] = ':'; + buf[6] = Utils::HEXCHARS[(_m >> 28) & 0xf]; + buf[7] = Utils::HEXCHARS[(_m >> 24) & 0xf]; + buf[8] = ':'; + buf[9] = Utils::HEXCHARS[(_m >> 20) & 0xf]; + buf[10] = Utils::HEXCHARS[(_m >> 16) & 0xf]; + buf[11] = ':'; + buf[12] = Utils::HEXCHARS[(_m >> 12) & 0xf]; + buf[13] = Utils::HEXCHARS[(_m >> 8) & 0xf]; + buf[14] = ':'; + buf[15] = Utils::HEXCHARS[(_m >> 4) & 0xf]; + buf[16] = Utils::HEXCHARS[_m & 0xf]; + buf[17] = (char)0; + return buf; + } - inline MAC &operator=(const MAC &m) - { - _m = m._m; - return *this; - } - inline MAC &operator=(const uint64_t m) - { - _m = m; - return *this; - } + inline MAC& operator=(const MAC& m) + { + _m = m._m; + return *this; + } + inline MAC& operator=(const uint64_t m) + { + _m = m; + return *this; + } - inline bool operator==(const MAC &m) const { return (_m == m._m); } - inline bool operator!=(const MAC &m) const { return (_m != m._m); } - inline bool operator<(const MAC &m) const { return (_m < m._m); } - inline bool operator<=(const MAC &m) const { return (_m <= m._m); } - inline bool operator>(const MAC &m) const { return (_m > m._m); } - inline bool operator>=(const MAC &m) const { return (_m >= m._m); } + inline bool operator==(const MAC& m) const + { + return (_m == m._m); + } + inline bool operator!=(const MAC& m) const + { + return (_m != m._m); + } + inline bool operator<(const MAC& m) const + { + return (_m < m._m); + } + inline bool operator<=(const MAC& m) const + { + return (_m <= m._m); + } + inline bool operator>(const MAC& m) const + { + return (_m > m._m); + } + inline bool operator>=(const MAC& m) const + { + return (_m >= m._m); + } -private: - uint64_t _m; + private: + uint64_t _m; }; -} // namespace ZeroTier +} // namespace ZeroTier #endif diff --git a/node/Membership.cpp b/node/Membership.cpp index 0c5d9cc7..04de6a3e 100644 --- a/node/Membership.cpp +++ b/node/Membership.cpp @@ -11,212 +11,215 @@ */ /****/ -#include - #include "Membership.hpp" -#include "RuntimeEnvironment.hpp" -#include "Peer.hpp" -#include "Topology.hpp" -#include "Switch.hpp" -#include "Packet.hpp" + #include "Node.hpp" +#include "Packet.hpp" +#include "Peer.hpp" +#include "RuntimeEnvironment.hpp" +#include "Switch.hpp" +#include "Topology.hpp" #include "Trace.hpp" +#include + namespace ZeroTier { -Membership::Membership() : - _lastUpdatedMulticast(0), - _comRevocationThreshold(0), - _lastPushedCredentials(0), - _revocations(4), - _remoteTags(4), - _remoteCaps(4), - _remoteCoos(4) +Membership::Membership() : _lastUpdatedMulticast(0), _comRevocationThreshold(0), _lastPushedCredentials(0), _revocations(4), _remoteTags(4), _remoteCaps(4), _remoteCoos(4) { } -void Membership::pushCredentials(const RuntimeEnvironment *RR,void *tPtr,const int64_t now,const Address &peerAddress,const NetworkConfig &nconf) +void Membership::pushCredentials(const RuntimeEnvironment* RR, void* tPtr, const int64_t now, const Address& peerAddress, const NetworkConfig& nconf) { - const Capability *sendCaps[ZT_MAX_NETWORK_CAPABILITIES]; - unsigned int sendCapCount = 0; - for(unsigned int c=0;cidentity.address(),Packet::VERB_NETWORK_CREDENTIALS); + unsigned int capPtr = 0; + unsigned int tagPtr = 0; + unsigned int cooPtr = 0; + bool sendCom = (bool)(nconf.com); + while ((capPtr < sendCapCount) || (tagPtr < sendTagCount) || (cooPtr < sendCooCount) || (sendCom)) { + Packet outp(peerAddress, RR->identity.address(), Packet::VERB_NETWORK_CREDENTIALS); - if (sendCom) { - sendCom = false; - nconf.com.serialize(outp); - } - outp.append((uint8_t)0x00); + if (sendCom) { + sendCom = false; + nconf.com.serialize(outp); + } + outp.append((uint8_t)0x00); - const unsigned int capCountAt = outp.size(); - outp.addSize(2); - unsigned int thisPacketCapCount = 0; - while ((capPtr < sendCapCount)&&((outp.size() + sizeof(Capability) + 16) < ZT_PROTO_MAX_PACKET_LENGTH)) { - sendCaps[capPtr++]->serialize(outp); - ++thisPacketCapCount; - } - outp.setAt(capCountAt,(uint16_t)thisPacketCapCount); + const unsigned int capCountAt = outp.size(); + outp.addSize(2); + unsigned int thisPacketCapCount = 0; + while ((capPtr < sendCapCount) && ((outp.size() + sizeof(Capability) + 16) < ZT_PROTO_MAX_PACKET_LENGTH)) { + sendCaps[capPtr++]->serialize(outp); + ++thisPacketCapCount; + } + outp.setAt(capCountAt, (uint16_t)thisPacketCapCount); - const unsigned int tagCountAt = outp.size(); - outp.addSize(2); - unsigned int thisPacketTagCount = 0; - while ((tagPtr < sendTagCount)&&((outp.size() + sizeof(Tag) + 16) < ZT_PROTO_MAX_PACKET_LENGTH)) { - sendTags[tagPtr++]->serialize(outp); - ++thisPacketTagCount; - } - outp.setAt(tagCountAt,(uint16_t)thisPacketTagCount); + const unsigned int tagCountAt = outp.size(); + outp.addSize(2); + unsigned int thisPacketTagCount = 0; + while ((tagPtr < sendTagCount) && ((outp.size() + sizeof(Tag) + 16) < ZT_PROTO_MAX_PACKET_LENGTH)) { + sendTags[tagPtr++]->serialize(outp); + ++thisPacketTagCount; + } + outp.setAt(tagCountAt, (uint16_t)thisPacketTagCount); - // No revocations, these propagate differently - outp.append((uint16_t)0); + // No revocations, these propagate differently + outp.append((uint16_t)0); - const unsigned int cooCountAt = outp.size(); - outp.addSize(2); - unsigned int thisPacketCooCount = 0; - while ((cooPtr < sendCooCount)&&((outp.size() + sizeof(CertificateOfOwnership) + 16) < ZT_PROTO_MAX_PACKET_LENGTH)) { - sendCoos[cooPtr++]->serialize(outp); - ++thisPacketCooCount; - } - outp.setAt(cooCountAt,(uint16_t)thisPacketCooCount); + const unsigned int cooCountAt = outp.size(); + outp.addSize(2); + unsigned int thisPacketCooCount = 0; + while ((cooPtr < sendCooCount) && ((outp.size() + sizeof(CertificateOfOwnership) + 16) < ZT_PROTO_MAX_PACKET_LENGTH)) { + sendCoos[cooPtr++]->serialize(outp); + ++thisPacketCooCount; + } + outp.setAt(cooCountAt, (uint16_t)thisPacketCooCount); - outp.compress(); - RR->sw->send(tPtr,outp,true); - Metrics::pkt_network_credentials_out++; - } + outp.compress(); + RR->sw->send(tPtr, outp, true); + Metrics::pkt_network_credentials_out++; + } - _lastPushedCredentials = now; + _lastPushedCredentials = now; } -Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironment *RR,void *tPtr,const NetworkConfig &nconf,const CertificateOfMembership &com) +Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironment* RR, void* tPtr, const NetworkConfig& nconf, const CertificateOfMembership& com) { - const int64_t newts = com.timestamp(); - if (newts <= _comRevocationThreshold) { - RR->t->credentialRejected(tPtr,com,"revoked"); - return ADD_REJECTED; - } + const int64_t newts = com.timestamp(); + if (newts <= _comRevocationThreshold) { + RR->t->credentialRejected(tPtr, com, "revoked"); + return ADD_REJECTED; + } - const int64_t oldts = _com.timestamp(); - if (newts < oldts) { - RR->t->credentialRejected(tPtr,com,"old"); - return ADD_REJECTED; - } - if (_com == com) { - return ADD_ACCEPTED_REDUNDANT; - } + const int64_t oldts = _com.timestamp(); + if (newts < oldts) { + RR->t->credentialRejected(tPtr, com, "old"); + return ADD_REJECTED; + } + if (_com == com) { + return ADD_ACCEPTED_REDUNDANT; + } - switch(com.verify(RR,tPtr)) { - default: - RR->t->credentialRejected(tPtr,com,"invalid"); - return ADD_REJECTED; - case 0: - //printf("%.16llx %.10llx replacing COM %lld with %lld\n", com.networkId(), com.issuedTo().toInt(), _com.timestamp(), com.timestamp()); fflush(stdout); - _com = com; - return ADD_ACCEPTED_NEW; - case 1: - return ADD_DEFERRED_FOR_WHOIS; - } + switch (com.verify(RR, tPtr)) { + default: + RR->t->credentialRejected(tPtr, com, "invalid"); + return ADD_REJECTED; + case 0: + // printf("%.16llx %.10llx replacing COM %lld with %lld\n", com.networkId(), com.issuedTo().toInt(), _com.timestamp(), com.timestamp()); fflush(stdout); + _com = com; + return ADD_ACCEPTED_NEW; + case 1: + return ADD_DEFERRED_FOR_WHOIS; + } } // Template out addCredential() for many cred types to avoid copypasta -template -static Membership::AddCredentialResult _addCredImpl(Hashtable &remoteCreds,const Hashtable &revocations,const RuntimeEnvironment *RR,void *tPtr,const NetworkConfig &nconf,const C &cred) +template +static Membership::AddCredentialResult _addCredImpl(Hashtable& remoteCreds, const Hashtable& revocations, const RuntimeEnvironment* RR, void* tPtr, const NetworkConfig& nconf, const C& cred) { - C *rc = remoteCreds.get(cred.id()); - if (rc) { - if (rc->timestamp() > cred.timestamp()) { - RR->t->credentialRejected(tPtr,cred,"old"); - return Membership::ADD_REJECTED; - } - if (*rc == cred) { - return Membership::ADD_ACCEPTED_REDUNDANT; - } - } + C* rc = remoteCreds.get(cred.id()); + if (rc) { + if (rc->timestamp() > cred.timestamp()) { + RR->t->credentialRejected(tPtr, cred, "old"); + return Membership::ADD_REJECTED; + } + if (*rc == cred) { + return Membership::ADD_ACCEPTED_REDUNDANT; + } + } - const int64_t *const rt = revocations.get(Membership::credentialKey(C::credentialType(),cred.id())); - if ((rt)&&(*rt >= cred.timestamp())) { - RR->t->credentialRejected(tPtr,cred,"revoked"); - return Membership::ADD_REJECTED; - } + const int64_t* const rt = revocations.get(Membership::credentialKey(C::credentialType(), cred.id())); + if ((rt) && (*rt >= cred.timestamp())) { + RR->t->credentialRejected(tPtr, cred, "revoked"); + return Membership::ADD_REJECTED; + } - switch(cred.verify(RR,tPtr)) { - default: - RR->t->credentialRejected(tPtr,cred,"invalid"); - return Membership::ADD_REJECTED; - case 0: - if (!rc) { - rc = &(remoteCreds[cred.id()]); - } - *rc = cred; - return Membership::ADD_ACCEPTED_NEW; - case 1: - return Membership::ADD_DEFERRED_FOR_WHOIS; - } + switch (cred.verify(RR, tPtr)) { + default: + RR->t->credentialRejected(tPtr, cred, "invalid"); + return Membership::ADD_REJECTED; + case 0: + if (! rc) { + rc = &(remoteCreds[cred.id()]); + } + *rc = cred; + return Membership::ADD_ACCEPTED_NEW; + case 1: + return Membership::ADD_DEFERRED_FOR_WHOIS; + } } -Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironment *RR,void *tPtr,const NetworkConfig &nconf,const Tag &tag) { return _addCredImpl(_remoteTags,_revocations,RR,tPtr,nconf,tag); } -Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironment *RR,void *tPtr,const NetworkConfig &nconf,const Capability &cap) { return _addCredImpl(_remoteCaps,_revocations,RR,tPtr,nconf,cap); } -Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironment *RR,void *tPtr,const NetworkConfig &nconf,const CertificateOfOwnership &coo) { return _addCredImpl(_remoteCoos,_revocations,RR,tPtr,nconf,coo); } - -Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironment *RR,void *tPtr,const NetworkConfig &nconf,const Revocation &rev) +Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironment* RR, void* tPtr, const NetworkConfig& nconf, const Tag& tag) { - int64_t *rt; - switch(rev.verify(RR,tPtr)) { - default: - RR->t->credentialRejected(tPtr,rev,"invalid"); - return ADD_REJECTED; - case 0: { - const Credential::Type ct = rev.type(); - switch(ct) { - case Credential::CREDENTIAL_TYPE_COM: - if (rev.threshold() > _comRevocationThreshold) { - _comRevocationThreshold = rev.threshold(); - return ADD_ACCEPTED_NEW; - } - return ADD_ACCEPTED_REDUNDANT; - case Credential::CREDENTIAL_TYPE_CAPABILITY: - case Credential::CREDENTIAL_TYPE_TAG: - case Credential::CREDENTIAL_TYPE_COO: - rt = &(_revocations[credentialKey(ct,rev.credentialId())]); - if (*rt < rev.threshold()) { - *rt = rev.threshold(); - _comRevocationThreshold = rev.threshold(); - return ADD_ACCEPTED_NEW; - } - return ADD_ACCEPTED_REDUNDANT; - default: - RR->t->credentialRejected(tPtr,rev,"invalid"); - return ADD_REJECTED; - } - } - case 1: - return ADD_DEFERRED_FOR_WHOIS; - } + return _addCredImpl(_remoteTags, _revocations, RR, tPtr, nconf, tag); +} +Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironment* RR, void* tPtr, const NetworkConfig& nconf, const Capability& cap) +{ + return _addCredImpl(_remoteCaps, _revocations, RR, tPtr, nconf, cap); +} +Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironment* RR, void* tPtr, const NetworkConfig& nconf, const CertificateOfOwnership& coo) +{ + return _addCredImpl(_remoteCoos, _revocations, RR, tPtr, nconf, coo); } -void Membership::clean(const int64_t now,const NetworkConfig &nconf) +Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironment* RR, void* tPtr, const NetworkConfig& nconf, const Revocation& rev) { - _cleanCredImpl(nconf,_remoteTags); - _cleanCredImpl(nconf,_remoteCaps); - _cleanCredImpl(nconf,_remoteCoos); + int64_t* rt; + switch (rev.verify(RR, tPtr)) { + default: + RR->t->credentialRejected(tPtr, rev, "invalid"); + return ADD_REJECTED; + case 0: { + const Credential::Type ct = rev.type(); + switch (ct) { + case Credential::CREDENTIAL_TYPE_COM: + if (rev.threshold() > _comRevocationThreshold) { + _comRevocationThreshold = rev.threshold(); + return ADD_ACCEPTED_NEW; + } + return ADD_ACCEPTED_REDUNDANT; + case Credential::CREDENTIAL_TYPE_CAPABILITY: + case Credential::CREDENTIAL_TYPE_TAG: + case Credential::CREDENTIAL_TYPE_COO: + rt = &(_revocations[credentialKey(ct, rev.credentialId())]); + if (*rt < rev.threshold()) { + *rt = rev.threshold(); + _comRevocationThreshold = rev.threshold(); + return ADD_ACCEPTED_NEW; + } + return ADD_ACCEPTED_REDUNDANT; + default: + RR->t->credentialRejected(tPtr, rev, "invalid"); + return ADD_REJECTED; + } + } + case 1: + return ADD_DEFERRED_FOR_WHOIS; + } } -} // namespace ZeroTier +void Membership::clean(const int64_t now, const NetworkConfig& nconf) +{ + _cleanCredImpl(nconf, _remoteTags); + _cleanCredImpl(nconf, _remoteCaps); + _cleanCredImpl(nconf, _remoteCoos); +} + +} // namespace ZeroTier diff --git a/node/Membership.hpp b/node/Membership.hpp index d7c98e5b..4429e1d1 100644 --- a/node/Membership.hpp +++ b/node/Membership.hpp @@ -14,17 +14,17 @@ #ifndef ZT_MEMBERSHIP_HPP #define ZT_MEMBERSHIP_HPP -#include - -#include "Constants.hpp" #include "../include/ZeroTierOne.h" +#include "Capability.hpp" +#include "CertificateOfMembership.hpp" +#include "Constants.hpp" #include "Credential.hpp" #include "Hashtable.hpp" -#include "CertificateOfMembership.hpp" -#include "Capability.hpp" -#include "Tag.hpp" -#include "Revocation.hpp" #include "NetworkConfig.hpp" +#include "Revocation.hpp" +#include "Tag.hpp" + +#include #define ZT_MEMBERSHIP_CRED_ID_UNUSED 0xffffffffffffffffULL @@ -40,257 +40,256 @@ class Network; * * This class is not thread safe. It must be locked externally. */ -class Membership -{ -public: - enum AddCredentialResult - { - ADD_REJECTED, - ADD_ACCEPTED_NEW, - ADD_ACCEPTED_REDUNDANT, - ADD_DEFERRED_FOR_WHOIS - }; +class Membership { + public: + enum AddCredentialResult { ADD_REJECTED, ADD_ACCEPTED_NEW, ADD_ACCEPTED_REDUNDANT, ADD_DEFERRED_FOR_WHOIS }; - Membership(); + Membership(); - /** - * Send COM and other credentials to this peer - * - * @param RR Runtime environment - * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call - * @param now Current time - * @param peerAddress Address of member peer (the one that this Membership describes) - * @param nconf My network config - */ - void pushCredentials(const RuntimeEnvironment *RR,void *tPtr,const int64_t now,const Address &peerAddress,const NetworkConfig &nconf); + /** + * Send COM and other credentials to this peer + * + * @param RR Runtime environment + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call + * @param now Current time + * @param peerAddress Address of member peer (the one that this Membership describes) + * @param nconf My network config + */ + void pushCredentials(const RuntimeEnvironment* RR, void* tPtr, const int64_t now, const Address& peerAddress, const NetworkConfig& nconf); - inline int64_t lastPushedCredentials() { return _lastPushedCredentials; } - inline int64_t comTimestamp() { return _com.timestamp(); } - inline int64_t comRevocationThreshold() { return _comRevocationThreshold; } + inline int64_t lastPushedCredentials() + { + return _lastPushedCredentials; + } + inline int64_t comTimestamp() + { + return _com.timestamp(); + } + inline int64_t comRevocationThreshold() + { + return _comRevocationThreshold; + } - /** - * Check whether we should push MULTICAST_LIKEs to this peer, and update last sent time if true - * - * @param now Current time - * @return True if we should update multicasts - */ - inline bool multicastLikeGate(const int64_t now) - { - if ((now - _lastUpdatedMulticast) >= ZT_MULTICAST_ANNOUNCE_PERIOD) { - _lastUpdatedMulticast = now; - return true; - } - return false; - } + /** + * Check whether we should push MULTICAST_LIKEs to this peer, and update last sent time if true + * + * @param now Current time + * @return True if we should update multicasts + */ + inline bool multicastLikeGate(const int64_t now) + { + if ((now - _lastUpdatedMulticast) >= ZT_MULTICAST_ANNOUNCE_PERIOD) { + _lastUpdatedMulticast = now; + return true; + } + return false; + } - /** - * Check whether the peer represented by this Membership should be allowed on this network at all - * - * @param nconf Our network config - * @param otherNodeIdentity Identity of remote node - * @return True if this peer is allowed on this network at all - */ - inline bool isAllowedOnNetwork(const NetworkConfig &thisNodeNetworkConfig, const Identity &otherNodeIdentity) const - { - return thisNodeNetworkConfig.isPublic() || (((_com.timestamp() > _comRevocationThreshold) && (thisNodeNetworkConfig.com.agreesWith(_com, otherNodeIdentity)))); - } + /** + * Check whether the peer represented by this Membership should be allowed on this network at all + * + * @param nconf Our network config + * @param otherNodeIdentity Identity of remote node + * @return True if this peer is allowed on this network at all + */ + inline bool isAllowedOnNetwork(const NetworkConfig& thisNodeNetworkConfig, const Identity& otherNodeIdentity) const + { + return thisNodeNetworkConfig.isPublic() || (((_com.timestamp() > _comRevocationThreshold) && (thisNodeNetworkConfig.com.agreesWith(_com, otherNodeIdentity)))); + } - inline bool recentlyAssociated(const int64_t now) const - { - return ((_com)&&((now - _com.timestamp()) < ZT_PEER_ACTIVITY_TIMEOUT)); - } + inline bool recentlyAssociated(const int64_t now) const + { + return ((_com) && ((now - _com.timestamp()) < ZT_PEER_ACTIVITY_TIMEOUT)); + } - /** - * Check whether the peer represented by this Membership owns a given resource - * - * @tparam Type of resource: InetAddress or MAC - * @param nconf Our network config - * @param r Resource to check - * @return True if this peer has a certificate of ownership for the given resource - */ - template - inline bool hasCertificateOfOwnershipFor(const NetworkConfig &nconf,const T &r) const - { - uint32_t *k = (uint32_t *)0; - CertificateOfOwnership *v = (CertificateOfOwnership *)0; - Hashtable< uint32_t,CertificateOfOwnership >::Iterator i(*(const_cast< Hashtable< uint32_t,CertificateOfOwnership> *>(&_remoteCoos))); - while (i.next(k,v)) { - if (_isCredentialTimestampValid(nconf,*v)&&(v->owns(r))) { - return true; - } - } - return _isV6NDPEmulated(nconf,r); - } + /** + * Check whether the peer represented by this Membership owns a given resource + * + * @tparam Type of resource: InetAddress or MAC + * @param nconf Our network config + * @param r Resource to check + * @return True if this peer has a certificate of ownership for the given resource + */ + template inline bool hasCertificateOfOwnershipFor(const NetworkConfig& nconf, const T& r) const + { + uint32_t* k = (uint32_t*)0; + CertificateOfOwnership* v = (CertificateOfOwnership*)0; + Hashtable::Iterator i(*(const_cast*>(&_remoteCoos))); + while (i.next(k, v)) { + if (_isCredentialTimestampValid(nconf, *v) && (v->owns(r))) { + return true; + } + } + return _isV6NDPEmulated(nconf, r); + } - /** - * Get a remote member's tag (if we have it) - * - * @param nconf Network configuration - * @param id Tag ID - * @return Pointer to tag or NULL if not found - */ - inline const Tag *getTag(const NetworkConfig &nconf,const uint32_t id) const - { - const Tag *const t = _remoteTags.get(id); - return (((t)&&(_isCredentialTimestampValid(nconf,*t))) ? t : (Tag *)0); - } + /** + * Get a remote member's tag (if we have it) + * + * @param nconf Network configuration + * @param id Tag ID + * @return Pointer to tag or NULL if not found + */ + inline const Tag* getTag(const NetworkConfig& nconf, const uint32_t id) const + { + const Tag* const t = _remoteTags.get(id); + return (((t) && (_isCredentialTimestampValid(nconf, *t))) ? t : (Tag*)0); + } - /** - * Validate and add a credential if signature is okay and it's otherwise good - */ - AddCredentialResult addCredential(const RuntimeEnvironment *RR,void *tPtr,const NetworkConfig &nconf,const CertificateOfMembership &com); + /** + * Validate and add a credential if signature is okay and it's otherwise good + */ + AddCredentialResult addCredential(const RuntimeEnvironment* RR, void* tPtr, const NetworkConfig& nconf, const CertificateOfMembership& com); - /** - * Validate and add a credential if signature is okay and it's otherwise good - */ - AddCredentialResult addCredential(const RuntimeEnvironment *RR,void *tPtr,const NetworkConfig &nconf,const Tag &tag); + /** + * Validate and add a credential if signature is okay and it's otherwise good + */ + AddCredentialResult addCredential(const RuntimeEnvironment* RR, void* tPtr, const NetworkConfig& nconf, const Tag& tag); - /** - * Validate and add a credential if signature is okay and it's otherwise good - */ - AddCredentialResult addCredential(const RuntimeEnvironment *RR,void *tPtr,const NetworkConfig &nconf,const Capability &cap); + /** + * Validate and add a credential if signature is okay and it's otherwise good + */ + AddCredentialResult addCredential(const RuntimeEnvironment* RR, void* tPtr, const NetworkConfig& nconf, const Capability& cap); - /** - * Validate and add a credential if signature is okay and it's otherwise good - */ - AddCredentialResult addCredential(const RuntimeEnvironment *RR,void *tPtr,const NetworkConfig &nconf,const CertificateOfOwnership &coo); + /** + * Validate and add a credential if signature is okay and it's otherwise good + */ + AddCredentialResult addCredential(const RuntimeEnvironment* RR, void* tPtr, const NetworkConfig& nconf, const CertificateOfOwnership& coo); - /** - * Validate and add a credential if signature is okay and it's otherwise good - */ - AddCredentialResult addCredential(const RuntimeEnvironment *RR,void *tPtr,const NetworkConfig &nconf,const Revocation &rev); + /** + * Validate and add a credential if signature is okay and it's otherwise good + */ + AddCredentialResult addCredential(const RuntimeEnvironment* RR, void* tPtr, const NetworkConfig& nconf, const Revocation& rev); - /** - * Clean internal databases of stale entries - * - * @param now Current time - * @param nconf Current network configuration - */ - void clean(const int64_t now,const NetworkConfig &nconf); + /** + * Clean internal databases of stale entries + * + * @param now Current time + * @param nconf Current network configuration + */ + void clean(const int64_t now, const NetworkConfig& nconf); - /** - * Generates a key for the internal use in indexing credentials by type and credential ID - */ - static uint64_t credentialKey(const Credential::Type &t,const uint32_t i) { return (((uint64_t)t << 32) | (uint64_t)i); } + /** + * Generates a key for the internal use in indexing credentials by type and credential ID + */ + static uint64_t credentialKey(const Credential::Type& t, const uint32_t i) + { + return (((uint64_t)t << 32) | (uint64_t)i); + } -private: - inline bool _isV6NDPEmulated(const NetworkConfig &nconf,const MAC &m) const { return false; } - inline bool _isV6NDPEmulated(const NetworkConfig &nconf,const InetAddress &ip) const - { - if ((ip.isV6())&&(nconf.ndpEmulation())) { - const InetAddress sixpl(InetAddress::makeIpv66plane(nconf.networkId,nconf.issuedTo.toInt())); - for(unsigned int i=0;isin6_addr.s6_addr)[j] != (((const struct sockaddr_in6 *)&sixpl)->sin6_addr.s6_addr)[j]) { - prefixMatches = false; - break; - } - } - if (prefixMatches) { - return true; - } - break; - } - } + private: + inline bool _isV6NDPEmulated(const NetworkConfig& nconf, const MAC& m) const + { + return false; + } + inline bool _isV6NDPEmulated(const NetworkConfig& nconf, const InetAddress& ip) const + { + if ((ip.isV6()) && (nconf.ndpEmulation())) { + const InetAddress sixpl(InetAddress::makeIpv66plane(nconf.networkId, nconf.issuedTo.toInt())); + for (unsigned int i = 0; i < nconf.staticIpCount; ++i) { + if (nconf.staticIps[i].ipsEqual(sixpl)) { + bool prefixMatches = true; + for (unsigned int j = 0; j < 5; ++j) { // check for match on /40 + if ((((const struct sockaddr_in6*)&ip)->sin6_addr.s6_addr)[j] != (((const struct sockaddr_in6*)&sixpl)->sin6_addr.s6_addr)[j]) { + prefixMatches = false; + break; + } + } + if (prefixMatches) { + return true; + } + break; + } + } - const InetAddress rfc4193(InetAddress::makeIpv6rfc4193(nconf.networkId,nconf.issuedTo.toInt())); - for(unsigned int i=0;isin6_addr.s6_addr)[j] != (((const struct sockaddr_in6 *)&rfc4193)->sin6_addr.s6_addr)[j]) { - prefixMatches = false; - break; - } - } - if (prefixMatches) { - return true; - } - break; - } - } - } - return false; - } + const InetAddress rfc4193(InetAddress::makeIpv6rfc4193(nconf.networkId, nconf.issuedTo.toInt())); + for (unsigned int i = 0; i < nconf.staticIpCount; ++i) { + if (nconf.staticIps[i].ipsEqual(rfc4193)) { + bool prefixMatches = true; + for (unsigned int j = 0; j < 11; ++j) { // check for match on /88 + if ((((const struct sockaddr_in6*)&ip)->sin6_addr.s6_addr)[j] != (((const struct sockaddr_in6*)&rfc4193)->sin6_addr.s6_addr)[j]) { + prefixMatches = false; + break; + } + } + if (prefixMatches) { + return true; + } + break; + } + } + } + return false; + } - template - inline bool _isCredentialTimestampValid(const NetworkConfig &nconf,const C &remoteCredential) const - { - const int64_t ts = remoteCredential.timestamp(); - if (((ts >= nconf.timestamp) ? (ts - nconf.timestamp) : (nconf.timestamp - ts)) <= nconf.credentialTimeMaxDelta) { - const int64_t *threshold = _revocations.get(credentialKey(C::credentialType(),remoteCredential.id())); - return ((!threshold)||(ts > *threshold)); - } - return false; - } + template inline bool _isCredentialTimestampValid(const NetworkConfig& nconf, const C& remoteCredential) const + { + const int64_t ts = remoteCredential.timestamp(); + if (((ts >= nconf.timestamp) ? (ts - nconf.timestamp) : (nconf.timestamp - ts)) <= nconf.credentialTimeMaxDelta) { + const int64_t* threshold = _revocations.get(credentialKey(C::credentialType(), remoteCredential.id())); + return ((! threshold) || (ts > *threshold)); + } + return false; + } - template - inline void _cleanCredImpl(const NetworkConfig &nconf,Hashtable &remoteCreds) - { - uint32_t *k = (uint32_t *)0; - C *v = (C *)0; - typename Hashtable::Iterator i(remoteCreds); - while (i.next(k,v)) { - if (!_isCredentialTimestampValid(nconf,*v)) { - remoteCreds.erase(*k); - } - } - } + template inline void _cleanCredImpl(const NetworkConfig& nconf, Hashtable& remoteCreds) + { + uint32_t* k = (uint32_t*)0; + C* v = (C*)0; + typename Hashtable::Iterator i(remoteCreds); + while (i.next(k, v)) { + if (! _isCredentialTimestampValid(nconf, *v)) { + remoteCreds.erase(*k); + } + } + } - // Last time we pushed MULTICAST_LIKE(s) - int64_t _lastUpdatedMulticast; + // Last time we pushed MULTICAST_LIKE(s) + int64_t _lastUpdatedMulticast; - // Revocation threshold for COM or 0 if none - int64_t _comRevocationThreshold; + // Revocation threshold for COM or 0 if none + int64_t _comRevocationThreshold; - // Time we last pushed credentials - int64_t _lastPushedCredentials; + // Time we last pushed credentials + int64_t _lastPushedCredentials; - // Remote member's latest network COM - CertificateOfMembership _com; + // Remote member's latest network COM + CertificateOfMembership _com; - // Revocations by credentialKey() - Hashtable< uint64_t,int64_t > _revocations; + // Revocations by credentialKey() + Hashtable _revocations; - // Remote credentials that we have received from this member (and that are valid) - Hashtable< uint32_t,Tag > _remoteTags; - Hashtable< uint32_t,Capability > _remoteCaps; - Hashtable< uint32_t,CertificateOfOwnership > _remoteCoos; + // Remote credentials that we have received from this member (and that are valid) + Hashtable _remoteTags; + Hashtable _remoteCaps; + Hashtable _remoteCoos; -public: - class CapabilityIterator - { - public: - CapabilityIterator(Membership &m,const NetworkConfig &nconf) : - _hti(m._remoteCaps), - _k((uint32_t *)0), - _c((Capability *)0), - _m(m), - _nconf(nconf) - { - } + public: + class CapabilityIterator { + public: + CapabilityIterator(Membership& m, const NetworkConfig& nconf) : _hti(m._remoteCaps), _k((uint32_t*)0), _c((Capability*)0), _m(m), _nconf(nconf) + { + } - inline Capability *next() - { - while (_hti.next(_k,_c)) { - if (_m._isCredentialTimestampValid(_nconf,*_c)) { - return _c; - } - } - return (Capability *)0; - } + inline Capability* next() + { + while (_hti.next(_k, _c)) { + if (_m._isCredentialTimestampValid(_nconf, *_c)) { + return _c; + } + } + return (Capability*)0; + } - private: - Hashtable< uint32_t,Capability >::Iterator _hti; - uint32_t *_k; - Capability *_c; - Membership &_m; - const NetworkConfig &_nconf; - }; + private: + Hashtable::Iterator _hti; + uint32_t* _k; + Capability* _c; + Membership& _m; + const NetworkConfig& _nconf; + }; }; -} // namespace ZeroTier +} // namespace ZeroTier #endif diff --git a/node/Metrics.cpp b/node/Metrics.cpp index b41120bb..45353fde 100644 --- a/node/Metrics.cpp +++ b/node/Metrics.cpp @@ -10,263 +10,154 @@ * of this software will be governed by version 2.0 of the Apache License. */ -#include -#include +#include "Metrics.hpp" namespace prometheus { - namespace simpleapi { - std::shared_ptr registry_ptr = std::make_shared(); - Registry& registry = *registry_ptr; - SaveToFile saver; - } -} +namespace simpleapi { +std::shared_ptr registry_ptr = std::make_shared(); +Registry& registry = *registry_ptr; +SaveToFile saver; +} // namespace simpleapi +} // namespace prometheus namespace ZeroTier { - namespace Metrics { - // Packet Type Counts - prometheus::simpleapi::counter_family_t packets - { "zt_packet", "ZeroTier packet type counts"}; +namespace Metrics { +// Packet Type Counts +prometheus::simpleapi::counter_family_t packets { "zt_packet", "ZeroTier packet type counts" }; - // Incoming packets - prometheus::simpleapi::counter_metric_t pkt_nop_in - { packets.Add({{"packet_type", "nop"}, {"direction", "rx"}}) }; - prometheus::simpleapi::counter_metric_t pkt_error_in - { packets.Add({{"packet_type", "error"}, {"direction", "rx"}}) }; - prometheus::simpleapi::counter_metric_t pkt_ack_in - { packets.Add({{"packet_type", "ack"}, {"direction", "rx"}}) }; - prometheus::simpleapi::counter_metric_t pkt_qos_in - { packets.Add({{"packet_type", "qos"}, {"direction", "rx"}}) }; - prometheus::simpleapi::counter_metric_t pkt_hello_in - { packets.Add({{"packet_type", "hello"}, {"direction", "rx"}}) }; - prometheus::simpleapi::counter_metric_t pkt_ok_in - { packets.Add({{"packet_type", "ok"}, {"direction", "rx"}}) }; - prometheus::simpleapi::counter_metric_t pkt_whois_in - { packets.Add({{"packet_type", "whois"}, {"direction", "rx"}}) }; - prometheus::simpleapi::counter_metric_t pkt_rendezvous_in - { packets.Add({{"packet_type", "rendezvous"}, {"direction", "rx"}}) }; - prometheus::simpleapi::counter_metric_t pkt_frame_in - { packets.Add({{"packet_type", "frame"}, {"direction", "rx"}}) }; - prometheus::simpleapi::counter_metric_t pkt_ext_frame_in - { packets.Add({{"packet_type", "ext_frame"}, {"direction", "rx"}}) }; - prometheus::simpleapi::counter_metric_t pkt_echo_in - { packets.Add({{"packet_type", "echo"}, {"direction", "rx"}}) }; - prometheus::simpleapi::counter_metric_t pkt_multicast_like_in - { packets.Add({{"packet_type", "multicast_like"}, {"direction", "rx"}}) }; - prometheus::simpleapi::counter_metric_t pkt_network_credentials_in - { packets.Add({{"packet_type", "network_credentials"}, {"direction", "rx"}}) }; - prometheus::simpleapi::counter_metric_t pkt_network_config_request_in - { packets.Add({{"packet_type", "network_config_request"}, {"direction", "rx"}}) }; - prometheus::simpleapi::counter_metric_t pkt_network_config_in - { packets.Add({{"packet_type", "network_config"}, {"direction", "rx"}}) }; - prometheus::simpleapi::counter_metric_t pkt_multicast_gather_in - { packets.Add({{"packet_type", "multicast_gather"}, {"direction", "rx"}}) }; - prometheus::simpleapi::counter_metric_t pkt_multicast_frame_in - { packets.Add({{"packet_type", "multicast_frame"}, {"direction", "rx"}}) }; - prometheus::simpleapi::counter_metric_t pkt_push_direct_paths_in - { packets.Add({{"packet_type", "push_direct_paths"}, {"direction", "rx"}}) }; - prometheus::simpleapi::counter_metric_t pkt_user_message_in - { packets.Add({{"packet_type", "user_message"}, {"direction", "rx"}}) }; - prometheus::simpleapi::counter_metric_t pkt_remote_trace_in - { packets.Add({{"packet_type", "remote_trace"}, {"direction", "rx"}}) }; - prometheus::simpleapi::counter_metric_t pkt_path_negotiation_request_in - { packets.Add({{"packet_type", "path_negotiation_request"}, {"direction", "rx"}}) }; +// Incoming packets +prometheus::simpleapi::counter_metric_t pkt_nop_in { packets.Add({ { "packet_type", "nop" }, { "direction", "rx" } }) }; +prometheus::simpleapi::counter_metric_t pkt_error_in { packets.Add({ { "packet_type", "error" }, { "direction", "rx" } }) }; +prometheus::simpleapi::counter_metric_t pkt_ack_in { packets.Add({ { "packet_type", "ack" }, { "direction", "rx" } }) }; +prometheus::simpleapi::counter_metric_t pkt_qos_in { packets.Add({ { "packet_type", "qos" }, { "direction", "rx" } }) }; +prometheus::simpleapi::counter_metric_t pkt_hello_in { packets.Add({ { "packet_type", "hello" }, { "direction", "rx" } }) }; +prometheus::simpleapi::counter_metric_t pkt_ok_in { packets.Add({ { "packet_type", "ok" }, { "direction", "rx" } }) }; +prometheus::simpleapi::counter_metric_t pkt_whois_in { packets.Add({ { "packet_type", "whois" }, { "direction", "rx" } }) }; +prometheus::simpleapi::counter_metric_t pkt_rendezvous_in { packets.Add({ { "packet_type", "rendezvous" }, { "direction", "rx" } }) }; +prometheus::simpleapi::counter_metric_t pkt_frame_in { packets.Add({ { "packet_type", "frame" }, { "direction", "rx" } }) }; +prometheus::simpleapi::counter_metric_t pkt_ext_frame_in { packets.Add({ { "packet_type", "ext_frame" }, { "direction", "rx" } }) }; +prometheus::simpleapi::counter_metric_t pkt_echo_in { packets.Add({ { "packet_type", "echo" }, { "direction", "rx" } }) }; +prometheus::simpleapi::counter_metric_t pkt_multicast_like_in { packets.Add({ { "packet_type", "multicast_like" }, { "direction", "rx" } }) }; +prometheus::simpleapi::counter_metric_t pkt_network_credentials_in { packets.Add({ { "packet_type", "network_credentials" }, { "direction", "rx" } }) }; +prometheus::simpleapi::counter_metric_t pkt_network_config_request_in { packets.Add({ { "packet_type", "network_config_request" }, { "direction", "rx" } }) }; +prometheus::simpleapi::counter_metric_t pkt_network_config_in { packets.Add({ { "packet_type", "network_config" }, { "direction", "rx" } }) }; +prometheus::simpleapi::counter_metric_t pkt_multicast_gather_in { packets.Add({ { "packet_type", "multicast_gather" }, { "direction", "rx" } }) }; +prometheus::simpleapi::counter_metric_t pkt_multicast_frame_in { packets.Add({ { "packet_type", "multicast_frame" }, { "direction", "rx" } }) }; +prometheus::simpleapi::counter_metric_t pkt_push_direct_paths_in { packets.Add({ { "packet_type", "push_direct_paths" }, { "direction", "rx" } }) }; +prometheus::simpleapi::counter_metric_t pkt_user_message_in { packets.Add({ { "packet_type", "user_message" }, { "direction", "rx" } }) }; +prometheus::simpleapi::counter_metric_t pkt_remote_trace_in { packets.Add({ { "packet_type", "remote_trace" }, { "direction", "rx" } }) }; +prometheus::simpleapi::counter_metric_t pkt_path_negotiation_request_in { packets.Add({ { "packet_type", "path_negotiation_request" }, { "direction", "rx" } }) }; - // Outgoing packets - prometheus::simpleapi::counter_metric_t pkt_nop_out - { packets.Add({{"packet_type", "nop"}, {"direction", "tx"}}) }; - prometheus::simpleapi::counter_metric_t pkt_error_out - { packets.Add({{"packet_type", "error"}, {"direction", "tx"}}) }; - prometheus::simpleapi::counter_metric_t pkt_ack_out - { packets.Add({{"packet_type", "ack"}, {"direction", "tx"}}) }; - prometheus::simpleapi::counter_metric_t pkt_qos_out - { packets.Add({{"packet_type", "qos"}, {"direction", "tx"}}) }; - prometheus::simpleapi::counter_metric_t pkt_hello_out - { packets.Add({{"packet_type", "hello"}, {"direction", "tx"}}) }; - prometheus::simpleapi::counter_metric_t pkt_ok_out - { packets.Add({{"packet_type", "ok"}, {"direction", "tx"}}) }; - prometheus::simpleapi::counter_metric_t pkt_whois_out - { packets.Add({{"packet_type", "whois"}, {"direction", "tx"}}) }; - prometheus::simpleapi::counter_metric_t pkt_rendezvous_out - { packets.Add({{"packet_type", "rendezvous"}, {"direction", "tx"}}) }; - prometheus::simpleapi::counter_metric_t pkt_frame_out - { packets.Add({{"packet_type", "frame"}, {"direction", "tx"}}) }; - prometheus::simpleapi::counter_metric_t pkt_ext_frame_out - { packets.Add({{"packet_type", "ext_frame"}, {"direction", "tx"}}) }; - prometheus::simpleapi::counter_metric_t pkt_echo_out - { packets.Add({{"packet_type", "echo"}, {"direction", "tx"}}) }; - prometheus::simpleapi::counter_metric_t pkt_multicast_like_out - { packets.Add({{"packet_type", "multicast_like"}, {"direction", "tx"}}) }; - prometheus::simpleapi::counter_metric_t pkt_network_credentials_out - { packets.Add({{"packet_type", "network_credentials"}, {"direction", "tx"}}) }; - prometheus::simpleapi::counter_metric_t pkt_network_config_request_out - { packets.Add({{"packet_type", "network_config_request"}, {"direction", "tx"}}) }; - prometheus::simpleapi::counter_metric_t pkt_network_config_out - { packets.Add({{"packet_type", "network_config"}, {"direction", "tx"}}) }; - prometheus::simpleapi::counter_metric_t pkt_multicast_gather_out - { packets.Add({{"packet_type", "multicast_gather"}, {"direction", "tx"}}) }; - prometheus::simpleapi::counter_metric_t pkt_multicast_frame_out - { packets.Add({{"packet_type", "multicast_frame"}, {"direction", "tx"}}) }; - prometheus::simpleapi::counter_metric_t pkt_push_direct_paths_out - { packets.Add({{"packet_type", "push_direct_paths"}, {"direction", "tx"}}) }; - prometheus::simpleapi::counter_metric_t pkt_user_message_out - { packets.Add({{"packet_type", "user_message"}, {"direction", "tx"}}) }; - prometheus::simpleapi::counter_metric_t pkt_remote_trace_out - { packets.Add({{"packet_type", "remote_trace"}, {"direction", "tx"}}) }; - prometheus::simpleapi::counter_metric_t pkt_path_negotiation_request_out - { packets.Add({{"packet_type", "path_negotiation_request"}, {"direction", "tx"}}) }; +// Outgoing packets +prometheus::simpleapi::counter_metric_t pkt_nop_out { packets.Add({ { "packet_type", "nop" }, { "direction", "tx" } }) }; +prometheus::simpleapi::counter_metric_t pkt_error_out { packets.Add({ { "packet_type", "error" }, { "direction", "tx" } }) }; +prometheus::simpleapi::counter_metric_t pkt_ack_out { packets.Add({ { "packet_type", "ack" }, { "direction", "tx" } }) }; +prometheus::simpleapi::counter_metric_t pkt_qos_out { packets.Add({ { "packet_type", "qos" }, { "direction", "tx" } }) }; +prometheus::simpleapi::counter_metric_t pkt_hello_out { packets.Add({ { "packet_type", "hello" }, { "direction", "tx" } }) }; +prometheus::simpleapi::counter_metric_t pkt_ok_out { packets.Add({ { "packet_type", "ok" }, { "direction", "tx" } }) }; +prometheus::simpleapi::counter_metric_t pkt_whois_out { packets.Add({ { "packet_type", "whois" }, { "direction", "tx" } }) }; +prometheus::simpleapi::counter_metric_t pkt_rendezvous_out { packets.Add({ { "packet_type", "rendezvous" }, { "direction", "tx" } }) }; +prometheus::simpleapi::counter_metric_t pkt_frame_out { packets.Add({ { "packet_type", "frame" }, { "direction", "tx" } }) }; +prometheus::simpleapi::counter_metric_t pkt_ext_frame_out { packets.Add({ { "packet_type", "ext_frame" }, { "direction", "tx" } }) }; +prometheus::simpleapi::counter_metric_t pkt_echo_out { packets.Add({ { "packet_type", "echo" }, { "direction", "tx" } }) }; +prometheus::simpleapi::counter_metric_t pkt_multicast_like_out { packets.Add({ { "packet_type", "multicast_like" }, { "direction", "tx" } }) }; +prometheus::simpleapi::counter_metric_t pkt_network_credentials_out { packets.Add({ { "packet_type", "network_credentials" }, { "direction", "tx" } }) }; +prometheus::simpleapi::counter_metric_t pkt_network_config_request_out { packets.Add({ { "packet_type", "network_config_request" }, { "direction", "tx" } }) }; +prometheus::simpleapi::counter_metric_t pkt_network_config_out { packets.Add({ { "packet_type", "network_config" }, { "direction", "tx" } }) }; +prometheus::simpleapi::counter_metric_t pkt_multicast_gather_out { packets.Add({ { "packet_type", "multicast_gather" }, { "direction", "tx" } }) }; +prometheus::simpleapi::counter_metric_t pkt_multicast_frame_out { packets.Add({ { "packet_type", "multicast_frame" }, { "direction", "tx" } }) }; +prometheus::simpleapi::counter_metric_t pkt_push_direct_paths_out { packets.Add({ { "packet_type", "push_direct_paths" }, { "direction", "tx" } }) }; +prometheus::simpleapi::counter_metric_t pkt_user_message_out { packets.Add({ { "packet_type", "user_message" }, { "direction", "tx" } }) }; +prometheus::simpleapi::counter_metric_t pkt_remote_trace_out { packets.Add({ { "packet_type", "remote_trace" }, { "direction", "tx" } }) }; +prometheus::simpleapi::counter_metric_t pkt_path_negotiation_request_out { packets.Add({ { "packet_type", "path_negotiation_request" }, { "direction", "tx" } }) }; +// Packet Error Counts +prometheus::simpleapi::counter_family_t packet_errors { "zt_packet_error", "ZeroTier packet errors" }; - // Packet Error Counts - prometheus::simpleapi::counter_family_t packet_errors - { "zt_packet_error", "ZeroTier packet errors"}; +// Incoming Error Counts +prometheus::simpleapi::counter_metric_t pkt_error_obj_not_found_in { packet_errors.Add({ { "error_type", "obj_not_found" }, { "direction", "rx" } }) }; +prometheus::simpleapi::counter_metric_t pkt_error_unsupported_op_in { packet_errors.Add({ { "error_type", "unsupported_operation" }, { "direction", "rx" } }) }; +prometheus::simpleapi::counter_metric_t pkt_error_identity_collision_in { packet_errors.Add({ { "error_type", "identity_collision" }, { "direction", "rx" } }) }; +prometheus::simpleapi::counter_metric_t pkt_error_need_membership_cert_in { packet_errors.Add({ { "error_type", "need_membership_certificate" }, { "direction", "rx" } }) }; +prometheus::simpleapi::counter_metric_t pkt_error_network_access_denied_in { packet_errors.Add({ { "error_type", "network_access_denied" }, { "direction", "rx" } }) }; +prometheus::simpleapi::counter_metric_t pkt_error_unwanted_multicast_in { packet_errors.Add({ { "error_type", "unwanted_multicast" }, { "direction", "rx" } }) }; +prometheus::simpleapi::counter_metric_t pkt_error_authentication_required_in { packet_errors.Add({ { "error_type", "authentication_required" }, { "direction", "rx" } }) }; +prometheus::simpleapi::counter_metric_t pkt_error_internal_server_error_in { packet_errors.Add({ { "error_type", "internal_server_error" }, { "direction", "rx" } }) }; - // Incoming Error Counts - prometheus::simpleapi::counter_metric_t pkt_error_obj_not_found_in - { packet_errors.Add({{"error_type", "obj_not_found"}, {"direction", "rx"}}) }; - prometheus::simpleapi::counter_metric_t pkt_error_unsupported_op_in - { packet_errors.Add({{"error_type", "unsupported_operation"}, {"direction", "rx"}}) }; - prometheus::simpleapi::counter_metric_t pkt_error_identity_collision_in - { packet_errors.Add({{"error_type", "identity_collision"}, {"direction", "rx"}}) }; - prometheus::simpleapi::counter_metric_t pkt_error_need_membership_cert_in - { packet_errors.Add({{"error_type", "need_membership_certificate"}, {"direction", "rx"}}) }; - prometheus::simpleapi::counter_metric_t pkt_error_network_access_denied_in - { packet_errors.Add({{"error_type", "network_access_denied"}, {"direction", "rx"}}) }; - prometheus::simpleapi::counter_metric_t pkt_error_unwanted_multicast_in - { packet_errors.Add({{"error_type", "unwanted_multicast"}, {"direction", "rx"}}) }; - prometheus::simpleapi::counter_metric_t pkt_error_authentication_required_in - { packet_errors.Add({{"error_type", "authentication_required"}, {"direction", "rx"}}) }; - prometheus::simpleapi::counter_metric_t pkt_error_internal_server_error_in - { packet_errors.Add({{"error_type", "internal_server_error"}, {"direction", "rx"}}) }; +// Outgoing Error Counts +prometheus::simpleapi::counter_metric_t pkt_error_obj_not_found_out { packet_errors.Add({ { "error_type", "obj_not_found" }, { "direction", "tx" } }) }; +prometheus::simpleapi::counter_metric_t pkt_error_unsupported_op_out { packet_errors.Add({ { "error_type", "unsupported_operation" }, { "direction", "tx" } }) }; +prometheus::simpleapi::counter_metric_t pkt_error_identity_collision_out { packet_errors.Add({ { "error_type", "identity_collision" }, { "direction", "tx" } }) }; +prometheus::simpleapi::counter_metric_t pkt_error_need_membership_cert_out { packet_errors.Add({ { "error_type", "need_membership_certificate" }, { "direction", "tx" } }) }; +prometheus::simpleapi::counter_metric_t pkt_error_network_access_denied_out { packet_errors.Add({ { "error_type", "network_access_denied" }, { "direction", "tx" } }) }; +prometheus::simpleapi::counter_metric_t pkt_error_unwanted_multicast_out { packet_errors.Add({ { "error_type", "unwanted_multicast" }, { "direction", "tx" } }) }; +prometheus::simpleapi::counter_metric_t pkt_error_authentication_required_out { packet_errors.Add({ { "error_type", "authentication_required" }, { "direction", "tx" } }) }; +prometheus::simpleapi::counter_metric_t pkt_error_internal_server_error_out { packet_errors.Add({ { "error_type", "internal_server_error" }, { "direction", "tx" } }) }; - // Outgoing Error Counts - prometheus::simpleapi::counter_metric_t pkt_error_obj_not_found_out - { packet_errors.Add({{"error_type", "obj_not_found"}, {"direction", "tx"}}) }; - prometheus::simpleapi::counter_metric_t pkt_error_unsupported_op_out - { packet_errors.Add({{"error_type", "unsupported_operation"}, {"direction", "tx"}}) }; - prometheus::simpleapi::counter_metric_t pkt_error_identity_collision_out - { packet_errors.Add({{"error_type", "identity_collision"}, {"direction", "tx"}}) }; - prometheus::simpleapi::counter_metric_t pkt_error_need_membership_cert_out - { packet_errors.Add({{"error_type", "need_membership_certificate"}, {"direction", "tx"}}) }; - prometheus::simpleapi::counter_metric_t pkt_error_network_access_denied_out - { packet_errors.Add({{"error_type", "network_access_denied"}, {"direction", "tx"}}) }; - prometheus::simpleapi::counter_metric_t pkt_error_unwanted_multicast_out - { packet_errors.Add({{"error_type", "unwanted_multicast"}, {"direction", "tx"}}) }; - prometheus::simpleapi::counter_metric_t pkt_error_authentication_required_out - { packet_errors.Add({{"error_type", "authentication_required"}, {"direction", "tx"}}) }; - prometheus::simpleapi::counter_metric_t pkt_error_internal_server_error_out - { packet_errors.Add({{"error_type", "internal_server_error"}, {"direction", "tx"}}) }; +// Data Sent/Received Metrics +prometheus::simpleapi::counter_family_t data { "zt_data", "number of bytes ZeroTier has transmitted or received" }; +prometheus::simpleapi::counter_metric_t udp_recv { data.Add({ { "protocol", "udp" }, { "direction", "rx" } }) }; +prometheus::simpleapi::counter_metric_t udp_send { data.Add({ { "protocol", "udp" }, { "direction", "tx" } }) }; +prometheus::simpleapi::counter_metric_t tcp_send { data.Add({ { "protocol", "tcp" }, { "direction", "tx" } }) }; +prometheus::simpleapi::counter_metric_t tcp_recv { data.Add({ { "protocol", "tcp" }, { "direction", "rx" } }) }; - // Data Sent/Received Metrics - prometheus::simpleapi::counter_family_t data - { "zt_data", "number of bytes ZeroTier has transmitted or received" }; - prometheus::simpleapi::counter_metric_t udp_recv - { data.Add({{"protocol","udp"},{"direction","rx"}}) }; - prometheus::simpleapi::counter_metric_t udp_send - { data.Add({{"protocol","udp"},{"direction","tx"}}) }; - prometheus::simpleapi::counter_metric_t tcp_send - { data.Add({{"protocol","tcp"},{"direction", "tx"}}) }; - prometheus::simpleapi::counter_metric_t tcp_recv - { data.Add({{"protocol","tcp"},{"direction", "rx"}}) }; +// Network Metrics +prometheus::simpleapi::gauge_metric_t network_num_joined { "zt_num_networks", "number of networks this instance is joined to" }; +prometheus::simpleapi::gauge_family_t network_num_multicast_groups { "zt_network_multicast_groups_subscribed", "number of multicast groups networks are subscribed to" }; +prometheus::simpleapi::counter_family_t network_packets { "zt_network_packets", "number of incoming/outgoing packets per network" }; - // Network Metrics - prometheus::simpleapi::gauge_metric_t network_num_joined - { "zt_num_networks", "number of networks this instance is joined to" }; - prometheus::simpleapi::gauge_family_t network_num_multicast_groups - { "zt_network_multicast_groups_subscribed", "number of multicast groups networks are subscribed to" }; - prometheus::simpleapi::counter_family_t network_packets - { "zt_network_packets", "number of incoming/outgoing packets per network" }; - #ifndef ZT_NO_PEER_METRICS - // PeerMetrics - prometheus::CustomFamily> &peer_latency = - prometheus::Builder>() - .Name("zt_peer_latency") - .Help("peer latency (ms)") - .Register(prometheus::simpleapi::registry); - - prometheus::simpleapi::gauge_family_t peer_path_count - { "zt_peer_path_count", "number of paths to peer" }; - prometheus::simpleapi::counter_family_t peer_packets - { "zt_peer_packets", "number of packets to/from a peer" }; - prometheus::simpleapi::counter_family_t peer_packet_errors - { "zt_peer_packet_errors" , "number of incoming packet errors from a peer" }; +// PeerMetrics +prometheus::CustomFamily >& peer_latency = prometheus::Builder >().Name("zt_peer_latency").Help("peer latency (ms)").Register(prometheus::simpleapi::registry); + +prometheus::simpleapi::gauge_family_t peer_path_count { "zt_peer_path_count", "number of paths to peer" }; +prometheus::simpleapi::counter_family_t peer_packets { "zt_peer_packets", "number of packets to/from a peer" }; +prometheus::simpleapi::counter_family_t peer_packet_errors { "zt_peer_packet_errors", "number of incoming packet errors from a peer" }; #endif - // General Controller Metrics - prometheus::simpleapi::gauge_metric_t network_count - {"controller_network_count", "number of networks the controller is serving"}; - prometheus::simpleapi::gauge_metric_t member_count - {"controller_member_count", "number of network members the controller is serving"}; - prometheus::simpleapi::counter_metric_t network_changes - {"controller_network_change_count", "number of times a network configuration is changed"}; - prometheus::simpleapi::counter_metric_t member_changes - {"controller_member_change_count", "number of times a network member configuration is changed"}; - prometheus::simpleapi::counter_metric_t member_auths - {"controller_member_auth_count", "number of network member auths"}; - prometheus::simpleapi::counter_metric_t member_deauths - {"controller_member_deauth_count", "number of network member deauths"}; +// General Controller Metrics +prometheus::simpleapi::gauge_metric_t network_count { "controller_network_count", "number of networks the controller is serving" }; +prometheus::simpleapi::gauge_metric_t member_count { "controller_member_count", "number of network members the controller is serving" }; +prometheus::simpleapi::counter_metric_t network_changes { "controller_network_change_count", "number of times a network configuration is changed" }; +prometheus::simpleapi::counter_metric_t member_changes { "controller_member_change_count", "number of times a network member configuration is changed" }; +prometheus::simpleapi::counter_metric_t member_auths { "controller_member_auth_count", "number of network member auths" }; +prometheus::simpleapi::counter_metric_t member_deauths { "controller_member_deauth_count", "number of network member deauths" }; - prometheus::simpleapi::gauge_metric_t network_config_request_queue_size - { "controller_network_config_request_queue", "number of entries in the request queue for network configurations" }; - - prometheus::simpleapi::counter_metric_t sso_expiration_checks - { "controller_sso_expiration_checks", "number of sso expiration checks done" }; +prometheus::simpleapi::gauge_metric_t network_config_request_queue_size { "controller_network_config_request_queue", "number of entries in the request queue for network configurations" }; - prometheus::simpleapi::counter_metric_t sso_member_deauth - { "controller_sso_timeouts", "number of sso timeouts" }; +prometheus::simpleapi::counter_metric_t sso_expiration_checks { "controller_sso_expiration_checks", "number of sso expiration checks done" }; - prometheus::simpleapi::counter_metric_t network_config_request - { "controller_network_config_request", "count of config requests handled" }; - prometheus::simpleapi::gauge_metric_t network_config_request_threads - { "controller_network_config_request_threads", "number of active network config handling threads" }; - prometheus::simpleapi::counter_metric_t db_get_network - { "controller_db_get_network", "counter" }; - prometheus::simpleapi::counter_metric_t db_get_network_and_member - { "controller_db_get_network_and_member", "counter" }; - prometheus::simpleapi::counter_metric_t db_get_network_and_member_and_summary - { "controller_db_get_networK_and_member_summary", "counter" }; - prometheus::simpleapi::counter_metric_t db_get_member_list - { "controller_db_get_member_list", "counter" }; - prometheus::simpleapi::counter_metric_t db_get_network_list - { "controller_db_get_network_list", "counter" }; - prometheus::simpleapi::counter_metric_t db_member_change - { "controller_db_member_change", "counter" }; - prometheus::simpleapi::counter_metric_t db_network_change - { "controller_db_network_change", "counter" }; +prometheus::simpleapi::counter_metric_t sso_member_deauth { "controller_sso_timeouts", "number of sso timeouts" }; + +prometheus::simpleapi::counter_metric_t network_config_request { "controller_network_config_request", "count of config requests handled" }; +prometheus::simpleapi::gauge_metric_t network_config_request_threads { "controller_network_config_request_threads", "number of active network config handling threads" }; +prometheus::simpleapi::counter_metric_t db_get_network { "controller_db_get_network", "counter" }; +prometheus::simpleapi::counter_metric_t db_get_network_and_member { "controller_db_get_network_and_member", "counter" }; +prometheus::simpleapi::counter_metric_t db_get_network_and_member_and_summary { "controller_db_get_networK_and_member_summary", "counter" }; +prometheus::simpleapi::counter_metric_t db_get_member_list { "controller_db_get_member_list", "counter" }; +prometheus::simpleapi::counter_metric_t db_get_network_list { "controller_db_get_network_list", "counter" }; +prometheus::simpleapi::counter_metric_t db_member_change { "controller_db_member_change", "counter" }; +prometheus::simpleapi::counter_metric_t db_network_change { "controller_db_network_change", "counter" }; #ifdef ZT_CONTROLLER_USE_LIBPQ - // Central Controller Metrics - prometheus::simpleapi::counter_metric_t pgsql_mem_notification - { "controller_pgsql_member_notifications_received", "number of member change notifications received via pgsql NOTIFY" }; - prometheus::simpleapi::counter_metric_t pgsql_net_notification - { "controller_pgsql_network_notifications_received", "number of network change notifications received via pgsql NOTIFY" }; - prometheus::simpleapi::counter_metric_t pgsql_node_checkin - { "controller_pgsql_node_checkin_count", "number of node check-ins (pgsql)" }; - prometheus::simpleapi::counter_metric_t pgsql_commit_ticks - { "controller_pgsql_commit_ticks", "number of commit ticks run (pgsql)" }; - prometheus::simpleapi::counter_metric_t db_get_sso_info - { "controller_db_get_sso_info", "counter" }; +// Central Controller Metrics +prometheus::simpleapi::counter_metric_t pgsql_mem_notification { "controller_pgsql_member_notifications_received", "number of member change notifications received via pgsql NOTIFY" }; +prometheus::simpleapi::counter_metric_t pgsql_net_notification { "controller_pgsql_network_notifications_received", "number of network change notifications received via pgsql NOTIFY" }; +prometheus::simpleapi::counter_metric_t pgsql_node_checkin { "controller_pgsql_node_checkin_count", "number of node check-ins (pgsql)" }; +prometheus::simpleapi::counter_metric_t pgsql_commit_ticks { "controller_pgsql_commit_ticks", "number of commit ticks run (pgsql)" }; +prometheus::simpleapi::counter_metric_t db_get_sso_info { "controller_db_get_sso_info", "counter" }; - prometheus::simpleapi::counter_metric_t redis_mem_notification - { "controller_redis_member_notifications_received", "number of member change notifications received via redis" }; - prometheus::simpleapi::counter_metric_t redis_net_notification - { "controller_redis_network_notifications_received", "number of network change notifications received via redis" }; - prometheus::simpleapi::counter_metric_t redis_node_checkin - { "controller_redis_node_checkin_count", "number of node check-ins (redis)" }; +prometheus::simpleapi::counter_metric_t redis_mem_notification { "controller_redis_member_notifications_received", "number of member change notifications received via redis" }; +prometheus::simpleapi::counter_metric_t redis_net_notification { "controller_redis_network_notifications_received", "number of network change notifications received via redis" }; +prometheus::simpleapi::counter_metric_t redis_node_checkin { "controller_redis_node_checkin_count", "number of node check-ins (redis)" }; - // Central DB Pool Metrics - prometheus::simpleapi::counter_metric_t conn_counter - { "controller_pgsql_connections_created", "number of pgsql connections created"}; - prometheus::simpleapi::counter_metric_t max_pool_size - { "controller_pgsql_max_conn_pool_size", "max connection pool size for postgres"}; - prometheus::simpleapi::counter_metric_t min_pool_size - { "controller_pgsql_min_conn_pool_size", "minimum connection pool size for postgres" }; - prometheus::simpleapi::gauge_metric_t pool_avail - { "controller_pgsql_available_conns", "number of available postgres connections" }; - prometheus::simpleapi::gauge_metric_t pool_in_use - { "controller_pgsql_in_use_conns", "number of postgres database connections in use" }; - prometheus::simpleapi::counter_metric_t pool_errors - { "controller_pgsql_connection_errors", "number of connection errors the connection pool has seen" }; +// Central DB Pool Metrics +prometheus::simpleapi::counter_metric_t conn_counter { "controller_pgsql_connections_created", "number of pgsql connections created" }; +prometheus::simpleapi::counter_metric_t max_pool_size { "controller_pgsql_max_conn_pool_size", "max connection pool size for postgres" }; +prometheus::simpleapi::counter_metric_t min_pool_size { "controller_pgsql_min_conn_pool_size", "minimum connection pool size for postgres" }; +prometheus::simpleapi::gauge_metric_t pool_avail { "controller_pgsql_available_conns", "number of available postgres connections" }; +prometheus::simpleapi::gauge_metric_t pool_in_use { "controller_pgsql_in_use_conns", "number of postgres database connections in use" }; +prometheus::simpleapi::counter_metric_t pool_errors { "controller_pgsql_connection_errors", "number of connection errors the connection pool has seen" }; #endif - } -} +} // namespace Metrics +} // namespace ZeroTier diff --git a/node/Metrics.hpp b/node/Metrics.hpp index 5906f18e..3f33a33e 100644 --- a/node/Metrics.hpp +++ b/node/Metrics.hpp @@ -12,155 +12,153 @@ #ifndef METRICS_H_ #define METRICS_H_ -#include +#include #include +#include namespace prometheus { - namespace simpleapi { - extern std::shared_ptr registry_ptr; - } +namespace simpleapi { +extern std::shared_ptr registry_ptr; } +} // namespace prometheus namespace ZeroTier { - namespace Metrics { - // Packet Type Counts - extern prometheus::simpleapi::counter_family_t packets; +namespace Metrics { +// Packet Type Counts +extern prometheus::simpleapi::counter_family_t packets; - // incoming packets - extern prometheus::simpleapi::counter_metric_t pkt_nop_in; - extern prometheus::simpleapi::counter_metric_t pkt_error_in; - extern prometheus::simpleapi::counter_metric_t pkt_ack_in; - extern prometheus::simpleapi::counter_metric_t pkt_qos_in; - extern prometheus::simpleapi::counter_metric_t pkt_hello_in; - extern prometheus::simpleapi::counter_metric_t pkt_ok_in; - extern prometheus::simpleapi::counter_metric_t pkt_whois_in; - extern prometheus::simpleapi::counter_metric_t pkt_rendezvous_in; - extern prometheus::simpleapi::counter_metric_t pkt_frame_in; - extern prometheus::simpleapi::counter_metric_t pkt_ext_frame_in; - extern prometheus::simpleapi::counter_metric_t pkt_echo_in; - extern prometheus::simpleapi::counter_metric_t pkt_multicast_like_in; - extern prometheus::simpleapi::counter_metric_t pkt_network_credentials_in; - extern prometheus::simpleapi::counter_metric_t pkt_network_config_request_in; - extern prometheus::simpleapi::counter_metric_t pkt_network_config_in; - extern prometheus::simpleapi::counter_metric_t pkt_multicast_gather_in; - extern prometheus::simpleapi::counter_metric_t pkt_multicast_frame_in; - extern prometheus::simpleapi::counter_metric_t pkt_push_direct_paths_in; - extern prometheus::simpleapi::counter_metric_t pkt_user_message_in; - extern prometheus::simpleapi::counter_metric_t pkt_remote_trace_in; - extern prometheus::simpleapi::counter_metric_t pkt_path_negotiation_request_in; +// incoming packets +extern prometheus::simpleapi::counter_metric_t pkt_nop_in; +extern prometheus::simpleapi::counter_metric_t pkt_error_in; +extern prometheus::simpleapi::counter_metric_t pkt_ack_in; +extern prometheus::simpleapi::counter_metric_t pkt_qos_in; +extern prometheus::simpleapi::counter_metric_t pkt_hello_in; +extern prometheus::simpleapi::counter_metric_t pkt_ok_in; +extern prometheus::simpleapi::counter_metric_t pkt_whois_in; +extern prometheus::simpleapi::counter_metric_t pkt_rendezvous_in; +extern prometheus::simpleapi::counter_metric_t pkt_frame_in; +extern prometheus::simpleapi::counter_metric_t pkt_ext_frame_in; +extern prometheus::simpleapi::counter_metric_t pkt_echo_in; +extern prometheus::simpleapi::counter_metric_t pkt_multicast_like_in; +extern prometheus::simpleapi::counter_metric_t pkt_network_credentials_in; +extern prometheus::simpleapi::counter_metric_t pkt_network_config_request_in; +extern prometheus::simpleapi::counter_metric_t pkt_network_config_in; +extern prometheus::simpleapi::counter_metric_t pkt_multicast_gather_in; +extern prometheus::simpleapi::counter_metric_t pkt_multicast_frame_in; +extern prometheus::simpleapi::counter_metric_t pkt_push_direct_paths_in; +extern prometheus::simpleapi::counter_metric_t pkt_user_message_in; +extern prometheus::simpleapi::counter_metric_t pkt_remote_trace_in; +extern prometheus::simpleapi::counter_metric_t pkt_path_negotiation_request_in; - // outgoing packets - extern prometheus::simpleapi::counter_metric_t pkt_nop_out; - extern prometheus::simpleapi::counter_metric_t pkt_error_out; - extern prometheus::simpleapi::counter_metric_t pkt_ack_out; - extern prometheus::simpleapi::counter_metric_t pkt_qos_out; - extern prometheus::simpleapi::counter_metric_t pkt_hello_out; - extern prometheus::simpleapi::counter_metric_t pkt_ok_out; - extern prometheus::simpleapi::counter_metric_t pkt_whois_out; - extern prometheus::simpleapi::counter_metric_t pkt_rendezvous_out; - extern prometheus::simpleapi::counter_metric_t pkt_frame_out; - extern prometheus::simpleapi::counter_metric_t pkt_ext_frame_out; - extern prometheus::simpleapi::counter_metric_t pkt_echo_out; - extern prometheus::simpleapi::counter_metric_t pkt_multicast_like_out; - extern prometheus::simpleapi::counter_metric_t pkt_network_credentials_out; - extern prometheus::simpleapi::counter_metric_t pkt_network_config_request_out; - extern prometheus::simpleapi::counter_metric_t pkt_network_config_out; - extern prometheus::simpleapi::counter_metric_t pkt_multicast_gather_out; - extern prometheus::simpleapi::counter_metric_t pkt_multicast_frame_out; - extern prometheus::simpleapi::counter_metric_t pkt_push_direct_paths_out; - extern prometheus::simpleapi::counter_metric_t pkt_user_message_out; - extern prometheus::simpleapi::counter_metric_t pkt_remote_trace_out; - extern prometheus::simpleapi::counter_metric_t pkt_path_negotiation_request_out; +// outgoing packets +extern prometheus::simpleapi::counter_metric_t pkt_nop_out; +extern prometheus::simpleapi::counter_metric_t pkt_error_out; +extern prometheus::simpleapi::counter_metric_t pkt_ack_out; +extern prometheus::simpleapi::counter_metric_t pkt_qos_out; +extern prometheus::simpleapi::counter_metric_t pkt_hello_out; +extern prometheus::simpleapi::counter_metric_t pkt_ok_out; +extern prometheus::simpleapi::counter_metric_t pkt_whois_out; +extern prometheus::simpleapi::counter_metric_t pkt_rendezvous_out; +extern prometheus::simpleapi::counter_metric_t pkt_frame_out; +extern prometheus::simpleapi::counter_metric_t pkt_ext_frame_out; +extern prometheus::simpleapi::counter_metric_t pkt_echo_out; +extern prometheus::simpleapi::counter_metric_t pkt_multicast_like_out; +extern prometheus::simpleapi::counter_metric_t pkt_network_credentials_out; +extern prometheus::simpleapi::counter_metric_t pkt_network_config_request_out; +extern prometheus::simpleapi::counter_metric_t pkt_network_config_out; +extern prometheus::simpleapi::counter_metric_t pkt_multicast_gather_out; +extern prometheus::simpleapi::counter_metric_t pkt_multicast_frame_out; +extern prometheus::simpleapi::counter_metric_t pkt_push_direct_paths_out; +extern prometheus::simpleapi::counter_metric_t pkt_user_message_out; +extern prometheus::simpleapi::counter_metric_t pkt_remote_trace_out; +extern prometheus::simpleapi::counter_metric_t pkt_path_negotiation_request_out; - // Packet Error Counts - extern prometheus::simpleapi::counter_family_t packet_errors; +// Packet Error Counts +extern prometheus::simpleapi::counter_family_t packet_errors; - // incoming errors - extern prometheus::simpleapi::counter_metric_t pkt_error_obj_not_found_in; - extern prometheus::simpleapi::counter_metric_t pkt_error_unsupported_op_in; - extern prometheus::simpleapi::counter_metric_t pkt_error_identity_collision_in; - extern prometheus::simpleapi::counter_metric_t pkt_error_need_membership_cert_in; - extern prometheus::simpleapi::counter_metric_t pkt_error_network_access_denied_in; - extern prometheus::simpleapi::counter_metric_t pkt_error_unwanted_multicast_in; - extern prometheus::simpleapi::counter_metric_t pkt_error_authentication_required_in; - extern prometheus::simpleapi::counter_metric_t pkt_error_internal_server_error_in; +// incoming errors +extern prometheus::simpleapi::counter_metric_t pkt_error_obj_not_found_in; +extern prometheus::simpleapi::counter_metric_t pkt_error_unsupported_op_in; +extern prometheus::simpleapi::counter_metric_t pkt_error_identity_collision_in; +extern prometheus::simpleapi::counter_metric_t pkt_error_need_membership_cert_in; +extern prometheus::simpleapi::counter_metric_t pkt_error_network_access_denied_in; +extern prometheus::simpleapi::counter_metric_t pkt_error_unwanted_multicast_in; +extern prometheus::simpleapi::counter_metric_t pkt_error_authentication_required_in; +extern prometheus::simpleapi::counter_metric_t pkt_error_internal_server_error_in; - // outgoing errors - extern prometheus::simpleapi::counter_metric_t pkt_error_obj_not_found_out; - extern prometheus::simpleapi::counter_metric_t pkt_error_unsupported_op_out; - extern prometheus::simpleapi::counter_metric_t pkt_error_identity_collision_out; - extern prometheus::simpleapi::counter_metric_t pkt_error_need_membership_cert_out; - extern prometheus::simpleapi::counter_metric_t pkt_error_network_access_denied_out; - extern prometheus::simpleapi::counter_metric_t pkt_error_unwanted_multicast_out; - extern prometheus::simpleapi::counter_metric_t pkt_error_authentication_required_out; - extern prometheus::simpleapi::counter_metric_t pkt_error_internal_server_error_out; +// outgoing errors +extern prometheus::simpleapi::counter_metric_t pkt_error_obj_not_found_out; +extern prometheus::simpleapi::counter_metric_t pkt_error_unsupported_op_out; +extern prometheus::simpleapi::counter_metric_t pkt_error_identity_collision_out; +extern prometheus::simpleapi::counter_metric_t pkt_error_need_membership_cert_out; +extern prometheus::simpleapi::counter_metric_t pkt_error_network_access_denied_out; +extern prometheus::simpleapi::counter_metric_t pkt_error_unwanted_multicast_out; +extern prometheus::simpleapi::counter_metric_t pkt_error_authentication_required_out; +extern prometheus::simpleapi::counter_metric_t pkt_error_internal_server_error_out; - // Data Sent/Received Metrics - extern prometheus::simpleapi::counter_family_t data; - extern prometheus::simpleapi::counter_metric_t udp_send; - extern prometheus::simpleapi::counter_metric_t udp_recv; - extern prometheus::simpleapi::counter_metric_t tcp_send; - extern prometheus::simpleapi::counter_metric_t tcp_recv; +// Data Sent/Received Metrics +extern prometheus::simpleapi::counter_family_t data; +extern prometheus::simpleapi::counter_metric_t udp_send; +extern prometheus::simpleapi::counter_metric_t udp_recv; +extern prometheus::simpleapi::counter_metric_t tcp_send; +extern prometheus::simpleapi::counter_metric_t tcp_recv; - // Network Metrics - extern prometheus::simpleapi::gauge_metric_t network_num_joined; - extern prometheus::simpleapi::gauge_family_t network_num_multicast_groups; - extern prometheus::simpleapi::counter_family_t network_packets; +// Network Metrics +extern prometheus::simpleapi::gauge_metric_t network_num_joined; +extern prometheus::simpleapi::gauge_family_t network_num_multicast_groups; +extern prometheus::simpleapi::counter_family_t network_packets; #ifndef ZT_NO_PEER_METRICS - // Peer Metrics - extern prometheus::CustomFamily> &peer_latency; - extern prometheus::simpleapi::gauge_family_t peer_path_count; - extern prometheus::simpleapi::counter_family_t peer_packets; - extern prometheus::simpleapi::counter_family_t peer_packet_errors; +// Peer Metrics +extern prometheus::CustomFamily >& peer_latency; +extern prometheus::simpleapi::gauge_family_t peer_path_count; +extern prometheus::simpleapi::counter_family_t peer_packets; +extern prometheus::simpleapi::counter_family_t peer_packet_errors; #endif - // General Controller Metrics - extern prometheus::simpleapi::gauge_metric_t network_count; - extern prometheus::simpleapi::gauge_metric_t member_count; - extern prometheus::simpleapi::counter_metric_t network_changes; - extern prometheus::simpleapi::counter_metric_t member_changes; - extern prometheus::simpleapi::counter_metric_t member_auths; - extern prometheus::simpleapi::counter_metric_t member_deauths; +// General Controller Metrics +extern prometheus::simpleapi::gauge_metric_t network_count; +extern prometheus::simpleapi::gauge_metric_t member_count; +extern prometheus::simpleapi::counter_metric_t network_changes; +extern prometheus::simpleapi::counter_metric_t member_changes; +extern prometheus::simpleapi::counter_metric_t member_auths; +extern prometheus::simpleapi::counter_metric_t member_deauths; - extern prometheus::simpleapi::gauge_metric_t network_config_request_queue_size; - extern prometheus::simpleapi::counter_metric_t sso_expiration_checks; - extern prometheus::simpleapi::counter_metric_t sso_member_deauth; - extern prometheus::simpleapi::counter_metric_t network_config_request; - extern prometheus::simpleapi::gauge_metric_t network_config_request_threads; - - extern prometheus::simpleapi::counter_metric_t db_get_network; - extern prometheus::simpleapi::counter_metric_t db_get_network_and_member; - extern prometheus::simpleapi::counter_metric_t db_get_network_and_member_and_summary; - extern prometheus::simpleapi::counter_metric_t db_get_member_list; - extern prometheus::simpleapi::counter_metric_t db_get_network_list; - extern prometheus::simpleapi::counter_metric_t db_member_change; - extern prometheus::simpleapi::counter_metric_t db_network_change; +extern prometheus::simpleapi::gauge_metric_t network_config_request_queue_size; +extern prometheus::simpleapi::counter_metric_t sso_expiration_checks; +extern prometheus::simpleapi::counter_metric_t sso_member_deauth; +extern prometheus::simpleapi::counter_metric_t network_config_request; +extern prometheus::simpleapi::gauge_metric_t network_config_request_threads; +extern prometheus::simpleapi::counter_metric_t db_get_network; +extern prometheus::simpleapi::counter_metric_t db_get_network_and_member; +extern prometheus::simpleapi::counter_metric_t db_get_network_and_member_and_summary; +extern prometheus::simpleapi::counter_metric_t db_get_member_list; +extern prometheus::simpleapi::counter_metric_t db_get_network_list; +extern prometheus::simpleapi::counter_metric_t db_member_change; +extern prometheus::simpleapi::counter_metric_t db_network_change; #ifdef ZT_CONTROLLER_USE_LIBPQ - // Central Controller Metrics - extern prometheus::simpleapi::counter_metric_t pgsql_mem_notification; - extern prometheus::simpleapi::counter_metric_t pgsql_net_notification; - extern prometheus::simpleapi::counter_metric_t pgsql_node_checkin; - extern prometheus::simpleapi::counter_metric_t pgsql_commit_ticks; - extern prometheus::simpleapi::counter_metric_t db_get_sso_info; - - extern prometheus::simpleapi::counter_metric_t redis_mem_notification; - extern prometheus::simpleapi::counter_metric_t redis_net_notification; - extern prometheus::simpleapi::counter_metric_t redis_node_checkin; +// Central Controller Metrics +extern prometheus::simpleapi::counter_metric_t pgsql_mem_notification; +extern prometheus::simpleapi::counter_metric_t pgsql_net_notification; +extern prometheus::simpleapi::counter_metric_t pgsql_node_checkin; +extern prometheus::simpleapi::counter_metric_t pgsql_commit_ticks; +extern prometheus::simpleapi::counter_metric_t db_get_sso_info; - +extern prometheus::simpleapi::counter_metric_t redis_mem_notification; +extern prometheus::simpleapi::counter_metric_t redis_net_notification; +extern prometheus::simpleapi::counter_metric_t redis_node_checkin; - // Central DB Pool Metrics - extern prometheus::simpleapi::counter_metric_t conn_counter; - extern prometheus::simpleapi::counter_metric_t max_pool_size; - extern prometheus::simpleapi::counter_metric_t min_pool_size; - extern prometheus::simpleapi::gauge_metric_t pool_avail; - extern prometheus::simpleapi::gauge_metric_t pool_in_use; - extern prometheus::simpleapi::counter_metric_t pool_errors; +// Central DB Pool Metrics +extern prometheus::simpleapi::counter_metric_t conn_counter; +extern prometheus::simpleapi::counter_metric_t max_pool_size; +extern prometheus::simpleapi::counter_metric_t min_pool_size; +extern prometheus::simpleapi::gauge_metric_t pool_avail; +extern prometheus::simpleapi::gauge_metric_t pool_in_use; +extern prometheus::simpleapi::counter_metric_t pool_errors; #endif - } // namespace Metrics -}// namespace ZeroTier +} // namespace Metrics +} // namespace ZeroTier -#endif // METRICS_H_ +#endif // METRICS_H_ diff --git a/node/MulticastGroup.hpp b/node/MulticastGroup.hpp index abd6f0aa..fc7cfd61 100644 --- a/node/MulticastGroup.hpp +++ b/node/MulticastGroup.hpp @@ -14,10 +14,10 @@ #ifndef ZT_MULTICASTGROUP_HPP #define ZT_MULTICASTGROUP_HPP -#include - -#include "MAC.hpp" #include "InetAddress.hpp" +#include "MAC.hpp" + +#include namespace ZeroTier { @@ -36,78 +36,99 @@ namespace ZeroTier { * * MulticastGroup behaves as an immutable value object. */ -class MulticastGroup -{ -public: - MulticastGroup() : - _mac(), - _adi(0) - { - } +class MulticastGroup { + public: + MulticastGroup() : _mac(), _adi(0) + { + } - MulticastGroup(const MAC &m,uint32_t a) : - _mac(m), - _adi(a) - { - } + MulticastGroup(const MAC& m, uint32_t a) : _mac(m), _adi(a) + { + } - /** - * Derive the multicast group used for address resolution (ARP/NDP) for an IP - * - * @param ip IP address (port field is ignored) - * @return Multicast group for ARP/NDP - */ - static inline MulticastGroup deriveMulticastGroupForAddressResolution(const InetAddress &ip) - { - if (ip.isV4()) { - // IPv4 wants broadcast MACs, so we shove the V4 address itself into - // the Multicast Group ADI field. Making V4 ARP work is basically why - // ADI was added, as well as handling other things that want mindless - // Ethernet broadcast to all. - return MulticastGroup(MAC(0xffffffffffffULL),Utils::ntoh(*((const uint32_t *)ip.rawIpData()))); - } else if (ip.isV6()) { - // IPv6 is better designed in this respect. We can compute the IPv6 - // multicast address directly from the IP address, and it gives us - // 24 bits of uniqueness. Collisions aren't likely to be common enough - // to care about. - const unsigned char *a = (const unsigned char *)ip.rawIpData(); - return MulticastGroup(MAC(0x33,0x33,0xff,a[13],a[14],a[15]),0); - } - return MulticastGroup(); - } + /** + * Derive the multicast group used for address resolution (ARP/NDP) for an IP + * + * @param ip IP address (port field is ignored) + * @return Multicast group for ARP/NDP + */ + static inline MulticastGroup deriveMulticastGroupForAddressResolution(const InetAddress& ip) + { + if (ip.isV4()) { + // IPv4 wants broadcast MACs, so we shove the V4 address itself into + // the Multicast Group ADI field. Making V4 ARP work is basically why + // ADI was added, as well as handling other things that want mindless + // Ethernet broadcast to all. + return MulticastGroup(MAC(0xffffffffffffULL), Utils::ntoh(*((const uint32_t*)ip.rawIpData()))); + } + else if (ip.isV6()) { + // IPv6 is better designed in this respect. We can compute the IPv6 + // multicast address directly from the IP address, and it gives us + // 24 bits of uniqueness. Collisions aren't likely to be common enough + // to care about. + const unsigned char* a = (const unsigned char*)ip.rawIpData(); + return MulticastGroup(MAC(0x33, 0x33, 0xff, a[13], a[14], a[15]), 0); + } + return MulticastGroup(); + } - /** - * @return Multicast address - */ - inline const MAC &mac() const { return _mac; } + /** + * @return Multicast address + */ + inline const MAC& mac() const + { + return _mac; + } - /** - * @return Additional distinguishing information - */ - inline uint32_t adi() const { return _adi; } + /** + * @return Additional distinguishing information + */ + inline uint32_t adi() const + { + return _adi; + } - inline unsigned long hashCode() const { return (_mac.hashCode() ^ (unsigned long)_adi); } + inline unsigned long hashCode() const + { + return (_mac.hashCode() ^ (unsigned long)_adi); + } - inline bool operator==(const MulticastGroup &g) const { return ((_mac == g._mac)&&(_adi == g._adi)); } - inline bool operator!=(const MulticastGroup &g) const { return ((_mac != g._mac)||(_adi != g._adi)); } - inline bool operator<(const MulticastGroup &g) const - { - if (_mac < g._mac) { - return true; - } else if (_mac == g._mac) { - return (_adi < g._adi); - } - return false; - } - inline bool operator>(const MulticastGroup &g) const { return (g < *this); } - inline bool operator<=(const MulticastGroup &g) const { return !(g < *this); } - inline bool operator>=(const MulticastGroup &g) const { return !(*this < g); } + inline bool operator==(const MulticastGroup& g) const + { + return ((_mac == g._mac) && (_adi == g._adi)); + } + inline bool operator!=(const MulticastGroup& g) const + { + return ((_mac != g._mac) || (_adi != g._adi)); + } + inline bool operator<(const MulticastGroup& g) const + { + if (_mac < g._mac) { + return true; + } + else if (_mac == g._mac) { + return (_adi < g._adi); + } + return false; + } + inline bool operator>(const MulticastGroup& g) const + { + return (g < *this); + } + inline bool operator<=(const MulticastGroup& g) const + { + return ! (g < *this); + } + inline bool operator>=(const MulticastGroup& g) const + { + return ! (*this < g); + } -private: - MAC _mac; - uint32_t _adi; + private: + MAC _mac; + uint32_t _adi; }; -} // namespace ZeroTier +} // namespace ZeroTier #endif diff --git a/node/Multicaster.cpp b/node/Multicaster.cpp index 3a771972..29add1f6 100644 --- a/node/Multicaster.cpp +++ b/node/Multicaster.cpp @@ -11,25 +11,23 @@ */ /****/ -#include - -#include "Constants.hpp" -#include "RuntimeEnvironment.hpp" #include "Multicaster.hpp" -#include "Topology.hpp" -#include "Switch.hpp" + +#include "CertificateOfMembership.hpp" +#include "Constants.hpp" +#include "Network.hpp" +#include "Node.hpp" #include "Packet.hpp" #include "Peer.hpp" -#include "C25519.hpp" -#include "CertificateOfMembership.hpp" -#include "Node.hpp" -#include "Network.hpp" +#include "RuntimeEnvironment.hpp" +#include "Switch.hpp" +#include "Topology.hpp" + +#include namespace ZeroTier { -Multicaster::Multicaster(const RuntimeEnvironment *renv) : - RR(renv), - _groups(32) +Multicaster::Multicaster(const RuntimeEnvironment* renv) : RR(renv), _groups(32) { } @@ -37,427 +35,417 @@ Multicaster::~Multicaster() { } -void Multicaster::addMultiple(void *tPtr,int64_t now,uint64_t nwid,const MulticastGroup &mg,const void *addresses,unsigned int count,unsigned int totalKnown) +void Multicaster::addMultiple(void* tPtr, int64_t now, uint64_t nwid, const MulticastGroup& mg, const void* addresses, unsigned int count, unsigned int totalKnown) { - const unsigned char *p = (const unsigned char *)addresses; - const unsigned char *e = p + (5 * count); - Mutex::Lock _l(_groups_m); - MulticastGroupStatus &gs = _groups[Multicaster::Key(nwid,mg)]; - while (p != e) { - _add(tPtr,now,nwid,mg,gs,Address(p,5)); - p += 5; - } + const unsigned char* p = (const unsigned char*)addresses; + const unsigned char* e = p + (5 * count); + Mutex::Lock _l(_groups_m); + MulticastGroupStatus& gs = _groups[Multicaster::Key(nwid, mg)]; + while (p != e) { + _add(tPtr, now, nwid, mg, gs, Address(p, 5)); + p += 5; + } } -void Multicaster::remove(uint64_t nwid,const MulticastGroup &mg,const Address &member) +void Multicaster::remove(uint64_t nwid, const MulticastGroup& mg, const Address& member) { - Mutex::Lock _l(_groups_m); - MulticastGroupStatus *s = _groups.get(Multicaster::Key(nwid,mg)); - if (s) { - for(std::vector::iterator m(s->members.begin());m!=s->members.end();++m) { - if (m->address == member) { - s->members.erase(m); - break; - } - } - } + Mutex::Lock _l(_groups_m); + MulticastGroupStatus* s = _groups.get(Multicaster::Key(nwid, mg)); + if (s) { + for (std::vector::iterator m(s->members.begin()); m != s->members.end(); ++m) { + if (m->address == member) { + s->members.erase(m); + break; + } + } + } } -unsigned int Multicaster::gather(const Address &queryingPeer,uint64_t nwid,const MulticastGroup &mg,Buffer &appendTo,unsigned int limit) const +unsigned int Multicaster::gather(const Address& queryingPeer, uint64_t nwid, const MulticastGroup& mg, Buffer& appendTo, unsigned int limit) const { - unsigned char *p; - unsigned int added = 0,i,k,rptr,totalKnown = 0; - uint64_t a,picked[(ZT_PROTO_MAX_PACKET_LENGTH / 5) + 2]; + unsigned char* p; + unsigned int added = 0, i, k, rptr, totalKnown = 0; + uint64_t a, picked[(ZT_PROTO_MAX_PACKET_LENGTH / 5) + 2]; - if (!limit) { - return 0; - } else if (limit > 0xffff) { - limit = 0xffff; - } + if (! limit) { + return 0; + } + else if (limit > 0xffff) { + limit = 0xffff; + } - const unsigned int totalAt = appendTo.size(); - appendTo.addSize(4); // sizeof(uint32_t) - const unsigned int addedAt = appendTo.size(); - appendTo.addSize(2); // sizeof(uint16_t) + const unsigned int totalAt = appendTo.size(); + appendTo.addSize(4); // sizeof(uint32_t) + const unsigned int addedAt = appendTo.size(); + appendTo.addSize(2); // sizeof(uint16_t) - { // Return myself if I am a member of this group - SharedPtr network(RR->node->network(nwid)); - if ((network)&&(network->subscribedToMulticastGroup(mg,true))) { - RR->identity.address().appendTo(appendTo); - ++totalKnown; - ++added; - } - } + { // Return myself if I am a member of this group + SharedPtr network(RR->node->network(nwid)); + if ((network) && (network->subscribedToMulticastGroup(mg, true))) { + RR->identity.address().appendTo(appendTo); + ++totalKnown; + ++added; + } + } - Mutex::Lock _l(_groups_m); + Mutex::Lock _l(_groups_m); - const MulticastGroupStatus *s = _groups.get(Multicaster::Key(nwid,mg)); - if ((s)&&(!s->members.empty())) { - totalKnown += (unsigned int)s->members.size(); + const MulticastGroupStatus* s = _groups.get(Multicaster::Key(nwid, mg)); + if ((s) && (! s->members.empty())) { + totalKnown += (unsigned int)s->members.size(); - // Members are returned in random order so that repeated gather queries - // will return different subsets of a large multicast group. - k = 0; - while ((added < limit)&&(k < s->members.size())&&((appendTo.size() + ZT_ADDRESS_LENGTH) <= ZT_PROTO_MAX_PACKET_LENGTH)) { - rptr = (unsigned int)RR->node->prng(); + // Members are returned in random order so that repeated gather queries + // will return different subsets of a large multicast group. + k = 0; + while ((added < limit) && (k < s->members.size()) && ((appendTo.size() + ZT_ADDRESS_LENGTH) <= ZT_PROTO_MAX_PACKET_LENGTH)) { + rptr = (unsigned int)RR->node->prng(); -restart_member_scan: - a = s->members[rptr % (unsigned int)s->members.size()].address.toInt(); - for(i=0;imembers[rptr % (unsigned int)s->members.size()].address.toInt(); + for (i = 0; i < k; ++i) { + if (picked[i] == a) { + ++rptr; + goto restart_member_scan; + } + } + picked[k++] = a; - if (queryingPeer.toInt() != a) { // do not return the peer that is making the request as a result - p = (unsigned char *)appendTo.appendField(ZT_ADDRESS_LENGTH); - *(p++) = (unsigned char)((a >> 32) & 0xff); - *(p++) = (unsigned char)((a >> 24) & 0xff); - *(p++) = (unsigned char)((a >> 16) & 0xff); - *(p++) = (unsigned char)((a >> 8) & 0xff); - *p = (unsigned char)(a & 0xff); - ++added; - } - } - } + if (queryingPeer.toInt() != a) { // do not return the peer that is making the request as a result + p = (unsigned char*)appendTo.appendField(ZT_ADDRESS_LENGTH); + *(p++) = (unsigned char)((a >> 32) & 0xff); + *(p++) = (unsigned char)((a >> 24) & 0xff); + *(p++) = (unsigned char)((a >> 16) & 0xff); + *(p++) = (unsigned char)((a >> 8) & 0xff); + *p = (unsigned char)(a & 0xff); + ++added; + } + } + } - appendTo.setAt(totalAt,(uint32_t)totalKnown); - appendTo.setAt(addedAt,(uint16_t)added); + appendTo.setAt(totalAt, (uint32_t)totalKnown); + appendTo.setAt(addedAt, (uint16_t)added); - return added; + return added; } -std::vector
Multicaster::getMembers(uint64_t nwid,const MulticastGroup &mg,unsigned int limit) const +std::vector
Multicaster::getMembers(uint64_t nwid, const MulticastGroup& mg, unsigned int limit) const { - std::vector
ls; - Mutex::Lock _l(_groups_m); - const MulticastGroupStatus *s = _groups.get(Multicaster::Key(nwid,mg)); - if (!s) { - return ls; - } - for(std::vector::const_reverse_iterator m(s->members.rbegin());m!=s->members.rend();++m) { - ls.push_back(m->address); - if (ls.size() >= limit) { - break; - } - } - return ls; + std::vector
ls; + Mutex::Lock _l(_groups_m); + const MulticastGroupStatus* s = _groups.get(Multicaster::Key(nwid, mg)); + if (! s) { + return ls; + } + for (std::vector::const_reverse_iterator m(s->members.rbegin()); m != s->members.rend(); ++m) { + ls.push_back(m->address); + if (ls.size() >= limit) { + break; + } + } + return ls; } -void Multicaster::send( - void *tPtr, - int64_t now, - const SharedPtr &network, - const Address &origin, - const MulticastGroup &mg, - const MAC &src, - unsigned int etherType, - const void *data, - unsigned int len) +void Multicaster::send(void* tPtr, int64_t now, const SharedPtr& network, const Address& origin, const MulticastGroup& mg, const MAC& src, unsigned int etherType, const void* data, unsigned int len) { - unsigned long idxbuf[4096]; - unsigned long *indexes = idxbuf; + unsigned long idxbuf[4096]; + unsigned long* indexes = idxbuf; - // If we're in hub-and-spoke designated multicast replication mode, see if we - // have a multicast replicator active. If so, pick the best and send it - // there. If we are a multicast replicator or if none are alive, fall back - // to sender replication. Note that bridges do not do this since this would - // break bridge route learning. This is sort of an edge case limitation of - // the current protocol and could be fixed, but fixing it would add more - // complexity than the fix is probably worth. Bridges are generally high - // bandwidth nodes. - if (!network->config().isActiveBridge(RR->identity.address())) { - Address multicastReplicators[ZT_MAX_NETWORK_SPECIALISTS]; - const unsigned int multicastReplicatorCount = network->config().multicastReplicators(multicastReplicators); - if (multicastReplicatorCount) { - if (std::find(multicastReplicators,multicastReplicators + multicastReplicatorCount,RR->identity.address()) == (multicastReplicators + multicastReplicatorCount)) { - SharedPtr bestMulticastReplicator; - SharedPtr bestMulticastReplicatorPath; - unsigned int bestMulticastReplicatorLatency = 0xffff; - for(unsigned int i=0;i p(RR->topology->getPeerNoCache(multicastReplicators[i])); - if ((p)&&(p->isAlive(now))) { - const SharedPtr pp(p->getAppropriatePath(now,false)); - if ((pp)&&(pp->latency() < bestMulticastReplicatorLatency)) { - bestMulticastReplicatorLatency = pp->latency(); - bestMulticastReplicatorPath = pp; - bestMulticastReplicator = p; - } - } - } - if (bestMulticastReplicator) { - Packet outp(bestMulticastReplicator->address(),RR->identity.address(),Packet::VERB_MULTICAST_FRAME); - outp.append((uint64_t)network->id()); - outp.append((uint8_t)0x0c); // includes source MAC | please replicate - ((src) ? src : MAC(RR->identity.address(),network->id())).appendTo(outp); - mg.mac().appendTo(outp); - outp.append((uint32_t)mg.adi()); - outp.append((uint16_t)etherType); - outp.append(data,len); - if (!network->config().disableCompression()) { - outp.compress(); - } - outp.armor(bestMulticastReplicator->key(),true,bestMulticastReplicator->aesKeysIfSupported()); - Metrics::pkt_multicast_frame_out++; - bestMulticastReplicatorPath->send(RR,tPtr,outp.data(),outp.size(),now); - return; - } - } - } - } + // If we're in hub-and-spoke designated multicast replication mode, see if we + // have a multicast replicator active. If so, pick the best and send it + // there. If we are a multicast replicator or if none are alive, fall back + // to sender replication. Note that bridges do not do this since this would + // break bridge route learning. This is sort of an edge case limitation of + // the current protocol and could be fixed, but fixing it would add more + // complexity than the fix is probably worth. Bridges are generally high + // bandwidth nodes. + if (! network->config().isActiveBridge(RR->identity.address())) { + Address multicastReplicators[ZT_MAX_NETWORK_SPECIALISTS]; + const unsigned int multicastReplicatorCount = network->config().multicastReplicators(multicastReplicators); + if (multicastReplicatorCount) { + if (std::find(multicastReplicators, multicastReplicators + multicastReplicatorCount, RR->identity.address()) == (multicastReplicators + multicastReplicatorCount)) { + SharedPtr bestMulticastReplicator; + SharedPtr bestMulticastReplicatorPath; + unsigned int bestMulticastReplicatorLatency = 0xffff; + for (unsigned int i = 0; i < multicastReplicatorCount; ++i) { + const SharedPtr p(RR->topology->getPeerNoCache(multicastReplicators[i])); + if ((p) && (p->isAlive(now))) { + const SharedPtr pp(p->getAppropriatePath(now, false)); + if ((pp) && (pp->latency() < bestMulticastReplicatorLatency)) { + bestMulticastReplicatorLatency = pp->latency(); + bestMulticastReplicatorPath = pp; + bestMulticastReplicator = p; + } + } + } + if (bestMulticastReplicator) { + Packet outp(bestMulticastReplicator->address(), RR->identity.address(), Packet::VERB_MULTICAST_FRAME); + outp.append((uint64_t)network->id()); + outp.append((uint8_t)0x0c); // includes source MAC | please replicate + ((src) ? src : MAC(RR->identity.address(), network->id())).appendTo(outp); + mg.mac().appendTo(outp); + outp.append((uint32_t)mg.adi()); + outp.append((uint16_t)etherType); + outp.append(data, len); + if (! network->config().disableCompression()) { + outp.compress(); + } + outp.armor(bestMulticastReplicator->key(), true, false, bestMulticastReplicator->aesKeysIfSupported(), bestMulticastReplicator->identity()); + Metrics::pkt_multicast_frame_out++; + bestMulticastReplicatorPath->send(RR, tPtr, outp.data(), outp.size(), now); + return; + } + } + } + } - try { - Mutex::Lock _l(_groups_m); - MulticastGroupStatus &gs = _groups[Multicaster::Key(network->id(),mg)]; + try { + Mutex::Lock _l(_groups_m); + MulticastGroupStatus& gs = _groups[Multicaster::Key(network->id(), mg)]; - if (!gs.members.empty()) { - // Allocate a memory buffer if group is monstrous - if (gs.members.size() > (sizeof(idxbuf) / sizeof(unsigned long))) { - indexes = new unsigned long[gs.members.size()]; - } + if (! gs.members.empty()) { + // Allocate a memory buffer if group is monstrous + if (gs.members.size() > (sizeof(idxbuf) / sizeof(unsigned long))) { + indexes = new unsigned long[gs.members.size()]; + } - // Generate a random permutation of member indexes - for(unsigned long i=0;i0;--i) { - unsigned long j = (unsigned long)RR->node->prng() % (i + 1); - unsigned long tmp = indexes[j]; - indexes[j] = indexes[i]; - indexes[i] = tmp; - } - } + // Generate a random permutation of member indexes + for (unsigned long i = 0; i < gs.members.size(); ++i) { + indexes[i] = i; + } + for (unsigned long i = (unsigned long)gs.members.size() - 1; i > 0; --i) { + unsigned long j = (unsigned long)RR->node->prng() % (i + 1); + unsigned long tmp = indexes[j]; + indexes[j] = indexes[i]; + indexes[i] = tmp; + } + } - Address activeBridges[ZT_MAX_NETWORK_SPECIALISTS]; - const unsigned int activeBridgeCount = network->config().activeBridges(activeBridges); - const unsigned int limit = network->config().multicastLimit; + Address activeBridges[ZT_MAX_NETWORK_SPECIALISTS]; + const unsigned int activeBridgeCount = network->config().activeBridges(activeBridges); + const unsigned int limit = network->config().multicastLimit; - if (gs.members.size() >= limit) { - // Skip queue if we already have enough members to complete the send operation - OutboundMulticast out; + if (gs.members.size() >= limit) { + // Skip queue if we already have enough members to complete the send operation + OutboundMulticast out; - out.init( - RR, - now, - network->id(), - network->config().disableCompression(), - limit, - 1, // we'll still gather a little from peers to keep multicast list fresh - src, - mg, - etherType, - data, - len); + out.init( + RR, + now, + network->id(), + network->config().disableCompression(), + limit, + 1, // we'll still gather a little from peers to keep multicast list fresh + src, + mg, + etherType, + data, + len); - unsigned int count = 0; + unsigned int count = 0; - for(unsigned int i=0;iidentity.address())&&(activeBridges[i] != origin)) { - out.sendOnly(RR,tPtr,activeBridges[i]); // optimization: don't use dedup log if it's a one-pass send - if (++count >= limit) { - break; - } - } - } + for (unsigned int i = 0; i < activeBridgeCount; ++i) { + if ((activeBridges[i] != RR->identity.address()) && (activeBridges[i] != origin)) { + out.sendOnly(RR, tPtr, activeBridges[i]); // optimization: don't use dedup log if it's a one-pass send + if (++count >= limit) { + break; + } + } + } - unsigned long idx = 0; - while ((count < limit)&&(idx < gs.members.size())) { - const Address ma(gs.members[indexes[idx++]].address); - if ((std::find(activeBridges,activeBridges + activeBridgeCount,ma) == (activeBridges + activeBridgeCount))&&(ma != origin)) { - out.sendOnly(RR,tPtr,ma); // optimization: don't use dedup log if it's a one-pass send - ++count; - } - } - } else { - while (gs.txQueue.size() >= ZT_TX_QUEUE_SIZE) { - gs.txQueue.pop_front(); - } + unsigned long idx = 0; + while ((count < limit) && (idx < gs.members.size())) { + const Address ma(gs.members[indexes[idx++]].address); + if ((std::find(activeBridges, activeBridges + activeBridgeCount, ma) == (activeBridges + activeBridgeCount)) && (ma != origin)) { + out.sendOnly(RR, tPtr, ma); // optimization: don't use dedup log if it's a one-pass send + ++count; + } + } + } + else { + while (gs.txQueue.size() >= ZT_TX_QUEUE_SIZE) { + gs.txQueue.pop_front(); + } - const unsigned int gatherLimit = (limit - (unsigned int)gs.members.size()) + 1; + const unsigned int gatherLimit = (limit - (unsigned int)gs.members.size()) + 1; - int timerScale = RR->node->lowBandwidthModeEnabled() ? 3 : 1; - if ((gs.members.empty())||((now - gs.lastExplicitGather) >= (ZT_MULTICAST_EXPLICIT_GATHER_DELAY * timerScale))) { - gs.lastExplicitGather = now; + int timerScale = RR->node->lowBandwidthModeEnabled() ? 3 : 1; + if ((gs.members.empty()) || ((now - gs.lastExplicitGather) >= (ZT_MULTICAST_EXPLICIT_GATHER_DELAY * timerScale))) { + gs.lastExplicitGather = now; - Address explicitGatherPeers[16]; - unsigned int numExplicitGatherPeers = 0; + Address explicitGatherPeers[16]; + unsigned int numExplicitGatherPeers = 0; - SharedPtr bestRoot(RR->topology->getUpstreamPeer()); - if (bestRoot) { - explicitGatherPeers[numExplicitGatherPeers++] = bestRoot->address(); - } + SharedPtr bestRoot(RR->topology->getUpstreamPeer()); + if (bestRoot) { + explicitGatherPeers[numExplicitGatherPeers++] = bestRoot->address(); + } - explicitGatherPeers[numExplicitGatherPeers++] = network->controller(); + explicitGatherPeers[numExplicitGatherPeers++] = network->controller(); - Address ac[ZT_MAX_NETWORK_SPECIALISTS]; - const unsigned int accnt = network->config().alwaysContactAddresses(ac); - unsigned int shuffled[ZT_MAX_NETWORK_SPECIALISTS]; - for(unsigned int i=0;i>1;inode->prng(); - const unsigned int x1 = shuffled[(unsigned int)x % accnt]; - const unsigned int x2 = shuffled[(unsigned int)(x >> 32) % accnt]; - const unsigned int tmp = shuffled[x1]; - shuffled[x1] = shuffled[x2]; - shuffled[x2] = tmp; - } - for(unsigned int i=0;iconfig().alwaysContactAddresses(ac); + unsigned int shuffled[ZT_MAX_NETWORK_SPECIALISTS]; + for (unsigned int i = 0; i < accnt; ++i) { + shuffled[i] = i; + } + for (unsigned int i = 0, k = accnt >> 1; i < k; ++i) { + const uint64_t x = RR->node->prng(); + const unsigned int x1 = shuffled[(unsigned int)x % accnt]; + const unsigned int x2 = shuffled[(unsigned int)(x >> 32) % accnt]; + const unsigned int tmp = shuffled[x1]; + shuffled[x1] = shuffled[x2]; + shuffled[x2] = tmp; + } + for (unsigned int i = 0; i < accnt; ++i) { + explicitGatherPeers[numExplicitGatherPeers++] = ac[shuffled[i]]; + if (numExplicitGatherPeers == 16) { + break; + } + } - std::vector
anchors(network->config().anchors()); - for(std::vector
::const_iterator a(anchors.begin());a!=anchors.end();++a) { - if (*a != RR->identity.address()) { - explicitGatherPeers[numExplicitGatherPeers++] = *a; - if (numExplicitGatherPeers == 16) { - break; - } - } - } + std::vector
anchors(network->config().anchors()); + for (std::vector
::const_iterator a(anchors.begin()); a != anchors.end(); ++a) { + if (*a != RR->identity.address()) { + explicitGatherPeers[numExplicitGatherPeers++] = *a; + if (numExplicitGatherPeers == 16) { + break; + } + } + } - for(unsigned int k=0;kconfig().com) ? &(network->config().com) : (const CertificateOfMembership *)0) : (const CertificateOfMembership *)0; - Packet outp(explicitGatherPeers[k],RR->identity.address(),Packet::VERB_MULTICAST_GATHER); - outp.append(network->id()); - outp.append((uint8_t)((com) ? 0x01 : 0x00)); - mg.mac().appendTo(outp); - outp.append((uint32_t)mg.adi()); - outp.append((uint32_t)gatherLimit); - if (com) { - com->serialize(outp); - } - RR->node->expectReplyTo(outp.packetId()); - RR->sw->send(tPtr,outp,true); - Metrics::pkt_multicast_gather_out++; - } - } + for (unsigned int k = 0; k < numExplicitGatherPeers; ++k) { + const CertificateOfMembership* com = (network) ? ((network->config().com) ? &(network->config().com) : (const CertificateOfMembership*)0) : (const CertificateOfMembership*)0; + Packet outp(explicitGatherPeers[k], RR->identity.address(), Packet::VERB_MULTICAST_GATHER); + outp.append(network->id()); + outp.append((uint8_t)((com) ? 0x01 : 0x00)); + mg.mac().appendTo(outp); + outp.append((uint32_t)mg.adi()); + outp.append((uint32_t)gatherLimit); + if (com) { + com->serialize(outp); + } + RR->node->expectReplyTo(outp.packetId()); + RR->sw->send(tPtr, outp, true); + Metrics::pkt_multicast_gather_out++; + } + } - gs.txQueue.push_back(OutboundMulticast()); - OutboundMulticast &out = gs.txQueue.back(); + gs.txQueue.push_back(OutboundMulticast()); + OutboundMulticast& out = gs.txQueue.back(); - out.init( - RR, - now, - network->id(), - network->config().disableCompression(), - limit, - gatherLimit, - src, - mg, - etherType, - data, - len); + out.init(RR, now, network->id(), network->config().disableCompression(), limit, gatherLimit, src, mg, etherType, data, len); - if (origin) { - out.logAsSent(origin); - } + if (origin) { + out.logAsSent(origin); + } - unsigned int count = 0; + unsigned int count = 0; - for(unsigned int i=0;iidentity.address()) { - out.sendAndLog(RR,tPtr,activeBridges[i]); - if (++count >= limit) { - break; - } - } - } + for (unsigned int i = 0; i < activeBridgeCount; ++i) { + if (activeBridges[i] != RR->identity.address()) { + out.sendAndLog(RR, tPtr, activeBridges[i]); + if (++count >= limit) { + break; + } + } + } - unsigned long idx = 0; - while ((count < limit)&&(idx < gs.members.size())) { - Address ma(gs.members[indexes[idx++]].address); - if (std::find(activeBridges,activeBridges + activeBridgeCount,ma) == (activeBridges + activeBridgeCount)) { - out.sendAndLog(RR,tPtr,ma); - ++count; - } - } - } - } catch ( ... ) {} // this is a sanity check to catch any failures and make sure indexes[] still gets deleted + unsigned long idx = 0; + while ((count < limit) && (idx < gs.members.size())) { + Address ma(gs.members[indexes[idx++]].address); + if (std::find(activeBridges, activeBridges + activeBridgeCount, ma) == (activeBridges + activeBridgeCount)) { + out.sendAndLog(RR, tPtr, ma); + ++count; + } + } + } + } + catch (...) { + } // this is a sanity check to catch any failures and make sure indexes[] still gets deleted - // Free allocated memory buffer if any - if (indexes != idxbuf) { - delete [] indexes; - } + // Free allocated memory buffer if any + if (indexes != idxbuf) { + delete[] indexes; + } } void Multicaster::clean(int64_t now) { - Mutex::Lock _l(_groups_m); - Multicaster::Key *k = (Multicaster::Key *)0; - MulticastGroupStatus *s = (MulticastGroupStatus *)0; - Hashtable::Iterator mm(_groups); - while (mm.next(k,s)) { - for(std::list::iterator tx(s->txQueue.begin());tx!=s->txQueue.end();) { - if ((tx->expired(now))||(tx->atLimit())) { - s->txQueue.erase(tx++); - } else { - ++tx; - } - } + Mutex::Lock _l(_groups_m); + Multicaster::Key* k = (Multicaster::Key*)0; + MulticastGroupStatus* s = (MulticastGroupStatus*)0; + Hashtable::Iterator mm(_groups); + while (mm.next(k, s)) { + for (std::list::iterator tx(s->txQueue.begin()); tx != s->txQueue.end();) { + if ((tx->expired(now)) || (tx->atLimit())) { + s->txQueue.erase(tx++); + } + else { + ++tx; + } + } - unsigned long count = 0; - { - std::vector::iterator reader(s->members.begin()); - std::vector::iterator writer(reader); - while (reader != s->members.end()) { - if ((now - reader->timestamp) < ZT_MULTICAST_LIKE_EXPIRE) { - *writer = *reader; - ++writer; - ++count; - } - ++reader; - } - } + unsigned long count = 0; + { + std::vector::iterator reader(s->members.begin()); + std::vector::iterator writer(reader); + while (reader != s->members.end()) { + if ((now - reader->timestamp) < ZT_MULTICAST_LIKE_EXPIRE) { + *writer = *reader; + ++writer; + ++count; + } + ++reader; + } + } - if (count) { - s->members.resize(count); - } else if (s->txQueue.empty()) { - _groups.erase(*k); - } else { - s->members.clear(); - } - } + if (count) { + s->members.resize(count); + } + else if (s->txQueue.empty()) { + _groups.erase(*k); + } + else { + s->members.clear(); + } + } } -void Multicaster::_add(void *tPtr,int64_t now,uint64_t nwid,const MulticastGroup &mg,MulticastGroupStatus &gs,const Address &member) +void Multicaster::_add(void* tPtr, int64_t now, uint64_t nwid, const MulticastGroup& mg, MulticastGroupStatus& gs, const Address& member) { - // assumes _groups_m is locked + // assumes _groups_m is locked - // Do not add self -- even if someone else returns it - if (member == RR->identity.address()) { - return; - } + // Do not add self -- even if someone else returns it + if (member == RR->identity.address()) { + return; + } - std::vector::iterator m(std::lower_bound(gs.members.begin(),gs.members.end(),member)); - if (m != gs.members.end()) { - if (m->address == member) { - m->timestamp = now; - return; - } - gs.members.insert(m,MulticastGroupMember(member,now)); - } else { - gs.members.push_back(MulticastGroupMember(member,now)); - } + std::vector::iterator m(std::lower_bound(gs.members.begin(), gs.members.end(), member)); + if (m != gs.members.end()) { + if (m->address == member) { + m->timestamp = now; + return; + } + gs.members.insert(m, MulticastGroupMember(member, now)); + } + else { + gs.members.push_back(MulticastGroupMember(member, now)); + } - for(std::list::iterator tx(gs.txQueue.begin());tx!=gs.txQueue.end();) { - if (tx->atLimit()) { - gs.txQueue.erase(tx++); - } else { - tx->sendIfNew(RR,tPtr,member); - if (tx->atLimit()) { - gs.txQueue.erase(tx++); - } else { - ++tx; - } - } - } + for (std::list::iterator tx(gs.txQueue.begin()); tx != gs.txQueue.end();) { + if (tx->atLimit()) { + gs.txQueue.erase(tx++); + } + else { + tx->sendIfNew(RR, tPtr, member); + if (tx->atLimit()) { + gs.txQueue.erase(tx++); + } + else { + ++tx; + } + } + } } -} // namespace ZeroTier +} // namespace ZeroTier diff --git a/node/Multicaster.hpp b/node/Multicaster.hpp index 38117144..11c0f97b 100644 --- a/node/Multicaster.hpp +++ b/node/Multicaster.hpp @@ -14,22 +14,21 @@ #ifndef ZT_MULTICASTER_HPP #define ZT_MULTICASTER_HPP -#include -#include - -#include -#include -#include - +#include "Address.hpp" #include "Constants.hpp" #include "Hashtable.hpp" -#include "Address.hpp" #include "MAC.hpp" #include "MulticastGroup.hpp" -#include "OutboundMulticast.hpp" -#include "Utils.hpp" #include "Mutex.hpp" +#include "OutboundMulticast.hpp" #include "SharedPtr.hpp" +#include "Utils.hpp" + +#include +#include +#include +#include +#include namespace ZeroTier { @@ -41,157 +40,181 @@ class Network; /** * Database of known multicast peers within a network */ -class Multicaster -{ -public: - Multicaster(const RuntimeEnvironment *renv); - ~Multicaster(); +class Multicaster { + public: + Multicaster(const RuntimeEnvironment* renv); + ~Multicaster(); - /** - * Add or update a member in a multicast group - * - * @param now Current time - * @param nwid Network ID - * @param mg Multicast group - * @param member New member address - */ - inline void add(void *tPtr,int64_t now,uint64_t nwid,const MulticastGroup &mg,const Address &member) - { - Mutex::Lock _l(_groups_m); - _add(tPtr,now,nwid,mg,_groups[Multicaster::Key(nwid,mg)],member); - } + /** + * Add or update a member in a multicast group + * + * @param now Current time + * @param nwid Network ID + * @param mg Multicast group + * @param member New member address + */ + inline void add(void* tPtr, int64_t now, uint64_t nwid, const MulticastGroup& mg, const Address& member) + { + Mutex::Lock _l(_groups_m); + _add(tPtr, now, nwid, mg, _groups[Multicaster::Key(nwid, mg)], member); + } - /** - * Add multiple addresses from a binary array of 5-byte address fields - * - * It's up to the caller to check bounds on the array before calling this. - * - * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call - * @param now Current time - * @param nwid Network ID - * @param mg Multicast group - * @param addresses Raw binary addresses in big-endian format, as a series of 5-byte fields - * @param count Number of addresses - * @param totalKnown Total number of known addresses as reported by peer - */ - void addMultiple(void *tPtr,int64_t now,uint64_t nwid,const MulticastGroup &mg,const void *addresses,unsigned int count,unsigned int totalKnown); + /** + * Add multiple addresses from a binary array of 5-byte address fields + * + * It's up to the caller to check bounds on the array before calling this. + * + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call + * @param now Current time + * @param nwid Network ID + * @param mg Multicast group + * @param addresses Raw binary addresses in big-endian format, as a series of 5-byte fields + * @param count Number of addresses + * @param totalKnown Total number of known addresses as reported by peer + */ + void addMultiple(void* tPtr, int64_t now, uint64_t nwid, const MulticastGroup& mg, const void* addresses, unsigned int count, unsigned int totalKnown); - /** - * Remove a multicast group member (if present) - * - * @param nwid Network ID - * @param mg Multicast group - * @param member Member to unsubscribe - */ - void remove(uint64_t nwid,const MulticastGroup &mg,const Address &member); + /** + * Remove a multicast group member (if present) + * + * @param nwid Network ID + * @param mg Multicast group + * @param member Member to unsubscribe + */ + void remove(uint64_t nwid, const MulticastGroup& mg, const Address& member); - /** - * Append gather results to a packet by choosing registered multicast recipients at random - * - * This appends the following fields to the packet: - * <[4] 32-bit total number of known members in this multicast group> - * <[2] 16-bit number of members enumerated in this packet> - * <[...] series of 5-byte ZeroTier addresses of enumerated members> - * - * If zero is returned, the first two fields will still have been appended. - * - * @param queryingPeer Peer asking for gather (to skip in results) - * @param nwid Network ID - * @param mg Multicast group - * @param appendTo Packet to append to - * @param limit Maximum number of 5-byte addresses to append - * @return Number of addresses appended - * @throws std::out_of_range Buffer overflow writing to packet - */ - unsigned int gather(const Address &queryingPeer,uint64_t nwid,const MulticastGroup &mg,Buffer &appendTo,unsigned int limit) const; + /** + * Append gather results to a packet by choosing registered multicast recipients at random + * + * This appends the following fields to the packet: + * <[4] 32-bit total number of known members in this multicast group> + * <[2] 16-bit number of members enumerated in this packet> + * <[...] series of 5-byte ZeroTier addresses of enumerated members> + * + * If zero is returned, the first two fields will still have been appended. + * + * @param queryingPeer Peer asking for gather (to skip in results) + * @param nwid Network ID + * @param mg Multicast group + * @param appendTo Packet to append to + * @param limit Maximum number of 5-byte addresses to append + * @return Number of addresses appended + * @throws std::out_of_range Buffer overflow writing to packet + */ + unsigned int gather(const Address& queryingPeer, uint64_t nwid, const MulticastGroup& mg, Buffer& appendTo, unsigned int limit) const; - /** - * Get subscribers to a multicast group - * - * @param nwid Network ID - * @param mg Multicast group - */ - std::vector
getMembers(uint64_t nwid,const MulticastGroup &mg,unsigned int limit) const; + /** + * Get subscribers to a multicast group + * + * @param nwid Network ID + * @param mg Multicast group + */ + std::vector
getMembers(uint64_t nwid, const MulticastGroup& mg, unsigned int limit) const; - /** - * Send a multicast - * - * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call - * @param now Current time - * @param network Network - * @param origin Origin of multicast (to not return to sender) or NULL if none - * @param mg Multicast group - * @param src Source Ethernet MAC address or NULL to skip in packet and compute from ZT address (non-bridged mode) - * @param etherType Ethernet frame type - * @param data Packet data - * @param len Length of packet data - */ - void send( - void *tPtr, - int64_t now, - const SharedPtr &network, - const Address &origin, - const MulticastGroup &mg, - const MAC &src, - unsigned int etherType, - const void *data, - unsigned int len); + /** + * Send a multicast + * + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call + * @param now Current time + * @param network Network + * @param origin Origin of multicast (to not return to sender) or NULL if none + * @param mg Multicast group + * @param src Source Ethernet MAC address or NULL to skip in packet and compute from ZT address (non-bridged mode) + * @param etherType Ethernet frame type + * @param data Packet data + * @param len Length of packet data + */ + void send(void* tPtr, int64_t now, const SharedPtr& network, const Address& origin, const MulticastGroup& mg, const MAC& src, unsigned int etherType, const void* data, unsigned int len); - /** - * Clean database - * - * @param RR Runtime environment - * @param now Current time - */ - void clean(int64_t now); + /** + * Clean database + * + * @param RR Runtime environment + * @param now Current time + */ + void clean(int64_t now); -private: - struct Key - { - Key() : nwid(0),mg() {} - Key(uint64_t n,const MulticastGroup &g) : nwid(n),mg(g) {} + private: + struct Key { + Key() : nwid(0), mg() + { + } + Key(uint64_t n, const MulticastGroup& g) : nwid(n), mg(g) + { + } - uint64_t nwid; - MulticastGroup mg; + uint64_t nwid; + MulticastGroup mg; - inline bool operator==(const Key &k) const { return ((nwid == k.nwid)&&(mg == k.mg)); } - inline bool operator!=(const Key &k) const { return ((nwid != k.nwid)||(mg != k.mg)); } - inline unsigned long hashCode() const { return (mg.hashCode() ^ (unsigned long)(nwid ^ (nwid >> 32))); } - }; + inline bool operator==(const Key& k) const + { + return ((nwid == k.nwid) && (mg == k.mg)); + } + inline bool operator!=(const Key& k) const + { + return ((nwid != k.nwid) || (mg != k.mg)); + } + inline unsigned long hashCode() const + { + return (mg.hashCode() ^ (unsigned long)(nwid ^ (nwid >> 32))); + } + }; - struct MulticastGroupMember - { - MulticastGroupMember() {} - MulticastGroupMember(const Address &a,uint64_t ts) : address(a),timestamp(ts) {} + struct MulticastGroupMember { + MulticastGroupMember() + { + } + MulticastGroupMember(const Address& a, uint64_t ts) : address(a), timestamp(ts) + { + } - inline bool operator<(const MulticastGroupMember &a) const { return (address < a.address); } - inline bool operator==(const MulticastGroupMember &a) const { return (address == a.address); } - inline bool operator!=(const MulticastGroupMember &a) const { return (address != a.address); } - inline bool operator<(const Address &a) const { return (address < a); } - inline bool operator==(const Address &a) const { return (address == a); } - inline bool operator!=(const Address &a) const { return (address != a); } + inline bool operator<(const MulticastGroupMember& a) const + { + return (address < a.address); + } + inline bool operator==(const MulticastGroupMember& a) const + { + return (address == a.address); + } + inline bool operator!=(const MulticastGroupMember& a) const + { + return (address != a.address); + } + inline bool operator<(const Address& a) const + { + return (address < a); + } + inline bool operator==(const Address& a) const + { + return (address == a); + } + inline bool operator!=(const Address& a) const + { + return (address != a); + } - Address address; - int64_t timestamp; // time of last notification - }; + Address address; + int64_t timestamp; // time of last notification + }; - struct MulticastGroupStatus - { - MulticastGroupStatus() : lastExplicitGather(0) {} + struct MulticastGroupStatus { + MulticastGroupStatus() : lastExplicitGather(0) + { + } - int64_t lastExplicitGather; - std::list txQueue; // pending outbound multicasts - std::vector members; // members of this group - }; + int64_t lastExplicitGather; + std::list txQueue; // pending outbound multicasts + std::vector members; // members of this group + }; - void _add(void *tPtr,int64_t now,uint64_t nwid,const MulticastGroup &mg,MulticastGroupStatus &gs,const Address &member); + void _add(void* tPtr, int64_t now, uint64_t nwid, const MulticastGroup& mg, MulticastGroupStatus& gs, const Address& member); - const RuntimeEnvironment *const RR; + const RuntimeEnvironment* const RR; - Hashtable _groups; - Mutex _groups_m; + Hashtable _groups; + Mutex _groups_m; }; -} // namespace ZeroTier +} // namespace ZeroTier #endif diff --git a/node/Mutex.hpp b/node/Mutex.hpp index 8c5be7a8..4597c698 100644 --- a/node/Mutex.hpp +++ b/node/Mutex.hpp @@ -18,68 +18,69 @@ #ifdef __UNIX_LIKE__ +#include #include #include -#include namespace ZeroTier { // libpthread based mutex lock -class Mutex -{ -public: - Mutex() - { - pthread_mutex_init(&_mh,(const pthread_mutexattr_t *)0); - } +class Mutex { + public: + Mutex() + { + pthread_mutex_init(&_mh, (const pthread_mutexattr_t*)0); + } - ~Mutex() - { - pthread_mutex_destroy(&_mh); - } + ~Mutex() + { + pthread_mutex_destroy(&_mh); + } - inline void lock() const - { - pthread_mutex_lock(&((const_cast (this))->_mh)); - } + inline void lock() const + { + pthread_mutex_lock(&((const_cast(this))->_mh)); + } - inline void unlock() const - { - pthread_mutex_unlock(&((const_cast (this))->_mh)); - } + inline void unlock() const + { + pthread_mutex_unlock(&((const_cast(this))->_mh)); + } - class Lock - { - public: - Lock(Mutex &m) : - _m(&m) - { - m.lock(); - } + class Lock { + public: + Lock(Mutex& m) : _m(&m) + { + m.lock(); + } - Lock(const Mutex &m) : - _m(const_cast(&m)) - { - _m->lock(); - } + Lock(const Mutex& m) : _m(const_cast(&m)) + { + _m->lock(); + } - ~Lock() - { - _m->unlock(); - } + ~Lock() + { + _m->unlock(); + } - private: - Mutex *const _m; - }; + private: + Mutex* const _m; + }; -private: - Mutex(const Mutex &) {} - const Mutex &operator=(const Mutex &) { return *this; } + private: + Mutex(const Mutex&) + { + } + const Mutex& operator=(const Mutex&) + { + return *this; + } - pthread_mutex_t _mh; + pthread_mutex_t _mh; }; -} // namespace ZeroTier +} // namespace ZeroTier #endif @@ -91,72 +92,73 @@ private: namespace ZeroTier { // Windows critical section based lock -class Mutex -{ -public: - Mutex() - { - InitializeCriticalSection(&_cs); - } +class Mutex { + public: + Mutex() + { + InitializeCriticalSection(&_cs); + } - ~Mutex() - { - DeleteCriticalSection(&_cs); - } + ~Mutex() + { + DeleteCriticalSection(&_cs); + } - inline void lock() - { - EnterCriticalSection(&_cs); - } + inline void lock() + { + EnterCriticalSection(&_cs); + } - inline void unlock() - { - LeaveCriticalSection(&_cs); - } + inline void unlock() + { + LeaveCriticalSection(&_cs); + } - inline void lock() const - { - (const_cast (this))->lock(); - } + inline void lock() const + { + (const_cast(this))->lock(); + } - inline void unlock() const - { - (const_cast (this))->unlock(); - } + inline void unlock() const + { + (const_cast(this))->unlock(); + } - class Lock - { - public: - Lock(Mutex &m) : - _m(&m) - { - m.lock(); - } + class Lock { + public: + Lock(Mutex& m) : _m(&m) + { + m.lock(); + } - Lock(const Mutex &m) : - _m(const_cast(&m)) - { - _m->lock(); - } + Lock(const Mutex& m) : _m(const_cast(&m)) + { + _m->lock(); + } - ~Lock() - { - _m->unlock(); - } + ~Lock() + { + _m->unlock(); + } - private: - Mutex *const _m; - }; + private: + Mutex* const _m; + }; -private: - Mutex(const Mutex &) {} - const Mutex &operator=(const Mutex &) { return *this; } + private: + Mutex(const Mutex&) + { + } + const Mutex& operator=(const Mutex&) + { + return *this; + } - CRITICAL_SECTION _cs; + CRITICAL_SECTION _cs; }; -} // namespace ZeroTier +} // namespace ZeroTier -#endif // _WIN32 +#endif // _WIN32 #endif diff --git a/node/Network.cpp b/node/Network.cpp index 1643487f..abec3a21 100644 --- a/node/Network.cpp +++ b/node/Network.cpp @@ -11,1713 +11,1853 @@ */ /****/ -#include -#include -#include -#include +#include "Network.hpp" #include "../include/ZeroTierDebug.h" - -#include "Constants.hpp" #include "../version.h" -#include "Network.hpp" -#include "RuntimeEnvironment.hpp" -#include "MAC.hpp" #include "Address.hpp" -#include "InetAddress.hpp" -#include "Switch.hpp" #include "Buffer.hpp" -#include "Packet.hpp" +#include "Constants.hpp" +#include "ECC.hpp" +#include "InetAddress.hpp" +#include "MAC.hpp" +#include "Metrics.hpp" #include "NetworkController.hpp" #include "Node.hpp" +#include "Packet.hpp" #include "Peer.hpp" +#include "RuntimeEnvironment.hpp" +#include "Switch.hpp" #include "Trace.hpp" -#include "Metrics.hpp" +#include #include +#include +#include +#include namespace ZeroTier { namespace { // Returns true if packet appears valid; pos and proto will be set -static inline bool _ipv6GetPayload(const uint8_t *frameData,unsigned int frameLen,unsigned int &pos,unsigned int &proto) +static inline bool _ipv6GetPayload(const uint8_t* frameData, unsigned int frameLen, unsigned int& pos, unsigned int& proto) { - if (frameLen < 40) { - return false; - } - pos = 40; - proto = frameData[6]; - while (pos <= frameLen) { - switch(proto) { - case 0: // hop-by-hop options - case 43: // routing - case 60: // destination options - case 135: // mobility options - if ((pos + 8) > frameLen) { - return false; // invalid! - } - proto = frameData[pos]; - pos += ((unsigned int)frameData[pos + 1] * 8) + 8; - break; + if (frameLen < 40) { + return false; + } + pos = 40; + proto = frameData[6]; + while (pos <= frameLen) { + switch (proto) { + case 0: // hop-by-hop options + case 43: // routing + case 60: // destination options + case 135: // mobility options + if ((pos + 8) > frameLen) { + return false; // invalid! + } + proto = frameData[pos]; + pos += ((unsigned int)frameData[pos + 1] * 8) + 8; + break; - //case 44: // fragment -- we currently can't parse these and they are deprecated in IPv6 anyway - //case 50: - //case 51: // IPSec ESP and AH -- we have to stop here since this is encrypted stuff - default: - return true; - } - } - return false; // overflow == invalid + // case 44: // fragment -- we currently can't parse these and they are deprecated in IPv6 anyway + // case 50: + // case 51: // IPSec ESP and AH -- we have to stop here since this is encrypted stuff + default: + return true; + } + } + return false; // overflow == invalid } -enum _doZtFilterResult -{ - DOZTFILTER_NO_MATCH, - DOZTFILTER_DROP, - DOZTFILTER_REDIRECT, - DOZTFILTER_ACCEPT, - DOZTFILTER_SUPER_ACCEPT -}; +enum _doZtFilterResult { DOZTFILTER_NO_MATCH, DOZTFILTER_DROP, DOZTFILTER_REDIRECT, DOZTFILTER_ACCEPT, DOZTFILTER_SUPER_ACCEPT }; static _doZtFilterResult _doZtFilter( - const RuntimeEnvironment *RR, - Trace::RuleResultLog &rrl, - const NetworkConfig &nconf, - const Membership *membership, // can be NULL - const bool inbound, - const Address &ztSource, - Address &ztDest, // MUTABLE -- is changed on REDIRECT actions - const MAC &macSource, - const MAC &macDest, - const uint8_t *const frameData, - const unsigned int frameLen, - const unsigned int etherType, - const unsigned int vlanId, - const ZT_VirtualNetworkRule *rules, // cannot be NULL - const unsigned int ruleCount, - Address &cc, // MUTABLE -- set to TEE destination if TEE action is taken or left alone otherwise - unsigned int &ccLength, // MUTABLE -- set to length of packet payload to TEE - bool &ccWatch, // MUTABLE -- set to true for WATCH target as opposed to normal TEE - uint8_t &qosBucket) // MUTABLE -- set to the value of the argument provided to PRIORITY + const RuntimeEnvironment* RR, + Trace::RuleResultLog& rrl, + const NetworkConfig& nconf, + const Membership* membership, // can be NULL + const bool inbound, + const Address& ztSource, + Address& ztDest, // MUTABLE -- is changed on REDIRECT actions + const MAC& macSource, + const MAC& macDest, + const uint8_t* const frameData, + const unsigned int frameLen, + const unsigned int etherType, + const unsigned int vlanId, + const ZT_VirtualNetworkRule* rules, // cannot be NULL + const unsigned int ruleCount, + Address& cc, // MUTABLE -- set to TEE destination if TEE action is taken or left alone otherwise + unsigned int& ccLength, // MUTABLE -- set to length of packet payload to TEE + bool& ccWatch, // MUTABLE -- set to true for WATCH target as opposed to normal TEE + uint8_t& qosBucket) // MUTABLE -- set to the value of the argument provided to PRIORITY { - // Set to true if we are a TEE/REDIRECT/WATCH target - bool superAccept = false; + // Set to true if we are a TEE/REDIRECT/WATCH target + bool superAccept = false; - // The default match state for each set of entries starts as 'true' since an - // ACTION with no MATCH entries preceding it is always taken. - uint8_t thisSetMatches = 1; - uint8_t skipDrop = 0; + // The default match state for each set of entries starts as 'true' since an + // ACTION with no MATCH entries preceding it is always taken. + uint8_t thisSetMatches = 1; + uint8_t skipDrop = 0; - rrl.clear(); + rrl.clear(); - // uncomment for easier debugging fprintf - // if (!ztDest) { return DOZTFILTER_ACCEPT; } + // uncomment for easier debugging fprintf + // if (!ztDest) { return DOZTFILTER_ACCEPT; } #ifdef ZT_TRACE - //char buf[40], buf2[40]; - //fprintf(stderr, "\nsrc %s dest %s inbound: %d ethertype %u", ztSource.toString(buf), ztDest.toString(buf2), inbound, etherType); + // char buf[40], buf2[40]; + // fprintf(stderr, "\nsrc %s dest %s inbound: %d ethertype %u", ztSource.toString(buf), ztDest.toString(buf2), inbound, etherType); #endif - for(unsigned int rn=0;rnidentity.address()) { - if (inbound) { - return DOZTFILTER_SUPER_ACCEPT; - } else { - } - } else if (fwdAddr == ztDest) { - } else { - if (rt == ZT_NETWORK_RULE_ACTION_REDIRECT) { - ztDest = fwdAddr; - return DOZTFILTER_REDIRECT; - } else { - cc = fwdAddr; - ccLength = (rules[rn].v.fwd.length != 0) ? ((frameLen < (unsigned int)rules[rn].v.fwd.length) ? frameLen : (unsigned int)rules[rn].v.fwd.length) : frameLen; - ccWatch = (rt == ZT_NETWORK_RULE_ACTION_WATCH); - } - } - } continue; + // These are initially handled together since preliminary logic is common + case ZT_NETWORK_RULE_ACTION_TEE: + case ZT_NETWORK_RULE_ACTION_WATCH: + case ZT_NETWORK_RULE_ACTION_REDIRECT: { + const Address fwdAddr(rules[rn].v.fwd.address); + if (fwdAddr == ztSource) { + // Skip as no-op since source is target + } + else if (fwdAddr == RR->identity.address()) { + if (inbound) { + return DOZTFILTER_SUPER_ACCEPT; + } + else { + } + } + else if (fwdAddr == ztDest) { + } + else { + if (rt == ZT_NETWORK_RULE_ACTION_REDIRECT) { + ztDest = fwdAddr; + return DOZTFILTER_REDIRECT; + } + else { + cc = fwdAddr; + ccLength = (rules[rn].v.fwd.length != 0) ? ((frameLen < (unsigned int)rules[rn].v.fwd.length) ? frameLen : (unsigned int)rules[rn].v.fwd.length) : frameLen; + ccWatch = (rt == ZT_NETWORK_RULE_ACTION_WATCH); + } + } + } + continue; - case ZT_NETWORK_RULE_ACTION_BREAK: - return DOZTFILTER_NO_MATCH; + case ZT_NETWORK_RULE_ACTION_BREAK: + return DOZTFILTER_NO_MATCH; - // Unrecognized ACTIONs are ignored as no-ops - default: - continue; - } - } else { - // If this is an incoming packet and we are a TEE or REDIRECT target, we should - // super-accept if we accept at all. This will cause us to accept redirected or - // tee'd packets in spite of MAC and ZT addressing checks. - if (inbound) { - switch(rt) { - case ZT_NETWORK_RULE_ACTION_TEE: - case ZT_NETWORK_RULE_ACTION_WATCH: - case ZT_NETWORK_RULE_ACTION_REDIRECT: - if (RR->identity.address() == rules[rn].v.fwd.address) { - superAccept = true; - } - break; - default: - break; - } - } + // Unrecognized ACTIONs are ignored as no-ops + default: + continue; + } + } + else { + // If this is an incoming packet and we are a TEE or REDIRECT target, we should + // super-accept if we accept at all. This will cause us to accept redirected or + // tee'd packets in spite of MAC and ZT addressing checks. + if (inbound) { + switch (rt) { + case ZT_NETWORK_RULE_ACTION_TEE: + case ZT_NETWORK_RULE_ACTION_WATCH: + case ZT_NETWORK_RULE_ACTION_REDIRECT: + if (RR->identity.address() == rules[rn].v.fwd.address) { + superAccept = true; + } + break; + default: + break; + } + } - thisSetMatches = 1; // reset to default true for next batch of entries - continue; - } - } + thisSetMatches = 1; // reset to default true for next batch of entries + continue; + } + } - // Circuit breaker: no need to evaluate an AND if the set's match state - // is currently false since anything AND false is false. - if ((!thisSetMatches)&&(!(rules[rn].t & 0x40))) { - rrl.logSkipped(rn,thisSetMatches); - continue; - } + // Circuit breaker: no need to evaluate an AND if the set's match state + // is currently false since anything AND false is false. + if ((! thisSetMatches) && (! (rules[rn].t & 0x40))) { + rrl.logSkipped(rn, thisSetMatches); + continue; + } - // If this was not an ACTION evaluate next MATCH and update thisSetMatches with (AND [result]) - uint8_t thisRuleMatches = 0; - uint64_t ownershipVerificationMask = 1; // this magic value means it hasn't been computed yet -- this is done lazily the first time it's needed - uint8_t hardYes = (rules[rn].t >> 7) ^ 1; // XOR with the NOT bit of the rule - uint8_t hardNo = (rules[rn].t >> 7) ^ 0; + // If this was not an ACTION evaluate next MATCH and update thisSetMatches with (AND [result]) + uint8_t thisRuleMatches = 0; + uint64_t ownershipVerificationMask = 1; // this magic value means it hasn't been computed yet -- this is done lazily the first time it's needed + uint8_t hardYes = (rules[rn].t >> 7) ^ 1; // XOR with the NOT bit of the rule + uint8_t hardNo = (rules[rn].t >> 7) ^ 0; - switch(rt) { - case ZT_NETWORK_RULE_MATCH_SOURCE_ZEROTIER_ADDRESS: - thisRuleMatches = (uint8_t)(rules[rn].v.zt == ztSource.toInt()); - break; - case ZT_NETWORK_RULE_MATCH_DEST_ZEROTIER_ADDRESS: - thisRuleMatches = (uint8_t)(rules[rn].v.zt == ztDest.toInt()); - break; - case ZT_NETWORK_RULE_MATCH_VLAN_ID: - thisRuleMatches = (uint8_t)(rules[rn].v.vlanId == (uint16_t)vlanId); - break; - case ZT_NETWORK_RULE_MATCH_VLAN_PCP: - // NOT SUPPORTED YET - thisRuleMatches = (uint8_t)(rules[rn].v.vlanPcp == 0); - break; - case ZT_NETWORK_RULE_MATCH_VLAN_DEI: - // NOT SUPPORTED YET - thisRuleMatches = (uint8_t)(rules[rn].v.vlanDei == 0); - break; - case ZT_NETWORK_RULE_MATCH_MAC_SOURCE: - thisRuleMatches = (uint8_t)(MAC(rules[rn].v.mac,6) == macSource); - break; - case ZT_NETWORK_RULE_MATCH_MAC_DEST: - thisRuleMatches = (uint8_t)(MAC(rules[rn].v.mac,6) == macDest); - break; - case ZT_NETWORK_RULE_MATCH_IPV4_SOURCE: - if ((etherType == ZT_ETHERTYPE_IPV4)&&(frameLen >= 20)) { - thisRuleMatches = (uint8_t)(InetAddress((const void *)&(rules[rn].v.ipv4.ip),4,rules[rn].v.ipv4.mask).containsAddress(InetAddress((const void *)(frameData + 12),4,0))); - } else { - thisRuleMatches = hardNo; - } - break; - case ZT_NETWORK_RULE_MATCH_IPV4_DEST: - if ((etherType == ZT_ETHERTYPE_IPV4)&&(frameLen >= 20)) { - thisRuleMatches = (uint8_t)(InetAddress((const void *)&(rules[rn].v.ipv4.ip),4,rules[rn].v.ipv4.mask).containsAddress(InetAddress((const void *)(frameData + 16),4,0))); - } else { - thisRuleMatches = hardNo; - } - break; - case ZT_NETWORK_RULE_MATCH_IPV6_SOURCE: - if ((etherType == ZT_ETHERTYPE_IPV6)&&(frameLen >= 40)) { - thisRuleMatches = (uint8_t)(InetAddress((const void *)rules[rn].v.ipv6.ip,16,rules[rn].v.ipv6.mask).containsAddress(InetAddress((const void *)(frameData + 8),16,0))); - } else { - thisRuleMatches = hardNo; - } - break; - case ZT_NETWORK_RULE_MATCH_IPV6_DEST: - if ((etherType == ZT_ETHERTYPE_IPV6)&&(frameLen >= 40)) { - thisRuleMatches = (uint8_t)(InetAddress((const void *)rules[rn].v.ipv6.ip,16,rules[rn].v.ipv6.mask).containsAddress(InetAddress((const void *)(frameData + 24),16,0))); - } else { - thisRuleMatches = hardNo; - } - break; - case ZT_NETWORK_RULE_MATCH_IP_TOS: - if ((etherType == ZT_ETHERTYPE_IPV4)&&(frameLen >= 20)) { - const uint8_t tosMasked = frameData[1] & rules[rn].v.ipTos.mask; - thisRuleMatches = (uint8_t)((tosMasked >= rules[rn].v.ipTos.value[0])&&(tosMasked <= rules[rn].v.ipTos.value[1])); - } else if ((etherType == ZT_ETHERTYPE_IPV6)&&(frameLen >= 40)) { - const uint8_t tosMasked = (((frameData[0] << 4) & 0xf0) | ((frameData[1] >> 4) & 0x0f)) & rules[rn].v.ipTos.mask; - thisRuleMatches = (uint8_t)((tosMasked >= rules[rn].v.ipTos.value[0])&&(tosMasked <= rules[rn].v.ipTos.value[1])); - } else { - thisRuleMatches = hardNo; - } - break; - case ZT_NETWORK_RULE_MATCH_IP_PROTOCOL: - if ((etherType == ZT_ETHERTYPE_IPV4)&&(frameLen >= 20)) { - thisRuleMatches = (uint8_t)(rules[rn].v.ipProtocol == frameData[9]); - } else if (etherType == ZT_ETHERTYPE_IPV6) { - unsigned int pos = 0,proto = 0; - if (_ipv6GetPayload(frameData,frameLen,pos,proto)) { - thisRuleMatches = (uint8_t)(rules[rn].v.ipProtocol == (uint8_t)proto); - } else { - thisRuleMatches = hardNo; - } - } else { - thisRuleMatches = hardNo; - } - break; - case ZT_NETWORK_RULE_MATCH_ETHERTYPE: - thisRuleMatches = (uint8_t)(rules[rn].v.etherType == (uint16_t)etherType); - break; - case ZT_NETWORK_RULE_MATCH_ICMP: - if ((etherType == ZT_ETHERTYPE_IPV4)&&(frameLen >= 20)) { - if (frameData[9] == 0x01) { // IP protocol == ICMP - const unsigned int ihl = (frameData[0] & 0xf) * 4; - if (frameLen >= (ihl + 2)) { - if (rules[rn].v.icmp.type == frameData[ihl]) { - if ((rules[rn].v.icmp.flags & 0x01) != 0) { - thisRuleMatches = (uint8_t)(frameData[ihl+1] == rules[rn].v.icmp.code); - } else { - thisRuleMatches = hardYes; - } - } else { - thisRuleMatches = hardNo; - } - } else { - thisRuleMatches = hardNo; - } - } else { - thisRuleMatches = hardNo; - } - } else if (etherType == ZT_ETHERTYPE_IPV6) { - unsigned int pos = 0,proto = 0; - if (_ipv6GetPayload(frameData,frameLen,pos,proto)) { - if ((proto == 0x3a)&&(frameLen >= (pos+2))) { - if (rules[rn].v.icmp.type == frameData[pos]) { - if ((rules[rn].v.icmp.flags & 0x01) != 0) { - thisRuleMatches = (uint8_t)(frameData[pos+1] == rules[rn].v.icmp.code); - } else { - thisRuleMatches = hardYes; - } - } else { - thisRuleMatches = hardNo; - } - } else { - thisRuleMatches = hardNo; - } - } else { - thisRuleMatches = hardNo; - } - } else { - thisRuleMatches = hardNo; - } - break; - case ZT_NETWORK_RULE_MATCH_IP_SOURCE_PORT_RANGE: - case ZT_NETWORK_RULE_MATCH_IP_DEST_PORT_RANGE: - if ((etherType == ZT_ETHERTYPE_IPV4)&&(frameLen >= 20)) { - const unsigned int headerLen = 4 * (frameData[0] & 0xf); - int p = -1; - switch(frameData[9]) { // IP protocol number - // All these start with 16-bit source and destination port in that order - case 0x06: // TCP - case 0x11: // UDP - case 0x84: // SCTP - case 0x88: // UDPLite - if (frameLen > (headerLen + 4)) { - unsigned int pos = headerLen + ((rt == ZT_NETWORK_RULE_MATCH_IP_DEST_PORT_RANGE) ? 2 : 0); - p = (int)frameData[pos++] << 8; - p |= (int)frameData[pos]; - } - break; - } + switch (rt) { + case ZT_NETWORK_RULE_MATCH_SOURCE_ZEROTIER_ADDRESS: + thisRuleMatches = (uint8_t)(rules[rn].v.zt == ztSource.toInt()); + break; + case ZT_NETWORK_RULE_MATCH_DEST_ZEROTIER_ADDRESS: + thisRuleMatches = (uint8_t)(rules[rn].v.zt == ztDest.toInt()); + break; + case ZT_NETWORK_RULE_MATCH_VLAN_ID: + thisRuleMatches = (uint8_t)(rules[rn].v.vlanId == (uint16_t)vlanId); + break; + case ZT_NETWORK_RULE_MATCH_VLAN_PCP: + // NOT SUPPORTED YET + thisRuleMatches = (uint8_t)(rules[rn].v.vlanPcp == 0); + break; + case ZT_NETWORK_RULE_MATCH_VLAN_DEI: + // NOT SUPPORTED YET + thisRuleMatches = (uint8_t)(rules[rn].v.vlanDei == 0); + break; + case ZT_NETWORK_RULE_MATCH_MAC_SOURCE: + thisRuleMatches = (uint8_t)(MAC(rules[rn].v.mac, 6) == macSource); + break; + case ZT_NETWORK_RULE_MATCH_MAC_DEST: + thisRuleMatches = (uint8_t)(MAC(rules[rn].v.mac, 6) == macDest); + break; + case ZT_NETWORK_RULE_MATCH_IPV4_SOURCE: + if ((etherType == ZT_ETHERTYPE_IPV4) && (frameLen >= 20)) { + thisRuleMatches = (uint8_t)(InetAddress((const void*)&(rules[rn].v.ipv4.ip), 4, rules[rn].v.ipv4.mask).containsAddress(InetAddress((const void*)(frameData + 12), 4, 0))); + } + else { + thisRuleMatches = hardNo; + } + break; + case ZT_NETWORK_RULE_MATCH_IPV4_DEST: + if ((etherType == ZT_ETHERTYPE_IPV4) && (frameLen >= 20)) { + thisRuleMatches = (uint8_t)(InetAddress((const void*)&(rules[rn].v.ipv4.ip), 4, rules[rn].v.ipv4.mask).containsAddress(InetAddress((const void*)(frameData + 16), 4, 0))); + } + else { + thisRuleMatches = hardNo; + } + break; + case ZT_NETWORK_RULE_MATCH_IPV6_SOURCE: + if ((etherType == ZT_ETHERTYPE_IPV6) && (frameLen >= 40)) { + thisRuleMatches = (uint8_t)(InetAddress((const void*)rules[rn].v.ipv6.ip, 16, rules[rn].v.ipv6.mask).containsAddress(InetAddress((const void*)(frameData + 8), 16, 0))); + } + else { + thisRuleMatches = hardNo; + } + break; + case ZT_NETWORK_RULE_MATCH_IPV6_DEST: + if ((etherType == ZT_ETHERTYPE_IPV6) && (frameLen >= 40)) { + thisRuleMatches = (uint8_t)(InetAddress((const void*)rules[rn].v.ipv6.ip, 16, rules[rn].v.ipv6.mask).containsAddress(InetAddress((const void*)(frameData + 24), 16, 0))); + } + else { + thisRuleMatches = hardNo; + } + break; + case ZT_NETWORK_RULE_MATCH_IP_TOS: + if ((etherType == ZT_ETHERTYPE_IPV4) && (frameLen >= 20)) { + const uint8_t tosMasked = frameData[1] & rules[rn].v.ipTos.mask; + thisRuleMatches = (uint8_t)((tosMasked >= rules[rn].v.ipTos.value[0]) && (tosMasked <= rules[rn].v.ipTos.value[1])); + } + else if ((etherType == ZT_ETHERTYPE_IPV6) && (frameLen >= 40)) { + const uint8_t tosMasked = (((frameData[0] << 4) & 0xf0) | ((frameData[1] >> 4) & 0x0f)) & rules[rn].v.ipTos.mask; + thisRuleMatches = (uint8_t)((tosMasked >= rules[rn].v.ipTos.value[0]) && (tosMasked <= rules[rn].v.ipTos.value[1])); + } + else { + thisRuleMatches = hardNo; + } + break; + case ZT_NETWORK_RULE_MATCH_IP_PROTOCOL: + if ((etherType == ZT_ETHERTYPE_IPV4) && (frameLen >= 20)) { + thisRuleMatches = (uint8_t)(rules[rn].v.ipProtocol == frameData[9]); + } + else if (etherType == ZT_ETHERTYPE_IPV6) { + unsigned int pos = 0, proto = 0; + if (_ipv6GetPayload(frameData, frameLen, pos, proto)) { + thisRuleMatches = (uint8_t)(rules[rn].v.ipProtocol == (uint8_t)proto); + } + else { + thisRuleMatches = hardNo; + } + } + else { + thisRuleMatches = hardNo; + } + break; + case ZT_NETWORK_RULE_MATCH_ETHERTYPE: + thisRuleMatches = (uint8_t)(rules[rn].v.etherType == (uint16_t)etherType); + break; + case ZT_NETWORK_RULE_MATCH_ICMP: + if ((etherType == ZT_ETHERTYPE_IPV4) && (frameLen >= 20)) { + if (frameData[9] == 0x01) { // IP protocol == ICMP + const unsigned int ihl = (frameData[0] & 0xf) * 4; + if (frameLen >= (ihl + 2)) { + if (rules[rn].v.icmp.type == frameData[ihl]) { + if ((rules[rn].v.icmp.flags & 0x01) != 0) { + thisRuleMatches = (uint8_t)(frameData[ihl + 1] == rules[rn].v.icmp.code); + } + else { + thisRuleMatches = hardYes; + } + } + else { + thisRuleMatches = hardNo; + } + } + else { + thisRuleMatches = hardNo; + } + } + else { + thisRuleMatches = hardNo; + } + } + else if (etherType == ZT_ETHERTYPE_IPV6) { + unsigned int pos = 0, proto = 0; + if (_ipv6GetPayload(frameData, frameLen, pos, proto)) { + if ((proto == 0x3a) && (frameLen >= (pos + 2))) { + if (rules[rn].v.icmp.type == frameData[pos]) { + if ((rules[rn].v.icmp.flags & 0x01) != 0) { + thisRuleMatches = (uint8_t)(frameData[pos + 1] == rules[rn].v.icmp.code); + } + else { + thisRuleMatches = hardYes; + } + } + else { + thisRuleMatches = hardNo; + } + } + else { + thisRuleMatches = hardNo; + } + } + else { + thisRuleMatches = hardNo; + } + } + else { + thisRuleMatches = hardNo; + } + break; + case ZT_NETWORK_RULE_MATCH_IP_SOURCE_PORT_RANGE: + case ZT_NETWORK_RULE_MATCH_IP_DEST_PORT_RANGE: + if ((etherType == ZT_ETHERTYPE_IPV4) && (frameLen >= 20)) { + const unsigned int headerLen = 4 * (frameData[0] & 0xf); + int p = -1; + switch (frameData[9]) { // IP protocol number + // All these start with 16-bit source and destination port in that order + case 0x06: // TCP + case 0x11: // UDP + case 0x84: // SCTP + case 0x88: // UDPLite + if (frameLen > (headerLen + 4)) { + unsigned int pos = headerLen + ((rt == ZT_NETWORK_RULE_MATCH_IP_DEST_PORT_RANGE) ? 2 : 0); + p = (int)frameData[pos++] << 8; + p |= (int)frameData[pos]; + } + break; + } - thisRuleMatches = (p >= 0) ? (uint8_t)((p >= (int)rules[rn].v.port[0])&&(p <= (int)rules[rn].v.port[1])) : (uint8_t)0; - } else if (etherType == ZT_ETHERTYPE_IPV6) { - unsigned int pos = 0,proto = 0; - if (_ipv6GetPayload(frameData,frameLen,pos,proto)) { - int p = -1; - switch(proto) { // IP protocol number - // All these start with 16-bit source and destination port in that order - case 0x06: // TCP - case 0x11: // UDP - case 0x84: // SCTP - case 0x88: // UDPLite - if (frameLen > (pos + 4)) { - if (rt == ZT_NETWORK_RULE_MATCH_IP_DEST_PORT_RANGE) { - pos += 2; - } - p = (int)frameData[pos++] << 8; - p |= (int)frameData[pos]; - } - break; - } - thisRuleMatches = (p > 0) ? (uint8_t)((p >= (int)rules[rn].v.port[0])&&(p <= (int)rules[rn].v.port[1])) : (uint8_t)0; - } else { - thisRuleMatches = hardNo; - } - } else { - thisRuleMatches = hardNo; - } - break; - case ZT_NETWORK_RULE_MATCH_CHARACTERISTICS: { - uint64_t cf = (inbound) ? ZT_RULE_PACKET_CHARACTERISTICS_INBOUND : 0ULL; - if (macDest.isMulticast()) { - cf |= ZT_RULE_PACKET_CHARACTERISTICS_MULTICAST; - } - if (macDest.isBroadcast()) { - cf |= ZT_RULE_PACKET_CHARACTERISTICS_BROADCAST; - } - if (ownershipVerificationMask == 1) { - ownershipVerificationMask = 0; - InetAddress src; - if ((etherType == ZT_ETHERTYPE_IPV4)&&(frameLen >= 20)) { - src.set((const void *)(frameData + 12),4,0); - } else if ((etherType == ZT_ETHERTYPE_IPV6)&&(frameLen >= 40)) { - // IPv6 NDP requires special handling, since the src and dest IPs in the packet are empty or link-local. - if ( (frameLen >= (40 + 8 + 16)) && (frameData[6] == 0x3a) && ((frameData[40] == 0x87)||(frameData[40] == 0x88)) ) { - if (frameData[40] == 0x87) { - // Neighbor solicitations contain no reliable source address, so we implement a small - // hack by considering them authenticated. Otherwise you would pretty much have to do - // this manually in the rule set for IPv6 to work at all. - ownershipVerificationMask |= ZT_RULE_PACKET_CHARACTERISTICS_SENDER_IP_AUTHENTICATED; - } else { - // Neighbor advertisements on the other hand can absolutely be authenticated. - src.set((const void *)(frameData + 40 + 8),16,0); - } - } else { - // Other IPv6 packets can be handled normally - src.set((const void *)(frameData + 8),16,0); - } - } else if ((etherType == ZT_ETHERTYPE_ARP)&&(frameLen >= 28)) { - src.set((const void *)(frameData + 14),4,0); - } - if (inbound) { - if (membership) { - if ((src)&&(membership->hasCertificateOfOwnershipFor(nconf,src))) { - ownershipVerificationMask |= ZT_RULE_PACKET_CHARACTERISTICS_SENDER_IP_AUTHENTICATED; - } - if (membership->hasCertificateOfOwnershipFor(nconf,macSource)) { - ownershipVerificationMask |= ZT_RULE_PACKET_CHARACTERISTICS_SENDER_MAC_AUTHENTICATED; - } - } - } else { - for(unsigned int i=0;i= 20)&&(frameData[9] == 0x06)) { - const unsigned int headerLen = 4 * (frameData[0] & 0xf); - cf |= (uint64_t)frameData[headerLen + 13]; - cf |= (((uint64_t)(frameData[headerLen + 12] & 0x0f)) << 8); - } else if (etherType == ZT_ETHERTYPE_IPV6) { - unsigned int pos = 0,proto = 0; - if (_ipv6GetPayload(frameData,frameLen,pos,proto)) { - if ((proto == 0x06)&&(frameLen > (pos + 14))) { - cf |= (uint64_t)frameData[pos + 13]; - cf |= (((uint64_t)(frameData[pos + 12] & 0x0f)) << 8); - } - } - } - thisRuleMatches = (uint8_t)((cf & rules[rn].v.characteristics) != 0); - } break; - case ZT_NETWORK_RULE_MATCH_FRAME_SIZE_RANGE: - thisRuleMatches = (uint8_t)((frameLen >= (unsigned int)rules[rn].v.frameSize[0])&&(frameLen <= (unsigned int)rules[rn].v.frameSize[1])); - break; - case ZT_NETWORK_RULE_MATCH_RANDOM: - thisRuleMatches = (uint8_t)((uint32_t)(RR->node->prng() & 0xffffffffULL) <= rules[rn].v.randomProbability); - break; - case ZT_NETWORK_RULE_MATCH_TAGS_DIFFERENCE: - case ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_AND: - case ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_OR: - case ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_XOR: - case ZT_NETWORK_RULE_MATCH_TAGS_EQUAL: { - const Tag *const localTag = std::lower_bound(&(nconf.tags[0]),&(nconf.tags[nconf.tagCount]),rules[rn].v.tag.id,Tag::IdComparePredicate()); - if ((localTag != &(nconf.tags[nconf.tagCount]))&&(localTag->id() == rules[rn].v.tag.id)) { - const Tag *const remoteTag = ((membership) ? membership->getTag(nconf,rules[rn].v.tag.id) : (const Tag *)0); + thisRuleMatches = (p >= 0) ? (uint8_t)((p >= (int)rules[rn].v.port[0]) && (p <= (int)rules[rn].v.port[1])) : (uint8_t)0; + } + else if (etherType == ZT_ETHERTYPE_IPV6) { + unsigned int pos = 0, proto = 0; + if (_ipv6GetPayload(frameData, frameLen, pos, proto)) { + int p = -1; + switch (proto) { // IP protocol number + // All these start with 16-bit source and destination port in that order + case 0x06: // TCP + case 0x11: // UDP + case 0x84: // SCTP + case 0x88: // UDPLite + if (frameLen > (pos + 4)) { + if (rt == ZT_NETWORK_RULE_MATCH_IP_DEST_PORT_RANGE) { + pos += 2; + } + p = (int)frameData[pos++] << 8; + p |= (int)frameData[pos]; + } + break; + } + thisRuleMatches = (p > 0) ? (uint8_t)((p >= (int)rules[rn].v.port[0]) && (p <= (int)rules[rn].v.port[1])) : (uint8_t)0; + } + else { + thisRuleMatches = hardNo; + } + } + else { + thisRuleMatches = hardNo; + } + break; + case ZT_NETWORK_RULE_MATCH_CHARACTERISTICS: { + uint64_t cf = (inbound) ? ZT_RULE_PACKET_CHARACTERISTICS_INBOUND : 0ULL; + if (macDest.isMulticast()) { + cf |= ZT_RULE_PACKET_CHARACTERISTICS_MULTICAST; + } + if (macDest.isBroadcast()) { + cf |= ZT_RULE_PACKET_CHARACTERISTICS_BROADCAST; + } + if (ownershipVerificationMask == 1) { + ownershipVerificationMask = 0; + InetAddress src; + if ((etherType == ZT_ETHERTYPE_IPV4) && (frameLen >= 20)) { + src.set((const void*)(frameData + 12), 4, 0); + } + else if ((etherType == ZT_ETHERTYPE_IPV6) && (frameLen >= 40)) { + // IPv6 NDP requires special handling, since the src and dest IPs in the packet are empty or link-local. + if ((frameLen >= (40 + 8 + 16)) && (frameData[6] == 0x3a) && ((frameData[40] == 0x87) || (frameData[40] == 0x88))) { + if (frameData[40] == 0x87) { + // Neighbor solicitations contain no reliable source address, so we implement a small + // hack by considering them authenticated. Otherwise you would pretty much have to do + // this manually in the rule set for IPv6 to work at all. + ownershipVerificationMask |= ZT_RULE_PACKET_CHARACTERISTICS_SENDER_IP_AUTHENTICATED; + } + else { + // Neighbor advertisements on the other hand can absolutely be authenticated. + src.set((const void*)(frameData + 40 + 8), 16, 0); + } + } + else { + // Other IPv6 packets can be handled normally + src.set((const void*)(frameData + 8), 16, 0); + } + } + else if ((etherType == ZT_ETHERTYPE_ARP) && (frameLen >= 28)) { + src.set((const void*)(frameData + 14), 4, 0); + } + if (inbound) { + if (membership) { + if ((src) && (membership->hasCertificateOfOwnershipFor(nconf, src))) { + ownershipVerificationMask |= ZT_RULE_PACKET_CHARACTERISTICS_SENDER_IP_AUTHENTICATED; + } + if (membership->hasCertificateOfOwnershipFor(nconf, macSource)) { + ownershipVerificationMask |= ZT_RULE_PACKET_CHARACTERISTICS_SENDER_MAC_AUTHENTICATED; + } + } + } + else { + for (unsigned int i = 0; i < nconf.certificateOfOwnershipCount; ++i) { + if ((src) && (nconf.certificatesOfOwnership[i].owns(src))) { + ownershipVerificationMask |= ZT_RULE_PACKET_CHARACTERISTICS_SENDER_IP_AUTHENTICATED; + } + if (nconf.certificatesOfOwnership[i].owns(macSource)) { + ownershipVerificationMask |= ZT_RULE_PACKET_CHARACTERISTICS_SENDER_MAC_AUTHENTICATED; + } + } + } + } + cf |= ownershipVerificationMask; + if ((etherType == ZT_ETHERTYPE_IPV4) && (frameLen >= 20) && (frameData[9] == 0x06)) { + const unsigned int headerLen = 4 * (frameData[0] & 0xf); + cf |= (uint64_t)frameData[headerLen + 13]; + cf |= (((uint64_t)(frameData[headerLen + 12] & 0x0f)) << 8); + } + else if (etherType == ZT_ETHERTYPE_IPV6) { + unsigned int pos = 0, proto = 0; + if (_ipv6GetPayload(frameData, frameLen, pos, proto)) { + if ((proto == 0x06) && (frameLen > (pos + 14))) { + cf |= (uint64_t)frameData[pos + 13]; + cf |= (((uint64_t)(frameData[pos + 12] & 0x0f)) << 8); + } + } + } + thisRuleMatches = (uint8_t)((cf & rules[rn].v.characteristics) != 0); + } break; + case ZT_NETWORK_RULE_MATCH_FRAME_SIZE_RANGE: + thisRuleMatches = (uint8_t)((frameLen >= (unsigned int)rules[rn].v.frameSize[0]) && (frameLen <= (unsigned int)rules[rn].v.frameSize[1])); + break; + case ZT_NETWORK_RULE_MATCH_RANDOM: + thisRuleMatches = (uint8_t)((uint32_t)(RR->node->prng() & 0xffffffffULL) <= rules[rn].v.randomProbability); + break; + case ZT_NETWORK_RULE_MATCH_TAGS_DIFFERENCE: + case ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_AND: + case ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_OR: + case ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_XOR: + case ZT_NETWORK_RULE_MATCH_TAGS_EQUAL: { + const Tag* const localTag = std::lower_bound(&(nconf.tags[0]), &(nconf.tags[nconf.tagCount]), rules[rn].v.tag.id, Tag::IdComparePredicate()); + if ((localTag != &(nconf.tags[nconf.tagCount])) && (localTag->id() == rules[rn].v.tag.id)) { + const Tag* const remoteTag = ((membership) ? membership->getTag(nconf, rules[rn].v.tag.id) : (const Tag*)0); #ifdef ZT_TRACE - /*fprintf(stderr, "\tlocal tag [%u: %u] remote tag [%u: %u] match [%u]", - !!localTag ? localTag->id() : 0, - !!localTag ? localTag->value() : 0, - !!remoteTag ? remoteTag->id() : 0, - !!remoteTag ? remoteTag->value() : 0, - thisRuleMatches);*/ + /*fprintf(stderr, "\tlocal tag [%u: %u] remote tag [%u: %u] match [%u]", + !!localTag ? localTag->id() : 0, + !!localTag ? localTag->value() : 0, + !!remoteTag ? remoteTag->id() : 0, + !!remoteTag ? remoteTag->value() : 0, + thisRuleMatches);*/ #endif - if (remoteTag) { - const uint32_t ltv = localTag->value(); - const uint32_t rtv = remoteTag->value(); - if (rt == ZT_NETWORK_RULE_MATCH_TAGS_DIFFERENCE) { - const uint32_t diff = (ltv > rtv) ? (ltv - rtv) : (rtv - ltv); - thisRuleMatches = (uint8_t)(diff <= rules[rn].v.tag.value); - } else if (rt == ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_AND) { - thisRuleMatches = (uint8_t)((ltv & rtv) == rules[rn].v.tag.value); - } else if (rt == ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_OR) { - thisRuleMatches = (uint8_t)((ltv | rtv) == rules[rn].v.tag.value); - } else if (rt == ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_XOR) { - thisRuleMatches = (uint8_t)((ltv ^ rtv) == rules[rn].v.tag.value); - } else if (rt == ZT_NETWORK_RULE_MATCH_TAGS_EQUAL) { - thisRuleMatches = (uint8_t)((ltv == rules[rn].v.tag.value)&&(rtv == rules[rn].v.tag.value)); - } else { // sanity check, can't really happen - thisRuleMatches = hardNo; - } - } else { - if ((inbound)&&(!superAccept)) { - thisRuleMatches = hardNo; + if (remoteTag) { + const uint32_t ltv = localTag->value(); + const uint32_t rtv = remoteTag->value(); + if (rt == ZT_NETWORK_RULE_MATCH_TAGS_DIFFERENCE) { + const uint32_t diff = (ltv > rtv) ? (ltv - rtv) : (rtv - ltv); + thisRuleMatches = (uint8_t)(diff <= rules[rn].v.tag.value); + } + else if (rt == ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_AND) { + thisRuleMatches = (uint8_t)((ltv & rtv) == rules[rn].v.tag.value); + } + else if (rt == ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_OR) { + thisRuleMatches = (uint8_t)((ltv | rtv) == rules[rn].v.tag.value); + } + else if (rt == ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_XOR) { + thisRuleMatches = (uint8_t)((ltv ^ rtv) == rules[rn].v.tag.value); + } + else if (rt == ZT_NETWORK_RULE_MATCH_TAGS_EQUAL) { + thisRuleMatches = (uint8_t)((ltv == rules[rn].v.tag.value) && (rtv == rules[rn].v.tag.value)); + } + else { // sanity check, can't really happen + thisRuleMatches = hardNo; + } + } + else { + if ((inbound) && (! superAccept)) { + thisRuleMatches = hardNo; #ifdef ZT_TRACE - //fprintf(stderr, "\tinbound "); + // fprintf(stderr, "\tinbound "); #endif - } else { - // Outbound side is not strict since if we have to match both tags and - // we are sending a first packet to a recipient, we probably do not know - // about their tags yet. They will filter on inbound and we will filter - // once we get their tag. If we are a tee/redirect target we are also - // not strict since we likely do not have these tags. - skipDrop = 1; - thisRuleMatches = hardYes; + } + else { + // Outbound side is not strict since if we have to match both tags and + // we are sending a first packet to a recipient, we probably do not know + // about their tags yet. They will filter on inbound and we will filter + // once we get their tag. If we are a tee/redirect target we are also + // not strict since we likely do not have these tags. + skipDrop = 1; + thisRuleMatches = hardYes; #ifdef ZT_TRACE - //fprintf(stderr, "\toutbound "); + // fprintf(stderr, "\toutbound "); #endif - } - } - } else { - thisRuleMatches = hardNo; - } - } break; - case ZT_NETWORK_RULE_MATCH_TAG_SENDER: - case ZT_NETWORK_RULE_MATCH_TAG_RECEIVER: { - const Tag *const localTag = std::lower_bound(&(nconf.tags[0]),&(nconf.tags[nconf.tagCount]),rules[rn].v.tag.id,Tag::IdComparePredicate()); + } + } + } + else { + thisRuleMatches = hardNo; + } + } break; + case ZT_NETWORK_RULE_MATCH_TAG_SENDER: + case ZT_NETWORK_RULE_MATCH_TAG_RECEIVER: { + const Tag* const localTag = std::lower_bound(&(nconf.tags[0]), &(nconf.tags[nconf.tagCount]), rules[rn].v.tag.id, Tag::IdComparePredicate()); #ifdef ZT_TRACE - /*const Tag *const remoteTag = ((membership) ? membership->getTag(nconf,rules[rn].v.tag.id) : (const Tag *)0); - fprintf(stderr, "\tlocal tag [%u: %u] remote tag [%u: %u] match [%u]", - !!localTag ? localTag->id() : 0, - !!localTag ? localTag->value() : 0, - !!remoteTag ? remoteTag->id() : 0, - !!remoteTag ? remoteTag->value() : 0, - thisRuleMatches);*/ + /*const Tag *const remoteTag = ((membership) ? membership->getTag(nconf,rules[rn].v.tag.id) : (const Tag *)0); + fprintf(stderr, "\tlocal tag [%u: %u] remote tag [%u: %u] match [%u]", + !!localTag ? localTag->id() : 0, + !!localTag ? localTag->value() : 0, + !!remoteTag ? remoteTag->id() : 0, + !!remoteTag ? remoteTag->value() : 0, + thisRuleMatches);*/ #endif - if (superAccept) { - skipDrop = 1; - thisRuleMatches = hardYes; - } else if ( ((rt == ZT_NETWORK_RULE_MATCH_TAG_SENDER)&&(inbound)) || ((rt == ZT_NETWORK_RULE_MATCH_TAG_RECEIVER)&&(!inbound)) ) { - const Tag *const remoteTag = ((membership) ? membership->getTag(nconf,rules[rn].v.tag.id) : (const Tag *)0); - if (remoteTag) { - thisRuleMatches = (uint8_t)(remoteTag->value() == rules[rn].v.tag.value); - } else { - if (rt == ZT_NETWORK_RULE_MATCH_TAG_RECEIVER) { - // If we are checking the receiver and this is an outbound packet, we - // can't be strict since we may not yet know the receiver's tag. - skipDrop = 1; - thisRuleMatches = hardYes; - } else { - thisRuleMatches = hardNo; - } - } - } else { // sender and outbound or receiver and inbound - if ((localTag != &(nconf.tags[nconf.tagCount]))&&(localTag->id() == rules[rn].v.tag.id)) { - thisRuleMatches = (uint8_t)(localTag->value() == rules[rn].v.tag.value); - } else { - thisRuleMatches = hardNo; - } - } - } break; - case ZT_NETWORK_RULE_MATCH_INTEGER_RANGE: { - uint64_t integer = 0; - const unsigned int bits = (rules[rn].v.intRange.format & 63) + 1; - const unsigned int bytes = ((bits + 8 - 1) / 8); // integer ceiling of division by 8 - if ((rules[rn].v.intRange.format & 0x80) == 0) { - // Big-endian - unsigned int idx = rules[rn].v.intRange.idx + (8 - bytes); - const unsigned int eof = idx + bytes; - if (eof <= frameLen) { - while (idx < eof) { - integer <<= 8; - integer |= frameData[idx++]; - } - } - integer &= 0xffffffffffffffffULL >> (64 - bits); - } else { - // Little-endian - unsigned int idx = rules[rn].v.intRange.idx; - const unsigned int eof = idx + bytes; - if (eof <= frameLen) { - while (idx < eof) { - integer >>= 8; - integer |= ((uint64_t)frameData[idx++]) << 56; - } - } - integer >>= (64 - bits); - } - thisRuleMatches = (uint8_t)((integer >= rules[rn].v.intRange.start)&&(integer <= (rules[rn].v.intRange.start + (uint64_t)rules[rn].v.intRange.end))); - } break; + if (superAccept) { + skipDrop = 1; + thisRuleMatches = hardYes; + } + else if (((rt == ZT_NETWORK_RULE_MATCH_TAG_SENDER) && (inbound)) || ((rt == ZT_NETWORK_RULE_MATCH_TAG_RECEIVER) && (! inbound))) { + const Tag* const remoteTag = ((membership) ? membership->getTag(nconf, rules[rn].v.tag.id) : (const Tag*)0); + if (remoteTag) { + thisRuleMatches = (uint8_t)(remoteTag->value() == rules[rn].v.tag.value); + } + else { + if (rt == ZT_NETWORK_RULE_MATCH_TAG_RECEIVER) { + // If we are checking the receiver and this is an outbound packet, we + // can't be strict since we may not yet know the receiver's tag. + skipDrop = 1; + thisRuleMatches = hardYes; + } + else { + thisRuleMatches = hardNo; + } + } + } + else { // sender and outbound or receiver and inbound + if ((localTag != &(nconf.tags[nconf.tagCount])) && (localTag->id() == rules[rn].v.tag.id)) { + thisRuleMatches = (uint8_t)(localTag->value() == rules[rn].v.tag.value); + } + else { + thisRuleMatches = hardNo; + } + } + } break; + case ZT_NETWORK_RULE_MATCH_INTEGER_RANGE: { + uint64_t integer = 0; + const unsigned int bits = (rules[rn].v.intRange.format & 63) + 1; + const unsigned int bytes = ((bits + 8 - 1) / 8); // integer ceiling of division by 8 + if ((rules[rn].v.intRange.format & 0x80) == 0) { + // Big-endian + unsigned int idx = rules[rn].v.intRange.idx + (8 - bytes); + const unsigned int eof = idx + bytes; + if (eof <= frameLen) { + while (idx < eof) { + integer <<= 8; + integer |= frameData[idx++]; + } + } + integer &= 0xffffffffffffffffULL >> (64 - bits); + } + else { + // Little-endian + unsigned int idx = rules[rn].v.intRange.idx; + const unsigned int eof = idx + bytes; + if (eof <= frameLen) { + while (idx < eof) { + integer >>= 8; + integer |= ((uint64_t)frameData[idx++]) << 56; + } + } + integer >>= (64 - bits); + } + thisRuleMatches = (uint8_t)((integer >= rules[rn].v.intRange.start) && (integer <= (rules[rn].v.intRange.start + (uint64_t)rules[rn].v.intRange.end))); + } break; - // The result of an unsupported MATCH is configurable at the network - // level via a flag. - default: - thisRuleMatches = (uint8_t)((nconf.flags & ZT_NETWORKCONFIG_FLAG_RULES_RESULT_OF_UNSUPPORTED_MATCH) != 0); - break; - } + // The result of an unsupported MATCH is configurable at the network + // level via a flag. + default: + thisRuleMatches = (uint8_t)((nconf.flags & ZT_NETWORKCONFIG_FLAG_RULES_RESULT_OF_UNSUPPORTED_MATCH) != 0); + break; + } - rrl.log(rn,thisRuleMatches,thisSetMatches); + rrl.log(rn, thisRuleMatches, thisSetMatches); - if ((rules[rn].t & 0x40)) { - thisSetMatches |= (thisRuleMatches ^ ((rules[rn].t >> 7) & 1)); - } else { - thisSetMatches &= (thisRuleMatches ^ ((rules[rn].t >> 7) & 1)); - } - } + if ((rules[rn].t & 0x40)) { + thisSetMatches |= (thisRuleMatches ^ ((rules[rn].t >> 7) & 1)); + } + else { + thisSetMatches &= (thisRuleMatches ^ ((rules[rn].t >> 7) & 1)); + } + } - return DOZTFILTER_NO_MATCH; + return DOZTFILTER_NO_MATCH; } -} // anonymous namespace +} // anonymous namespace -const ZeroTier::MulticastGroup Network::BROADCAST(ZeroTier::MAC(0xffffffffffffULL),0); +const ZeroTier::MulticastGroup Network::BROADCAST(ZeroTier::MAC(0xffffffffffffULL), 0); -Network::Network(const RuntimeEnvironment *renv,void *tPtr,uint64_t nwid,void *uptr,const NetworkConfig *nconf) : - RR(renv), - _uPtr(uptr), - _id(nwid), - _nwidStr(OSUtils::networkIDStr(nwid)), - _lastAnnouncedMulticastGroupsUpstream(0), - _mac(renv->identity.address(),nwid), - _portInitialized(false), - _lastConfigUpdate(0), - _destroyed(false), - _netconfFailure(NETCONF_FAILURE_NONE), - _portError(0), - _num_multicast_groups{Metrics::network_num_multicast_groups.Add({{"network_id", _nwidStr}})}, - _incoming_packets_accepted{Metrics::network_packets.Add({{"direction","rx"},{"network_id", _nwidStr},{"accepted","yes"}})}, - _incoming_packets_dropped{Metrics::network_packets.Add({{"direction","rx"},{"network_id", _nwidStr},{"accepted","no"}})}, - _outgoing_packets_accepted{Metrics::network_packets.Add({{"direction","tx"},{"network_id", _nwidStr},{"accepted","yes"}})}, - _outgoing_packets_dropped{Metrics::network_packets.Add({{"direction","tx"},{"network_id", _nwidStr},{"accepted","no"}})} +Network::Network(const RuntimeEnvironment* renv, void* tPtr, uint64_t nwid, void* uptr, const NetworkConfig* nconf) + : RR(renv) + , _uPtr(uptr) + , _id(nwid) + , _nwidStr(OSUtils::networkIDStr(nwid)) + , _lastAnnouncedMulticastGroupsUpstream(0) + , _mac(renv->identity.address(), nwid) + , _portInitialized(false) + , _lastConfigUpdate(0) + , _destroyed(false) + , _netconfFailure(NETCONF_FAILURE_NONE) + , _portError(0) + , _num_multicast_groups { Metrics::network_num_multicast_groups.Add({ { "network_id", _nwidStr } }) } + , _incoming_packets_accepted { Metrics::network_packets.Add({ { "direction", "rx" }, { "network_id", _nwidStr }, { "accepted", "yes" } }) } + , _incoming_packets_dropped { Metrics::network_packets.Add({ { "direction", "rx" }, { "network_id", _nwidStr }, { "accepted", "no" } }) } + , _outgoing_packets_accepted { Metrics::network_packets.Add({ { "direction", "tx" }, { "network_id", _nwidStr }, { "accepted", "yes" } }) } + , _outgoing_packets_dropped { Metrics::network_packets.Add({ { "direction", "tx" }, { "network_id", _nwidStr }, { "accepted", "no" } }) } { - for(int i=0;isetConfiguration(tPtr,*nconf,false); - _lastConfigUpdate = 0; // still want to re-request since it's likely outdated - } else { - uint64_t tmp[2]; - tmp[0] = nwid; - tmp[1] = 0; + if (nconf) { + this->setConfiguration(tPtr, *nconf, false); + _lastConfigUpdate = 0; // still want to re-request since it's likely outdated + } + else { + uint64_t tmp[2]; + tmp[0] = nwid; + tmp[1] = 0; - bool got = false; - Dictionary *dict = new Dictionary(); - try { - int n = RR->node->stateObjectGet(tPtr,ZT_STATE_OBJECT_NETWORK_CONFIG,tmp,dict->unsafeData(),ZT_NETWORKCONFIG_DICT_CAPACITY - 1); - if (n > 1) { - NetworkConfig *nconf = new NetworkConfig(); - try { - if (nconf->fromDictionary(*dict)) { - this->setConfiguration(tPtr,*nconf,false); - _lastConfigUpdate = 0; // still want to re-request an update since it's likely outdated - got = true; - } - } catch ( ... ) {} - delete nconf; - } - } catch ( ... ) {} - delete dict; + bool got = false; + Dictionary* dict = new Dictionary(); + try { + int n = RR->node->stateObjectGet(tPtr, ZT_STATE_OBJECT_NETWORK_CONFIG, tmp, dict->unsafeData(), ZT_NETWORKCONFIG_DICT_CAPACITY - 1); + if (n > 1) { + NetworkConfig* nconf = new NetworkConfig(); + try { + if (nconf->fromDictionary(*dict)) { + this->setConfiguration(tPtr, *nconf, false); + _lastConfigUpdate = 0; // still want to re-request an update since it's likely outdated + got = true; + } + } + catch (...) { + } + delete nconf; + } + } + catch (...) { + } + delete dict; - if (!got) { - RR->node->stateObjectPut(tPtr,ZT_STATE_OBJECT_NETWORK_CONFIG,tmp,"\n",1); - } - } + if (! got) { + RR->node->stateObjectPut(tPtr, ZT_STATE_OBJECT_NETWORK_CONFIG, tmp, "\n", 1); + } + } - if (!_portInitialized) { - ZT_VirtualNetworkConfig ctmp; - memset(&ctmp, 0, sizeof(ZT_VirtualNetworkConfig)); - _externalConfig(&ctmp); - _portError = RR->node->configureVirtualNetworkPort(tPtr,_id,&_uPtr,ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_UP,&ctmp); - _portInitialized = true; - } + if (! _portInitialized) { + ZT_VirtualNetworkConfig ctmp; + memset(&ctmp, 0, sizeof(ZT_VirtualNetworkConfig)); + _externalConfig(&ctmp); + _portError = RR->node->configureVirtualNetworkPort(tPtr, _id, &_uPtr, ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_UP, &ctmp); + _portInitialized = true; + } - Metrics::network_num_joined++; + Metrics::network_num_joined++; } Network::~Network() { - ZT_VirtualNetworkConfig ctmp; - _externalConfig(&ctmp); - Metrics::network_num_joined--; - if (_destroyed) { - // This is done in Node::leave() so we can pass tPtr properly - //RR->node->configureVirtualNetworkPort((void *)0,_id,&_uPtr,ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_DESTROY,&ctmp); - } else { - RR->node->configureVirtualNetworkPort((void *)0,_id,&_uPtr,ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_DOWN,&ctmp); - } + ZT_VirtualNetworkConfig ctmp; + _externalConfig(&ctmp); + Metrics::network_num_joined--; + if (_destroyed) { + // This is done in Node::leave() so we can pass tPtr properly + // RR->node->configureVirtualNetworkPort((void *)0,_id,&_uPtr,ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_DESTROY,&ctmp); + } + else { + RR->node->configureVirtualNetworkPort((void*)0, _id, &_uPtr, ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_DOWN, &ctmp); + } } bool Network::filterOutgoingPacket( - void *tPtr, - const bool noTee, - const Address &ztSource, - const Address &ztDest, - const MAC &macSource, - const MAC &macDest, - const uint8_t *frameData, - const unsigned int frameLen, - const unsigned int etherType, - const unsigned int vlanId, - uint8_t &qosBucket) + void* tPtr, + const bool noTee, + const Address& ztSource, + const Address& ztDest, + const MAC& macSource, + const MAC& macDest, + const uint8_t* frameData, + const unsigned int frameLen, + const unsigned int etherType, + const unsigned int vlanId, + uint8_t& qosBucket) { - Address ztFinalDest(ztDest); - int localCapabilityIndex = -1; - int accept = 0; - Trace::RuleResultLog rrl,crrl; - Address cc; - unsigned int ccLength = 0; - bool ccWatch = false; + Address ztFinalDest(ztDest); + int localCapabilityIndex = -1; + int accept = 0; + Trace::RuleResultLog rrl, crrl; + Address cc; + unsigned int ccLength = 0; + bool ccWatch = false; - Mutex::Lock _l(_lock); + Mutex::Lock _l(_lock); - Membership *const membership = (ztDest) ? _memberships.get(ztDest) : (Membership *)0; + Membership* const membership = (ztDest) ? _memberships.get(ztDest) : (Membership*)0; - switch(_doZtFilter(RR,rrl,_config,membership,false,ztSource,ztFinalDest,macSource,macDest,frameData,frameLen,etherType,vlanId,_config.rules,_config.ruleCount,cc,ccLength,ccWatch,qosBucket)) { + switch (_doZtFilter(RR, rrl, _config, membership, false, ztSource, ztFinalDest, macSource, macDest, frameData, frameLen, etherType, vlanId, _config.rules, _config.ruleCount, cc, ccLength, ccWatch, qosBucket)) { + case DOZTFILTER_NO_MATCH: { + for (unsigned int c = 0; c < _config.capabilityCount; ++c) { + ztFinalDest = ztDest; // sanity check, shouldn't be possible if there was no match + Address cc2; + unsigned int ccLength2 = 0; + bool ccWatch2 = false; + switch (_doZtFilter( + RR, + crrl, + _config, + membership, + false, + ztSource, + ztFinalDest, + macSource, + macDest, + frameData, + frameLen, + etherType, + vlanId, + _config.capabilities[c].rules(), + _config.capabilities[c].ruleCount(), + cc2, + ccLength2, + ccWatch2, + qosBucket)) { + case DOZTFILTER_NO_MATCH: + case DOZTFILTER_DROP: // explicit DROP in a capability just terminates its evaluation and is an anti-pattern + break; - case DOZTFILTER_NO_MATCH: { - for(unsigned int c=0;c<_config.capabilityCount;++c) { - ztFinalDest = ztDest; // sanity check, shouldn't be possible if there was no match - Address cc2; - unsigned int ccLength2 = 0; - bool ccWatch2 = false; - switch (_doZtFilter(RR,crrl,_config,membership,false,ztSource,ztFinalDest,macSource,macDest,frameData,frameLen,etherType,vlanId,_config.capabilities[c].rules(),_config.capabilities[c].ruleCount(),cc2,ccLength2,ccWatch2,qosBucket)) { - case DOZTFILTER_NO_MATCH: - case DOZTFILTER_DROP: // explicit DROP in a capability just terminates its evaluation and is an anti-pattern - break; + case DOZTFILTER_REDIRECT: // interpreted as ACCEPT but ztFinalDest will have been changed in _doZtFilter() + case DOZTFILTER_ACCEPT: + case DOZTFILTER_SUPER_ACCEPT: // no difference in behavior on outbound side in capabilities + localCapabilityIndex = (int)c; + accept = 1; - case DOZTFILTER_REDIRECT: // interpreted as ACCEPT but ztFinalDest will have been changed in _doZtFilter() - case DOZTFILTER_ACCEPT: - case DOZTFILTER_SUPER_ACCEPT: // no difference in behavior on outbound side in capabilities - localCapabilityIndex = (int)c; - accept = 1; + if ((! noTee) && (cc2)) { + Packet outp(cc2, RR->identity.address(), Packet::VERB_EXT_FRAME); + outp.append(_id); + outp.append((uint8_t)(ccWatch2 ? 0x16 : 0x02)); + macDest.appendTo(outp); + macSource.appendTo(outp); + outp.append((uint16_t)etherType); + outp.append(frameData, ccLength2); + outp.compress(); + RR->sw->send(tPtr, outp, true); + } - if ((!noTee)&&(cc2)) { - Packet outp(cc2,RR->identity.address(),Packet::VERB_EXT_FRAME); - outp.append(_id); - outp.append((uint8_t)(ccWatch2 ? 0x16 : 0x02)); - macDest.appendTo(outp); - macSource.appendTo(outp); - outp.append((uint16_t)etherType); - outp.append(frameData,ccLength2); - outp.compress(); - RR->sw->send(tPtr,outp,true); - } + break; + } + if (accept) { + break; + } + } + } break; - break; - } - if (accept) { - break; - } - } - } break; + case DOZTFILTER_DROP: + if (_config.remoteTraceTarget) { + RR->t->networkFilter(tPtr, *this, rrl, (Trace::RuleResultLog*)0, (Capability*)0, ztSource, ztDest, macSource, macDest, frameData, frameLen, etherType, vlanId, noTee, false, 0); + } + return false; - case DOZTFILTER_DROP: - if (_config.remoteTraceTarget) { - RR->t->networkFilter(tPtr,*this,rrl,(Trace::RuleResultLog *)0,(Capability *)0,ztSource,ztDest,macSource,macDest,frameData,frameLen,etherType,vlanId,noTee,false,0); - } - return false; + case DOZTFILTER_REDIRECT: // interpreted as ACCEPT but ztFinalDest will have been changed in _doZtFilter() + case DOZTFILTER_ACCEPT: + accept = 1; + break; - case DOZTFILTER_REDIRECT: // interpreted as ACCEPT but ztFinalDest will have been changed in _doZtFilter() - case DOZTFILTER_ACCEPT: - accept = 1; - break; + case DOZTFILTER_SUPER_ACCEPT: + accept = 2; + break; + } - case DOZTFILTER_SUPER_ACCEPT: - accept = 2; - break; - } + if (accept) { + _outgoing_packets_accepted++; + if ((! noTee) && (cc)) { + Packet outp(cc, RR->identity.address(), Packet::VERB_EXT_FRAME); + outp.append(_id); + outp.append((uint8_t)(ccWatch ? 0x16 : 0x02)); + macDest.appendTo(outp); + macSource.appendTo(outp); + outp.append((uint16_t)etherType); + outp.append(frameData, ccLength); + outp.compress(); + RR->sw->send(tPtr, outp, true); + } - if (accept) { - _outgoing_packets_accepted++; - if ((!noTee)&&(cc)) { - Packet outp(cc,RR->identity.address(),Packet::VERB_EXT_FRAME); - outp.append(_id); - outp.append((uint8_t)(ccWatch ? 0x16 : 0x02)); - macDest.appendTo(outp); - macSource.appendTo(outp); - outp.append((uint16_t)etherType); - outp.append(frameData,ccLength); - outp.compress(); - RR->sw->send(tPtr,outp,true); - } + if ((ztDest != ztFinalDest) && (ztFinalDest)) { + Packet outp(ztFinalDest, RR->identity.address(), Packet::VERB_EXT_FRAME); + outp.append(_id); + outp.append((uint8_t)0x04); + macDest.appendTo(outp); + macSource.appendTo(outp); + outp.append((uint16_t)etherType); + outp.append(frameData, frameLen); + outp.compress(); + RR->sw->send(tPtr, outp, true); - if ((ztDest != ztFinalDest)&&(ztFinalDest)) { - Packet outp(ztFinalDest,RR->identity.address(),Packet::VERB_EXT_FRAME); - outp.append(_id); - outp.append((uint8_t)0x04); - macDest.appendTo(outp); - macSource.appendTo(outp); - outp.append((uint16_t)etherType); - outp.append(frameData,frameLen); - outp.compress(); - RR->sw->send(tPtr,outp,true); - - if (_config.remoteTraceTarget) { - RR->t->networkFilter(tPtr,*this,rrl,(localCapabilityIndex >= 0) ? &crrl : (Trace::RuleResultLog *)0,(localCapabilityIndex >= 0) ? &(_config.capabilities[localCapabilityIndex]) : (Capability *)0,ztSource,ztDest,macSource,macDest,frameData,frameLen,etherType,vlanId,noTee,false,0); - } - return false; // DROP locally, since we redirected - } else { - if (_config.remoteTraceTarget) { - RR->t->networkFilter(tPtr,*this,rrl,(localCapabilityIndex >= 0) ? &crrl : (Trace::RuleResultLog *)0,(localCapabilityIndex >= 0) ? &(_config.capabilities[localCapabilityIndex]) : (Capability *)0,ztSource,ztDest,macSource,macDest,frameData,frameLen,etherType,vlanId,noTee,false,1); - } - return true; - } - } else { - _outgoing_packets_dropped++; - if (_config.remoteTraceTarget) { - RR->t->networkFilter(tPtr,*this,rrl,(localCapabilityIndex >= 0) ? &crrl : (Trace::RuleResultLog *)0,(localCapabilityIndex >= 0) ? &(_config.capabilities[localCapabilityIndex]) : (Capability *)0,ztSource,ztDest,macSource,macDest,frameData,frameLen,etherType,vlanId,noTee,false,0); - } - return false; - } + if (_config.remoteTraceTarget) { + RR->t->networkFilter( + tPtr, + *this, + rrl, + (localCapabilityIndex >= 0) ? &crrl : (Trace::RuleResultLog*)0, + (localCapabilityIndex >= 0) ? &(_config.capabilities[localCapabilityIndex]) : (Capability*)0, + ztSource, + ztDest, + macSource, + macDest, + frameData, + frameLen, + etherType, + vlanId, + noTee, + false, + 0); + } + return false; // DROP locally, since we redirected + } + else { + if (_config.remoteTraceTarget) { + RR->t->networkFilter( + tPtr, + *this, + rrl, + (localCapabilityIndex >= 0) ? &crrl : (Trace::RuleResultLog*)0, + (localCapabilityIndex >= 0) ? &(_config.capabilities[localCapabilityIndex]) : (Capability*)0, + ztSource, + ztDest, + macSource, + macDest, + frameData, + frameLen, + etherType, + vlanId, + noTee, + false, + 1); + } + return true; + } + } + else { + _outgoing_packets_dropped++; + if (_config.remoteTraceTarget) { + RR->t->networkFilter( + tPtr, + *this, + rrl, + (localCapabilityIndex >= 0) ? &crrl : (Trace::RuleResultLog*)0, + (localCapabilityIndex >= 0) ? &(_config.capabilities[localCapabilityIndex]) : (Capability*)0, + ztSource, + ztDest, + macSource, + macDest, + frameData, + frameLen, + etherType, + vlanId, + noTee, + false, + 0); + } + return false; + } } int Network::filterIncomingPacket( - void *tPtr, - const SharedPtr &sourcePeer, - const Address &ztDest, - const MAC &macSource, - const MAC &macDest, - const uint8_t *frameData, - const unsigned int frameLen, - const unsigned int etherType, - const unsigned int vlanId) + void* tPtr, + const SharedPtr& sourcePeer, + const Address& ztDest, + const MAC& macSource, + const MAC& macDest, + const uint8_t* frameData, + const unsigned int frameLen, + const unsigned int etherType, + const unsigned int vlanId) { - Address ztFinalDest(ztDest); - Trace::RuleResultLog rrl,crrl; - int accept = 0; - Address cc; - unsigned int ccLength = 0; - bool ccWatch = false; - const Capability *c = (Capability *)0; + Address ztFinalDest(ztDest); + Trace::RuleResultLog rrl, crrl; + int accept = 0; + Address cc; + unsigned int ccLength = 0; + bool ccWatch = false; + const Capability* c = (Capability*)0; - uint8_t qosBucket = 255; // For incoming packets this is a dummy value + uint8_t qosBucket = 255; // For incoming packets this is a dummy value - Mutex::Lock _l(_lock); + Mutex::Lock _l(_lock); - Membership &membership = _membership(sourcePeer->address()); + Membership& membership = _membership(sourcePeer->address()); - switch (_doZtFilter(RR,rrl,_config,&membership,true,sourcePeer->address(),ztFinalDest,macSource,macDest,frameData,frameLen,etherType,vlanId,_config.rules,_config.ruleCount,cc,ccLength,ccWatch,qosBucket)) { + switch (_doZtFilter(RR, rrl, _config, &membership, true, sourcePeer->address(), ztFinalDest, macSource, macDest, frameData, frameLen, etherType, vlanId, _config.rules, _config.ruleCount, cc, ccLength, ccWatch, qosBucket)) { + case DOZTFILTER_NO_MATCH: { + Membership::CapabilityIterator mci(membership, _config); + while ((c = mci.next())) { + ztFinalDest = ztDest; // sanity check, should be unmodified if there was no match + Address cc2; + unsigned int ccLength2 = 0; + bool ccWatch2 = false; + switch (_doZtFilter(RR, crrl, _config, &membership, true, sourcePeer->address(), ztFinalDest, macSource, macDest, frameData, frameLen, etherType, vlanId, c->rules(), c->ruleCount(), cc2, ccLength2, ccWatch2, qosBucket)) { + case DOZTFILTER_NO_MATCH: + case DOZTFILTER_DROP: // explicit DROP in a capability just terminates its evaluation and is an anti-pattern + break; + case DOZTFILTER_REDIRECT: // interpreted as ACCEPT but ztDest will have been changed in _doZtFilter() + case DOZTFILTER_ACCEPT: + accept = 1; // ACCEPT + break; + case DOZTFILTER_SUPER_ACCEPT: + accept = 2; // super-ACCEPT + break; + } - case DOZTFILTER_NO_MATCH: { - Membership::CapabilityIterator mci(membership,_config); - while ((c = mci.next())) { - ztFinalDest = ztDest; // sanity check, should be unmodified if there was no match - Address cc2; - unsigned int ccLength2 = 0; - bool ccWatch2 = false; - switch(_doZtFilter(RR,crrl,_config,&membership,true,sourcePeer->address(),ztFinalDest,macSource,macDest,frameData,frameLen,etherType,vlanId,c->rules(),c->ruleCount(),cc2,ccLength2,ccWatch2,qosBucket)) { - case DOZTFILTER_NO_MATCH: - case DOZTFILTER_DROP: // explicit DROP in a capability just terminates its evaluation and is an anti-pattern - break; - case DOZTFILTER_REDIRECT: // interpreted as ACCEPT but ztDest will have been changed in _doZtFilter() - case DOZTFILTER_ACCEPT: - accept = 1; // ACCEPT - break; - case DOZTFILTER_SUPER_ACCEPT: - accept = 2; // super-ACCEPT - break; - } + if (accept) { + if (cc2) { + Packet outp(cc2, RR->identity.address(), Packet::VERB_EXT_FRAME); + outp.append(_id); + outp.append((uint8_t)(ccWatch2 ? 0x1c : 0x08)); + macDest.appendTo(outp); + macSource.appendTo(outp); + outp.append((uint16_t)etherType); + outp.append(frameData, ccLength2); + outp.compress(); + RR->sw->send(tPtr, outp, true); + } + break; + } + } + } break; - if (accept) { - if (cc2) { - Packet outp(cc2,RR->identity.address(),Packet::VERB_EXT_FRAME); - outp.append(_id); - outp.append((uint8_t)(ccWatch2 ? 0x1c : 0x08)); - macDest.appendTo(outp); - macSource.appendTo(outp); - outp.append((uint16_t)etherType); - outp.append(frameData,ccLength2); - outp.compress(); - RR->sw->send(tPtr,outp,true); - } - break; - } - } - } break; + case DOZTFILTER_DROP: + if (_config.remoteTraceTarget) { + RR->t->networkFilter(tPtr, *this, rrl, (Trace::RuleResultLog*)0, (Capability*)0, sourcePeer->address(), ztDest, macSource, macDest, frameData, frameLen, etherType, vlanId, false, true, 0); + } + return 0; // DROP - case DOZTFILTER_DROP: - if (_config.remoteTraceTarget) { - RR->t->networkFilter(tPtr,*this,rrl,(Trace::RuleResultLog *)0,(Capability *)0,sourcePeer->address(),ztDest,macSource,macDest,frameData,frameLen,etherType,vlanId,false,true,0); - } - return 0; // DROP + case DOZTFILTER_REDIRECT: // interpreted as ACCEPT but ztFinalDest will have been changed in _doZtFilter() + case DOZTFILTER_ACCEPT: + accept = 1; // ACCEPT + break; + case DOZTFILTER_SUPER_ACCEPT: + accept = 2; // super-ACCEPT + break; + } - case DOZTFILTER_REDIRECT: // interpreted as ACCEPT but ztFinalDest will have been changed in _doZtFilter() - case DOZTFILTER_ACCEPT: - accept = 1; // ACCEPT - break; - case DOZTFILTER_SUPER_ACCEPT: - accept = 2; // super-ACCEPT - break; - } + if (accept) { + _incoming_packets_accepted++; + if (cc) { + Packet outp(cc, RR->identity.address(), Packet::VERB_EXT_FRAME); + outp.append(_id); + outp.append((uint8_t)(ccWatch ? 0x1c : 0x08)); + macDest.appendTo(outp); + macSource.appendTo(outp); + outp.append((uint16_t)etherType); + outp.append(frameData, ccLength); + outp.compress(); + RR->sw->send(tPtr, outp, true); + } - if (accept) { - _incoming_packets_accepted++; - if (cc) { - Packet outp(cc,RR->identity.address(),Packet::VERB_EXT_FRAME); - outp.append(_id); - outp.append((uint8_t)(ccWatch ? 0x1c : 0x08)); - macDest.appendTo(outp); - macSource.appendTo(outp); - outp.append((uint16_t)etherType); - outp.append(frameData,ccLength); - outp.compress(); - RR->sw->send(tPtr,outp,true); - } + if ((ztDest != ztFinalDest) && (ztFinalDest)) { + Packet outp(ztFinalDest, RR->identity.address(), Packet::VERB_EXT_FRAME); + outp.append(_id); + outp.append((uint8_t)0x0a); + macDest.appendTo(outp); + macSource.appendTo(outp); + outp.append((uint16_t)etherType); + outp.append(frameData, frameLen); + outp.compress(); + RR->sw->send(tPtr, outp, true); - if ((ztDest != ztFinalDest)&&(ztFinalDest)) { - Packet outp(ztFinalDest,RR->identity.address(),Packet::VERB_EXT_FRAME); - outp.append(_id); - outp.append((uint8_t)0x0a); - macDest.appendTo(outp); - macSource.appendTo(outp); - outp.append((uint16_t)etherType); - outp.append(frameData,frameLen); - outp.compress(); - RR->sw->send(tPtr,outp,true); + if (_config.remoteTraceTarget) { + RR->t->networkFilter(tPtr, *this, rrl, (c) ? &crrl : (Trace::RuleResultLog*)0, c, sourcePeer->address(), ztDest, macSource, macDest, frameData, frameLen, etherType, vlanId, false, true, 0); + } + return 0; // DROP locally, since we redirected + } + } + else { + _incoming_packets_dropped++; + } - if (_config.remoteTraceTarget) { - RR->t->networkFilter(tPtr,*this,rrl,(c) ? &crrl : (Trace::RuleResultLog *)0,c,sourcePeer->address(),ztDest,macSource,macDest,frameData,frameLen,etherType,vlanId,false,true,0); - } - return 0; // DROP locally, since we redirected - } - } else { - _incoming_packets_dropped++; - } - - if (_config.remoteTraceTarget) { - RR->t->networkFilter(tPtr,*this,rrl,(c) ? &crrl : (Trace::RuleResultLog *)0,c,sourcePeer->address(),ztDest,macSource,macDest,frameData,frameLen,etherType,vlanId,false,true,accept); - } - return accept; + if (_config.remoteTraceTarget) { + RR->t->networkFilter(tPtr, *this, rrl, (c) ? &crrl : (Trace::RuleResultLog*)0, c, sourcePeer->address(), ztDest, macSource, macDest, frameData, frameLen, etherType, vlanId, false, true, accept); + } + return accept; } -bool Network::subscribedToMulticastGroup(const MulticastGroup &mg,bool includeBridgedGroups) const +bool Network::subscribedToMulticastGroup(const MulticastGroup& mg, bool includeBridgedGroups) const { - Mutex::Lock _l(_lock); - if (std::binary_search(_myMulticastGroups.begin(),_myMulticastGroups.end(),mg)) { - return true; - } else if (includeBridgedGroups) { - return _multicastGroupsBehindMe.contains(mg); - } - return false; + Mutex::Lock _l(_lock); + if (std::binary_search(_myMulticastGroups.begin(), _myMulticastGroups.end(), mg)) { + return true; + } + else if (includeBridgedGroups) { + return _multicastGroupsBehindMe.contains(mg); + } + return false; } -void Network::multicastSubscribe(void *tPtr,const MulticastGroup &mg) +void Network::multicastSubscribe(void* tPtr, const MulticastGroup& mg) { - Mutex::Lock _l(_lock); - if (!std::binary_search(_myMulticastGroups.begin(),_myMulticastGroups.end(),mg)) { - _myMulticastGroups.insert(std::upper_bound(_myMulticastGroups.begin(),_myMulticastGroups.end(),mg),mg); - _sendUpdatesToMembers(tPtr,&mg); - _num_multicast_groups++; - } + Mutex::Lock _l(_lock); + if (! std::binary_search(_myMulticastGroups.begin(), _myMulticastGroups.end(), mg)) { + _myMulticastGroups.insert(std::upper_bound(_myMulticastGroups.begin(), _myMulticastGroups.end(), mg), mg); + _sendUpdatesToMembers(tPtr, &mg); + _num_multicast_groups++; + } } -void Network::multicastUnsubscribe(const MulticastGroup &mg) +void Network::multicastUnsubscribe(const MulticastGroup& mg) { - Mutex::Lock _l(_lock); - std::vector::iterator i(std::lower_bound(_myMulticastGroups.begin(),_myMulticastGroups.end(),mg)); - if ( (i != _myMulticastGroups.end()) && (*i == mg) ) { - _myMulticastGroups.erase(i); - _num_multicast_groups--; - } + Mutex::Lock _l(_lock); + std::vector::iterator i(std::lower_bound(_myMulticastGroups.begin(), _myMulticastGroups.end(), mg)); + if ((i != _myMulticastGroups.end()) && (*i == mg)) { + _myMulticastGroups.erase(i); + _num_multicast_groups--; + } } -uint64_t Network::handleConfigChunk(void *tPtr,const uint64_t packetId,const Address &source,const Buffer &chunk,unsigned int ptr) +uint64_t Network::handleConfigChunk(void* tPtr, const uint64_t packetId, const Address& source, const Buffer& chunk, unsigned int ptr) { - if (_destroyed) { - return 0; - } + if (_destroyed) { + return 0; + } - const unsigned int start = ptr; + const unsigned int start = ptr; - ptr += 8; // skip network ID, which is already obviously known - const unsigned int chunkLen = chunk.at(ptr); - ptr += 2; - const void *chunkData = chunk.field(ptr,chunkLen); - ptr += chunkLen; + ptr += 8; // skip network ID, which is already obviously known + const unsigned int chunkLen = chunk.at(ptr); + ptr += 2; + const void* chunkData = chunk.field(ptr, chunkLen); + ptr += chunkLen; - NetworkConfig *nc = (NetworkConfig *)0; - uint64_t configUpdateId; - { - Mutex::Lock _l(_lock); + NetworkConfig* nc = (NetworkConfig*)0; + uint64_t configUpdateId; + { + Mutex::Lock _l(_lock); - _IncomingConfigChunk *c = (_IncomingConfigChunk *)0; - uint64_t chunkId = 0; - unsigned long totalLength,chunkIndex; - if (ptr < chunk.size()) { - const bool fastPropagate = ((chunk[ptr++] & 0x01) != 0); - configUpdateId = chunk.at(ptr); - ptr += 8; - totalLength = chunk.at(ptr); - ptr += 4; - chunkIndex = chunk.at(ptr); - ptr += 4; + _IncomingConfigChunk* c = (_IncomingConfigChunk*)0; + uint64_t chunkId = 0; + unsigned long totalLength, chunkIndex; + if (ptr < chunk.size()) { + const bool fastPropagate = ((chunk[ptr++] & 0x01) != 0); + configUpdateId = chunk.at(ptr); + ptr += 8; + totalLength = chunk.at(ptr); + ptr += 4; + chunkIndex = chunk.at(ptr); + ptr += 4; - if (((chunkIndex + chunkLen) > totalLength)||(totalLength >= ZT_NETWORKCONFIG_DICT_CAPACITY)) { // >= since we need room for a null at the end - return 0; - } - if ((chunk[ptr] != 1)||(chunk.at(ptr + 1) != ZT_C25519_SIGNATURE_LEN)) { - return 0; - } - const uint8_t *sig = reinterpret_cast(chunk.field(ptr + 3,ZT_C25519_SIGNATURE_LEN)); + if (((chunkIndex + chunkLen) > totalLength) || (totalLength >= ZT_NETWORKCONFIG_DICT_CAPACITY)) { // >= since we need room for a null at the end + return 0; + } + if ((chunk[ptr] != 1) || (chunk.at(ptr + 1) != ZT_ECC_SIGNATURE_LEN)) { + return 0; + } + const uint8_t* sig = reinterpret_cast(chunk.field(ptr + 3, ZT_ECC_SIGNATURE_LEN)); - // We can use the signature, which is unique per chunk, to get a per-chunk ID for local deduplication use - for(unsigned int i=0;i<16;++i) { - reinterpret_cast(&chunkId)[i & 7] ^= sig[i]; - } + // We can use the signature, which is unique per chunk, to get a per-chunk ID for local deduplication use + for (unsigned int i = 0; i < 16; ++i) { + reinterpret_cast(&chunkId)[i & 7] ^= sig[i]; + } - // Find existing or new slot for this update and check if this is a duplicate chunk - for(int i=0;ihaveChunks;++j) { - if (c->haveChunkIds[j] == chunkId) { - return 0; - } - } + for (unsigned long j = 0; j < c->haveChunks; ++j) { + if (c->haveChunkIds[j] == chunkId) { + return 0; + } + } - break; - } else if ((!c)||(_incomingConfigChunks[i].ts < c->ts)) { - c = &(_incomingConfigChunks[i]); - } - } + break; + } + else if ((! c) || (_incomingConfigChunks[i].ts < c->ts)) { + c = &(_incomingConfigChunks[i]); + } + } - // If it's not a duplicate, check chunk signature - const Identity controllerId(RR->topology->getIdentity(tPtr,controller())); - if (!controllerId) { // we should always have the controller identity by now, otherwise how would we have queried it the first time? - return 0; - } - if (!controllerId.verify(chunk.field(start,ptr - start),ptr - start,sig,ZT_C25519_SIGNATURE_LEN)) { - return 0; - } + // If it's not a duplicate, check chunk signature + const Identity controllerId(RR->topology->getIdentity(tPtr, controller())); + if (! controllerId) { // we should always have the controller identity by now, otherwise how would we have queried it the first time? + return 0; + } + if (! controllerId.verify(chunk.field(start, ptr - start), ptr - start, sig, ZT_ECC_SIGNATURE_LEN)) { + return 0; + } - // New properly verified chunks can be flooded "virally" through the network - if (fastPropagate) { - Address *a = (Address *)0; - Membership *m = (Membership *)0; - Hashtable::Iterator i(_memberships); - while (i.next(a,m)) { - if ((*a != source)&&(*a != controller())) { - Packet outp(*a,RR->identity.address(),Packet::VERB_NETWORK_CONFIG); - outp.append(reinterpret_cast(chunk.data()) + start,chunk.size() - start); - RR->sw->send(tPtr,outp,true); - } - } - } - } else if ((source == controller())||(!source)) { // since old chunks aren't signed, only accept from controller itself (or via cluster backplane) - // Legacy support for OK(NETWORK_CONFIG_REQUEST) from older controllers - chunkId = packetId; - configUpdateId = chunkId; - totalLength = chunkLen; - chunkIndex = 0; + // New properly verified chunks can be flooded "virally" through the network + if (fastPropagate) { + Address* a = (Address*)0; + Membership* m = (Membership*)0; + Hashtable::Iterator i(_memberships); + while (i.next(a, m)) { + if ((*a != source) && (*a != controller())) { + Packet outp(*a, RR->identity.address(), Packet::VERB_NETWORK_CONFIG); + outp.append(reinterpret_cast(chunk.data()) + start, chunk.size() - start); + RR->sw->send(tPtr, outp, true); + } + } + } + } + else if ((source == controller()) || (! source)) { // since old chunks aren't signed, only accept from controller itself (or via cluster backplane) + // Legacy support for OK(NETWORK_CONFIG_REQUEST) from older controllers + chunkId = packetId; + configUpdateId = chunkId; + totalLength = chunkLen; + chunkIndex = 0; - if (totalLength >= ZT_NETWORKCONFIG_DICT_CAPACITY) { - return 0; - } + if (totalLength >= ZT_NETWORKCONFIG_DICT_CAPACITY) { + return 0; + } - for(int i=0;its)) { - c = &(_incomingConfigChunks[i]); - } - } - } else { - // Single-chunk unsigned legacy configs are only allowed from the controller itself - return 0; - } + for (int i = 0; i < ZT_NETWORK_MAX_INCOMING_UPDATES; ++i) { + if ((! c) || (_incomingConfigChunks[i].ts < c->ts)) { + c = &(_incomingConfigChunks[i]); + } + } + } + else { + // Single-chunk unsigned legacy configs are only allowed from the controller itself + return 0; + } - ++c->ts; // newer is higher, that's all we need + ++c->ts; // newer is higher, that's all we need - if (c->updateId != configUpdateId) { - c->updateId = configUpdateId; - c->haveChunks = 0; - c->haveBytes = 0; - } - if (c->haveChunks >= ZT_NETWORK_MAX_UPDATE_CHUNKS) { - return false; - } - c->haveChunkIds[c->haveChunks++] = chunkId; + if (c->updateId != configUpdateId) { + c->updateId = configUpdateId; + c->haveChunks = 0; + c->haveBytes = 0; + } + if (c->haveChunks >= ZT_NETWORK_MAX_UPDATE_CHUNKS) { + return false; + } + c->haveChunkIds[c->haveChunks++] = chunkId; - memcpy(c->data.unsafeData() + chunkIndex,chunkData,chunkLen); - c->haveBytes += chunkLen; + memcpy(c->data.unsafeData() + chunkIndex, chunkData, chunkLen); + c->haveBytes += chunkLen; - if (c->haveBytes == totalLength) { - c->data.unsafeData()[c->haveBytes] = (char)0; // ensure null terminated + if (c->haveBytes == totalLength) { + c->data.unsafeData()[c->haveBytes] = (char)0; // ensure null terminated - nc = new NetworkConfig(); - try { - if (!nc->fromDictionary(c->data)) { - delete nc; - nc = (NetworkConfig *)0; - } - } catch ( ... ) { - delete nc; - nc = (NetworkConfig *)0; - } - } - } + nc = new NetworkConfig(); + try { + if (! nc->fromDictionary(c->data)) { + delete nc; + nc = (NetworkConfig*)0; + } + } + catch (...) { + delete nc; + nc = (NetworkConfig*)0; + } + } + } - if (nc) { - this->setConfiguration(tPtr, *nc, true); - delete nc; - return configUpdateId; - } else { - return 0; - } + if (nc) { + this->setConfiguration(tPtr, *nc, true); + delete nc; + return configUpdateId; + } + else { + return 0; + } - return 0; + return 0; } -int Network::setConfiguration(void *tPtr,const NetworkConfig &nconf,bool saveToDisk) +int Network::setConfiguration(void* tPtr, const NetworkConfig& nconf, bool saveToDisk) { - if (_destroyed) { - return 0; - } + if (_destroyed) { + return 0; + } - // _lock is NOT locked when this is called - try { - if ((nconf.issuedTo != RR->identity.address())||(nconf.networkId != _id)) { - return 0; // invalid config that is not for us or not for this network - } - if (_config == nconf) { - return 1; // OK config, but duplicate of what we already have - } + // _lock is NOT locked when this is called + try { + if ((nconf.issuedTo != RR->identity.address()) || (nconf.networkId != _id)) { + return 0; // invalid config that is not for us or not for this network + } + if (_config == nconf) { + return 1; // OK config, but duplicate of what we already have + } - ZT_VirtualNetworkConfig ctmp; - bool oldPortInitialized; - { // do things that require lock here, but unlock before calling callbacks - Mutex::Lock _l(_lock); + ZT_VirtualNetworkConfig ctmp; + bool oldPortInitialized; + { // do things that require lock here, but unlock before calling callbacks + Mutex::Lock _l(_lock); - _config = nconf; - _lastConfigUpdate = RR->node->now(); - _netconfFailure = NETCONF_FAILURE_NONE; + _config = nconf; + _lastConfigUpdate = RR->node->now(); + _netconfFailure = NETCONF_FAILURE_NONE; - oldPortInitialized = _portInitialized; - _portInitialized = true; + oldPortInitialized = _portInitialized; + _portInitialized = true; - _externalConfig(&ctmp); - } + _externalConfig(&ctmp); + } - _portError = RR->node->configureVirtualNetworkPort(tPtr,_id,&_uPtr,(oldPortInitialized) ? ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_CONFIG_UPDATE : ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_UP,&ctmp); - _authenticationURL = nconf.authenticationURL; + _portError = RR->node->configureVirtualNetworkPort(tPtr, _id, &_uPtr, (oldPortInitialized) ? ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_CONFIG_UPDATE : ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_UP, &ctmp); + _authenticationURL = nconf.authenticationURL; - if (saveToDisk) { - Dictionary *const d = new Dictionary(); - try { - if (nconf.toDictionary(*d,false)) { - uint64_t tmp[2]; - tmp[0] = _id; - tmp[1] = 0; - RR->node->stateObjectPut(tPtr,ZT_STATE_OBJECT_NETWORK_CONFIG,tmp,d->data(),d->sizeBytes()); - } - } catch ( ... ) {} - delete d; - } + if (saveToDisk) { + Dictionary* const d = new Dictionary(); + try { + if (nconf.toDictionary(*d, false)) { + uint64_t tmp[2]; + tmp[0] = _id; + tmp[1] = 0; + RR->node->stateObjectPut(tPtr, ZT_STATE_OBJECT_NETWORK_CONFIG, tmp, d->data(), d->sizeBytes()); + } + } + catch (...) { + } + delete d; + } - return 2; // OK and configuration has changed - } catch ( ... ) {} // ignore invalid configs - return 0; + return 2; // OK and configuration has changed + } + catch (...) { + } // ignore invalid configs + return 0; } -void Network::requestConfiguration(void *tPtr) +void Network::requestConfiguration(void* tPtr) { - if (_destroyed) { - return; - } + if (_destroyed) { + return; + } - if ((_id >> 56) == 0xff) { - if ((_id & 0xffffff) == 0) { - const uint16_t startPortRange = (uint16_t)((_id >> 40) & 0xffff); - const uint16_t endPortRange = (uint16_t)((_id >> 24) & 0xffff); - if (endPortRange >= startPortRange) { - NetworkConfig *const nconf = new NetworkConfig(); + if ((_id >> 56) == 0xff) { + if ((_id & 0xffffff) == 0) { + const uint16_t startPortRange = (uint16_t)((_id >> 40) & 0xffff); + const uint16_t endPortRange = (uint16_t)((_id >> 24) & 0xffff); + if (endPortRange >= startPortRange) { + NetworkConfig* const nconf = new NetworkConfig(); - nconf->networkId = _id; - nconf->timestamp = RR->node->now(); - nconf->credentialTimeMaxDelta = ZT_NETWORKCONFIG_DEFAULT_CREDENTIAL_TIME_MAX_MAX_DELTA; - nconf->revision = 1; - nconf->issuedTo = RR->identity.address(); - nconf->flags = ZT_NETWORKCONFIG_FLAG_ENABLE_IPV6_NDP_EMULATION; - nconf->mtu = ZT_DEFAULT_MTU; - nconf->multicastLimit = 0; - nconf->staticIpCount = 1; - nconf->ruleCount = 14; - nconf->staticIps[0] = InetAddress::makeIpv66plane(_id,RR->identity.address().toInt()); + nconf->networkId = _id; + nconf->timestamp = RR->node->now(); + nconf->credentialTimeMaxDelta = ZT_NETWORKCONFIG_DEFAULT_CREDENTIAL_TIME_MAX_MAX_DELTA; + nconf->revision = 1; + nconf->issuedTo = RR->identity.address(); + nconf->flags = ZT_NETWORKCONFIG_FLAG_ENABLE_IPV6_NDP_EMULATION; + nconf->mtu = ZT_DEFAULT_MTU; + nconf->multicastLimit = 0; + nconf->staticIpCount = 1; + nconf->ruleCount = 14; + nconf->staticIps[0] = InetAddress::makeIpv66plane(_id, RR->identity.address().toInt()); - // Drop everything but IPv6 - nconf->rules[0].t = (uint8_t)ZT_NETWORK_RULE_MATCH_ETHERTYPE | 0x80; // NOT - nconf->rules[0].v.etherType = 0x86dd; // IPv6 - nconf->rules[1].t = (uint8_t)ZT_NETWORK_RULE_ACTION_DROP; + // Drop everything but IPv6 + nconf->rules[0].t = (uint8_t)ZT_NETWORK_RULE_MATCH_ETHERTYPE | 0x80; // NOT + nconf->rules[0].v.etherType = 0x86dd; // IPv6 + nconf->rules[1].t = (uint8_t)ZT_NETWORK_RULE_ACTION_DROP; - // Allow ICMPv6 - nconf->rules[2].t = (uint8_t)ZT_NETWORK_RULE_MATCH_IP_PROTOCOL; - nconf->rules[2].v.ipProtocol = 0x3a; // ICMPv6 - nconf->rules[3].t = (uint8_t)ZT_NETWORK_RULE_ACTION_ACCEPT; + // Allow ICMPv6 + nconf->rules[2].t = (uint8_t)ZT_NETWORK_RULE_MATCH_IP_PROTOCOL; + nconf->rules[2].v.ipProtocol = 0x3a; // ICMPv6 + nconf->rules[3].t = (uint8_t)ZT_NETWORK_RULE_ACTION_ACCEPT; - // Allow destination ports within range - nconf->rules[4].t = (uint8_t)ZT_NETWORK_RULE_MATCH_IP_PROTOCOL; - nconf->rules[4].v.ipProtocol = 0x11; // UDP - nconf->rules[5].t = (uint8_t)ZT_NETWORK_RULE_MATCH_IP_PROTOCOL | 0x40; // OR - nconf->rules[5].v.ipProtocol = 0x06; // TCP - nconf->rules[6].t = (uint8_t)ZT_NETWORK_RULE_MATCH_IP_DEST_PORT_RANGE; - nconf->rules[6].v.port[0] = startPortRange; - nconf->rules[6].v.port[1] = endPortRange; - nconf->rules[7].t = (uint8_t)ZT_NETWORK_RULE_ACTION_ACCEPT; + // Allow destination ports within range + nconf->rules[4].t = (uint8_t)ZT_NETWORK_RULE_MATCH_IP_PROTOCOL; + nconf->rules[4].v.ipProtocol = 0x11; // UDP + nconf->rules[5].t = (uint8_t)ZT_NETWORK_RULE_MATCH_IP_PROTOCOL | 0x40; // OR + nconf->rules[5].v.ipProtocol = 0x06; // TCP + nconf->rules[6].t = (uint8_t)ZT_NETWORK_RULE_MATCH_IP_DEST_PORT_RANGE; + nconf->rules[6].v.port[0] = startPortRange; + nconf->rules[6].v.port[1] = endPortRange; + nconf->rules[7].t = (uint8_t)ZT_NETWORK_RULE_ACTION_ACCEPT; - // Allow non-SYN TCP packets to permit non-connection-initiating traffic - nconf->rules[8].t = (uint8_t)ZT_NETWORK_RULE_MATCH_CHARACTERISTICS | 0x80; // NOT - nconf->rules[8].v.characteristics = ZT_RULE_PACKET_CHARACTERISTICS_TCP_SYN; - nconf->rules[9].t = (uint8_t)ZT_NETWORK_RULE_ACTION_ACCEPT; + // Allow non-SYN TCP packets to permit non-connection-initiating traffic + nconf->rules[8].t = (uint8_t)ZT_NETWORK_RULE_MATCH_CHARACTERISTICS | 0x80; // NOT + nconf->rules[8].v.characteristics = ZT_RULE_PACKET_CHARACTERISTICS_TCP_SYN; + nconf->rules[9].t = (uint8_t)ZT_NETWORK_RULE_ACTION_ACCEPT; - // Also allow SYN+ACK which are replies to SYN - nconf->rules[10].t = (uint8_t)ZT_NETWORK_RULE_MATCH_CHARACTERISTICS; - nconf->rules[10].v.characteristics = ZT_RULE_PACKET_CHARACTERISTICS_TCP_SYN; - nconf->rules[11].t = (uint8_t)ZT_NETWORK_RULE_MATCH_CHARACTERISTICS; - nconf->rules[11].v.characteristics = ZT_RULE_PACKET_CHARACTERISTICS_TCP_ACK; - nconf->rules[12].t = (uint8_t)ZT_NETWORK_RULE_ACTION_ACCEPT; + // Also allow SYN+ACK which are replies to SYN + nconf->rules[10].t = (uint8_t)ZT_NETWORK_RULE_MATCH_CHARACTERISTICS; + nconf->rules[10].v.characteristics = ZT_RULE_PACKET_CHARACTERISTICS_TCP_SYN; + nconf->rules[11].t = (uint8_t)ZT_NETWORK_RULE_MATCH_CHARACTERISTICS; + nconf->rules[11].v.characteristics = ZT_RULE_PACKET_CHARACTERISTICS_TCP_ACK; + nconf->rules[12].t = (uint8_t)ZT_NETWORK_RULE_ACTION_ACCEPT; - nconf->rules[13].t = (uint8_t)ZT_NETWORK_RULE_ACTION_DROP; + nconf->rules[13].t = (uint8_t)ZT_NETWORK_RULE_ACTION_DROP; - nconf->type = ZT_NETWORK_TYPE_PUBLIC; + nconf->type = ZT_NETWORK_TYPE_PUBLIC; - nconf->name[0] = 'a'; - nconf->name[1] = 'd'; - nconf->name[2] = 'h'; - nconf->name[3] = 'o'; - nconf->name[4] = 'c'; - nconf->name[5] = '-'; - Utils::hex((uint16_t)startPortRange,nconf->name + 6); - nconf->name[10] = '-'; - Utils::hex((uint16_t)endPortRange,nconf->name + 11); - nconf->name[15] = (char)0; + nconf->name[0] = 'a'; + nconf->name[1] = 'd'; + nconf->name[2] = 'h'; + nconf->name[3] = 'o'; + nconf->name[4] = 'c'; + nconf->name[5] = '-'; + Utils::hex((uint16_t)startPortRange, nconf->name + 6); + nconf->name[10] = '-'; + Utils::hex((uint16_t)endPortRange, nconf->name + 11); + nconf->name[15] = (char)0; - this->setConfiguration(tPtr,*nconf,false); - delete nconf; - } else { - this->setNotFound(tPtr); - } - } else if ((_id & 0xff) == 0x01) { - // ffAAaaaaaaaaaa01 -- where AA is the IPv4 /8 to use and aaaaaaaaaa is the anchor node for multicast gather and replication - const uint64_t myAddress = RR->identity.address().toInt(); - const uint64_t networkHub = (_id >> 8) & 0xffffffffffULL; + this->setConfiguration(tPtr, *nconf, false); + delete nconf; + } + else { + this->setNotFound(tPtr); + } + } + else if ((_id & 0xff) == 0x01) { + // ffAAaaaaaaaaaa01 -- where AA is the IPv4 /8 to use and aaaaaaaaaa is the anchor node for multicast gather and replication + const uint64_t myAddress = RR->identity.address().toInt(); + const uint64_t networkHub = (_id >> 8) & 0xffffffffffULL; - uint8_t ipv4[4]; - ipv4[0] = (uint8_t)((_id >> 48) & 0xff); - ipv4[1] = (uint8_t)((myAddress >> 16) & 0xff); - ipv4[2] = (uint8_t)((myAddress >> 8) & 0xff); - ipv4[3] = (uint8_t)(myAddress & 0xff); + uint8_t ipv4[4]; + ipv4[0] = (uint8_t)((_id >> 48) & 0xff); + ipv4[1] = (uint8_t)((myAddress >> 16) & 0xff); + ipv4[2] = (uint8_t)((myAddress >> 8) & 0xff); + ipv4[3] = (uint8_t)(myAddress & 0xff); - char v4ascii[24]; - Utils::decimal(ipv4[0],v4ascii); + char v4ascii[24]; + Utils::decimal(ipv4[0], v4ascii); - NetworkConfig *const nconf = new NetworkConfig(); + NetworkConfig* const nconf = new NetworkConfig(); - nconf->networkId = _id; - nconf->timestamp = RR->node->now(); - nconf->credentialTimeMaxDelta = ZT_NETWORKCONFIG_DEFAULT_CREDENTIAL_TIME_MAX_MAX_DELTA; - nconf->revision = 1; - nconf->issuedTo = RR->identity.address(); - nconf->flags = ZT_NETWORKCONFIG_FLAG_ENABLE_IPV6_NDP_EMULATION; - nconf->mtu = ZT_DEFAULT_MTU; - nconf->multicastLimit = 1024; - nconf->specialistCount = (networkHub == 0) ? 0 : 1; - nconf->staticIpCount = 2; - nconf->ruleCount = 1; + nconf->networkId = _id; + nconf->timestamp = RR->node->now(); + nconf->credentialTimeMaxDelta = ZT_NETWORKCONFIG_DEFAULT_CREDENTIAL_TIME_MAX_MAX_DELTA; + nconf->revision = 1; + nconf->issuedTo = RR->identity.address(); + nconf->flags = ZT_NETWORKCONFIG_FLAG_ENABLE_IPV6_NDP_EMULATION; + nconf->mtu = ZT_DEFAULT_MTU; + nconf->multicastLimit = 1024; + nconf->specialistCount = (networkHub == 0) ? 0 : 1; + nconf->staticIpCount = 2; + nconf->ruleCount = 1; - if (networkHub != 0) { - nconf->specialists[0] = networkHub; - } + if (networkHub != 0) { + nconf->specialists[0] = networkHub; + } - nconf->staticIps[0] = InetAddress::makeIpv66plane(_id,myAddress); - nconf->staticIps[1].set(ipv4,4,8); + nconf->staticIps[0] = InetAddress::makeIpv66plane(_id, myAddress); + nconf->staticIps[1].set(ipv4, 4, 8); - nconf->rules[0].t = (uint8_t)ZT_NETWORK_RULE_ACTION_ACCEPT; + nconf->rules[0].t = (uint8_t)ZT_NETWORK_RULE_ACTION_ACCEPT; - nconf->type = ZT_NETWORK_TYPE_PUBLIC; + nconf->type = ZT_NETWORK_TYPE_PUBLIC; - nconf->name[0] = 'a'; - nconf->name[1] = 'd'; - nconf->name[2] = 'h'; - nconf->name[3] = 'o'; - nconf->name[4] = 'c'; - nconf->name[5] = '-'; - unsigned long nn = 6; - while ((nconf->name[nn] = v4ascii[nn - 6])) { - ++nn; - } - nconf->name[nn++] = '.'; - nconf->name[nn++] = '0'; - nconf->name[nn++] = '.'; - nconf->name[nn++] = '0'; - nconf->name[nn++] = '.'; - nconf->name[nn++] = '0'; - nconf->name[nn++] = (char)0; + nconf->name[0] = 'a'; + nconf->name[1] = 'd'; + nconf->name[2] = 'h'; + nconf->name[3] = 'o'; + nconf->name[4] = 'c'; + nconf->name[5] = '-'; + unsigned long nn = 6; + while ((nconf->name[nn] = v4ascii[nn - 6])) { + ++nn; + } + nconf->name[nn++] = '.'; + nconf->name[nn++] = '0'; + nconf->name[nn++] = '.'; + nconf->name[nn++] = '0'; + nconf->name[nn++] = '.'; + nconf->name[nn++] = '0'; + nconf->name[nn++] = (char)0; - this->setConfiguration(tPtr,*nconf,false); - delete nconf; - } - return; - } + this->setConfiguration(tPtr, *nconf, false); + delete nconf; + } + return; + } - const Address ctrl(controller()); + const Address ctrl(controller()); - Dictionary rmd; - rmd.add(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_VERSION,(uint64_t)ZT_NETWORKCONFIG_VERSION); - rmd.add(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_NODE_VENDOR,(uint64_t)ZT_VENDOR_ZEROTIER); - rmd.add(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_PROTOCOL_VERSION,(uint64_t)ZT_PROTO_VERSION); - rmd.add(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_NODE_MAJOR_VERSION,(uint64_t)ZEROTIER_ONE_VERSION_MAJOR); - rmd.add(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_NODE_MINOR_VERSION,(uint64_t)ZEROTIER_ONE_VERSION_MINOR); - rmd.add(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_NODE_REVISION,(uint64_t)ZEROTIER_ONE_VERSION_REVISION); - rmd.add(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_MAX_NETWORK_RULES,(uint64_t)ZT_MAX_NETWORK_RULES); - rmd.add(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_MAX_NETWORK_CAPABILITIES,(uint64_t)ZT_MAX_NETWORK_CAPABILITIES); - rmd.add(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_MAX_CAPABILITY_RULES,(uint64_t)ZT_MAX_CAPABILITY_RULES); - rmd.add(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_MAX_NETWORK_TAGS,(uint64_t)ZT_MAX_NETWORK_TAGS); - rmd.add(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_FLAGS,(uint64_t)0); - rmd.add(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_RULES_ENGINE_REV,(uint64_t)ZT_RULES_ENGINE_REVISION); - rmd.add(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_OS_ARCH,ZT_TARGET_NAME); + Dictionary rmd; + rmd.add(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_VERSION, (uint64_t)ZT_NETWORKCONFIG_VERSION); + rmd.add(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_NODE_VENDOR, (uint64_t)ZT_VENDOR_ZEROTIER); + rmd.add(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_PROTOCOL_VERSION, (uint64_t)ZT_PROTO_VERSION); + rmd.add(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_NODE_MAJOR_VERSION, (uint64_t)ZEROTIER_ONE_VERSION_MAJOR); + rmd.add(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_NODE_MINOR_VERSION, (uint64_t)ZEROTIER_ONE_VERSION_MINOR); + rmd.add(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_NODE_REVISION, (uint64_t)ZEROTIER_ONE_VERSION_REVISION); + rmd.add(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_MAX_NETWORK_RULES, (uint64_t)ZT_MAX_NETWORK_RULES); + rmd.add(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_MAX_NETWORK_CAPABILITIES, (uint64_t)ZT_MAX_NETWORK_CAPABILITIES); + rmd.add(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_MAX_CAPABILITY_RULES, (uint64_t)ZT_MAX_CAPABILITY_RULES); + rmd.add(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_MAX_NETWORK_TAGS, (uint64_t)ZT_MAX_NETWORK_TAGS); + rmd.add(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_FLAGS, (uint64_t)0); + rmd.add(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_RULES_ENGINE_REV, (uint64_t)ZT_RULES_ENGINE_REVISION); + rmd.add(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_OS_ARCH, ZT_TARGET_NAME); - RR->t->networkConfigRequestSent(tPtr,*this,ctrl); + RR->t->networkConfigRequestSent(tPtr, *this, ctrl); - if (ctrl == RR->identity.address()) { - if (RR->localNetworkController) { - RR->localNetworkController->request(_id,InetAddress(),0xffffffffffffffffULL,RR->identity,rmd); - } else { - this->setNotFound(tPtr); - } - return; - } + if (ctrl == RR->identity.address()) { + if (RR->localNetworkController) { + RR->localNetworkController->request(_id, InetAddress(), 0xffffffffffffffffULL, RR->identity, rmd); + } + else { + this->setNotFound(tPtr); + } + return; + } - Packet outp(ctrl,RR->identity.address(),Packet::VERB_NETWORK_CONFIG_REQUEST); - outp.append((uint64_t)_id); - const unsigned int rmdSize = rmd.sizeBytes(); - outp.append((uint16_t)rmdSize); - outp.append((const void *)rmd.data(),rmdSize); - if (_config) { - outp.append((uint64_t)_config.revision); - outp.append((uint64_t)_config.timestamp); - } else { - outp.append((unsigned char)0,16); - } - outp.compress(); - RR->node->expectReplyTo(outp.packetId()); - RR->sw->send(tPtr,outp,true); + Packet outp(ctrl, RR->identity.address(), Packet::VERB_NETWORK_CONFIG_REQUEST); + outp.append((uint64_t)_id); + const unsigned int rmdSize = rmd.sizeBytes(); + outp.append((uint16_t)rmdSize); + outp.append((const void*)rmd.data(), rmdSize); + if (_config) { + outp.append((uint64_t)_config.revision); + outp.append((uint64_t)_config.timestamp); + } + else { + outp.append((unsigned char)0, 16); + } + outp.compress(); + RR->node->expectReplyTo(outp.packetId()); + RR->sw->send(tPtr, outp, true); } -bool Network::gate(void *tPtr,const SharedPtr &peer) +bool Network::gate(void* tPtr, const SharedPtr& peer) { - const int64_t now = RR->node->now(); - //int64_t comTimestamp = 0; - //int64_t comRevocationThreshold = 0; - Mutex::Lock _l(_lock); - try { - if (_config) { - Membership *m = _memberships.get(peer->address()); - //if (m) { - // comTimestamp = m->comTimestamp(); - // comRevocationThreshold = m->comRevocationThreshold(); - //} - if ( (_config.isPublic()) || ((m)&&(m->isAllowedOnNetwork(_config, peer->identity()))) ) { - if (!m) { - m = &(_membership(peer->address())); - } - if (m->multicastLikeGate(now)) { - _announceMulticastGroupsTo(tPtr,peer->address(),_allMulticastGroups()); - } - return true; - } - } - } catch ( ... ) {} - //printf("%.16llx %.10llx not allowed, COM ts %lld revocation %lld\n", _id, peer->address().toInt(), comTimestamp, comRevocationThreshold); fflush(stdout); + const int64_t now = RR->node->now(); + // int64_t comTimestamp = 0; + // int64_t comRevocationThreshold = 0; + Mutex::Lock _l(_lock); + try { + if (_config) { + Membership* m = _memberships.get(peer->address()); + // if (m) { + // comTimestamp = m->comTimestamp(); + // comRevocationThreshold = m->comRevocationThreshold(); + // } + if ((_config.isPublic()) || ((m) && (m->isAllowedOnNetwork(_config, peer->identity())))) { + if (! m) { + m = &(_membership(peer->address())); + } + if (m->multicastLikeGate(now)) { + _announceMulticastGroupsTo(tPtr, peer->address(), _allMulticastGroups()); + } + return true; + } + } + } + catch (...) { + } + // printf("%.16llx %.10llx not allowed, COM ts %lld revocation %lld\n", _id, peer->address().toInt(), comTimestamp, comRevocationThreshold); fflush(stdout); - return false; + return false; } -bool Network::recentlyAssociatedWith(const Address &addr) +bool Network::recentlyAssociatedWith(const Address& addr) { - Mutex::Lock _l(_lock); - const Membership *m = _memberships.get(addr); - return ((m)&&(m->recentlyAssociated(RR->node->now()))); + Mutex::Lock _l(_lock); + const Membership* m = _memberships.get(addr); + return ((m) && (m->recentlyAssociated(RR->node->now()))); } void Network::clean() { - const int64_t now = RR->node->now(); - Mutex::Lock _l(_lock); + const int64_t now = RR->node->now(); + Mutex::Lock _l(_lock); - if (_destroyed) { - return; - } + if (_destroyed) { + return; + } - { - Hashtable< MulticastGroup,uint64_t >::Iterator i(_multicastGroupsBehindMe); - MulticastGroup *mg = (MulticastGroup *)0; - uint64_t *ts = (uint64_t *)0; - while (i.next(mg,ts)) { - if ((now - *ts) > (ZT_MULTICAST_LIKE_EXPIRE * 2)) { - _multicastGroupsBehindMe.erase(*mg); - } - } - } + { + Hashtable::Iterator i(_multicastGroupsBehindMe); + MulticastGroup* mg = (MulticastGroup*)0; + uint64_t* ts = (uint64_t*)0; + while (i.next(mg, ts)) { + if ((now - *ts) > (ZT_MULTICAST_LIKE_EXPIRE * 2)) { + _multicastGroupsBehindMe.erase(*mg); + } + } + } - { - Address *a = (Address *)0; - Membership *m = (Membership *)0; - Hashtable::Iterator i(_memberships); - while (i.next(a,m)) { - if (!RR->topology->getPeerNoCache(*a)) { - _memberships.erase(*a); - } else { - m->clean(now,_config); - } - } - } + { + Address* a = (Address*)0; + Membership* m = (Membership*)0; + Hashtable::Iterator i(_memberships); + while (i.next(a, m)) { + if (! RR->topology->getPeerNoCache(*a)) { + _memberships.erase(*a); + } + else { + m->clean(now, _config); + } + } + } } -void Network::learnBridgeRoute(const MAC &mac,const Address &addr) +void Network::learnBridgeRoute(const MAC& mac, const Address& addr) { - Mutex::Lock _l(_lock); - _remoteBridgeRoutes[mac] = addr; + Mutex::Lock _l(_lock); + _remoteBridgeRoutes[mac] = addr; - // Anti-DOS circuit breaker to prevent nodes from spamming us with absurd numbers of bridge routes - while (_remoteBridgeRoutes.size() > ZT_MAX_BRIDGE_ROUTES) { - Hashtable< Address,unsigned long > counts; - Address maxAddr; - unsigned long maxCount = 0; + // Anti-DOS circuit breaker to prevent nodes from spamming us with absurd numbers of bridge routes + while (_remoteBridgeRoutes.size() > ZT_MAX_BRIDGE_ROUTES) { + Hashtable counts; + Address maxAddr; + unsigned long maxCount = 0; - MAC *m = (MAC *)0; - Address *a = (Address *)0; + MAC* m = (MAC*)0; + Address* a = (Address*)0; - // Find the address responsible for the most entries - { - Hashtable::Iterator i(_remoteBridgeRoutes); - while (i.next(m,a)) { - const unsigned long c = ++counts[*a]; - if (c > maxCount) { - maxCount = c; - maxAddr = *a; - } - } - } + // Find the address responsible for the most entries + { + Hashtable::Iterator i(_remoteBridgeRoutes); + while (i.next(m, a)) { + const unsigned long c = ++counts[*a]; + if (c > maxCount) { + maxCount = c; + maxAddr = *a; + } + } + } - // Kill this address from our table, since it's most likely spamming us - { - Hashtable::Iterator i(_remoteBridgeRoutes); - while (i.next(m,a)) { - if (*a == maxAddr) { - _remoteBridgeRoutes.erase(*m); - } - } - } - } + // Kill this address from our table, since it's most likely spamming us + { + Hashtable::Iterator i(_remoteBridgeRoutes); + while (i.next(m, a)) { + if (*a == maxAddr) { + _remoteBridgeRoutes.erase(*m); + } + } + } + } } -void Network::learnBridgedMulticastGroup(void *tPtr,const MulticastGroup &mg,int64_t now) +void Network::learnBridgedMulticastGroup(void* tPtr, const MulticastGroup& mg, int64_t now) { - Mutex::Lock _l(_lock); - const unsigned long tmp = (unsigned long)_multicastGroupsBehindMe.size(); - _multicastGroupsBehindMe.set(mg,now); - if (tmp != _multicastGroupsBehindMe.size()) { - _sendUpdatesToMembers(tPtr,&mg); - } + Mutex::Lock _l(_lock); + const unsigned long tmp = (unsigned long)_multicastGroupsBehindMe.size(); + _multicastGroupsBehindMe.set(mg, now); + if (tmp != _multicastGroupsBehindMe.size()) { + _sendUpdatesToMembers(tPtr, &mg); + } } -Membership::AddCredentialResult Network::addCredential(void *tPtr,const CertificateOfMembership &com) +Membership::AddCredentialResult Network::addCredential(void* tPtr, const CertificateOfMembership& com) { - if (com.networkId() != _id) { - return Membership::ADD_REJECTED; - } - Mutex::Lock _l(_lock); - return _membership(com.issuedTo()).addCredential(RR,tPtr,_config,com); + if (com.networkId() != _id) { + return Membership::ADD_REJECTED; + } + Mutex::Lock _l(_lock); + return _membership(com.issuedTo()).addCredential(RR, tPtr, _config, com); } -Membership::AddCredentialResult Network::addCredential(void *tPtr,const Address &sentFrom,const Revocation &rev) +Membership::AddCredentialResult Network::addCredential(void* tPtr, const Address& sentFrom, const Revocation& rev) { - if (rev.networkId() != _id) { - return Membership::ADD_REJECTED; - } + if (rev.networkId() != _id) { + return Membership::ADD_REJECTED; + } - Mutex::Lock _l(_lock); - Membership &m = _membership(rev.target()); + Mutex::Lock _l(_lock); + Membership& m = _membership(rev.target()); - const Membership::AddCredentialResult result = m.addCredential(RR,tPtr,_config,rev); + const Membership::AddCredentialResult result = m.addCredential(RR, tPtr, _config, rev); - if ((result == Membership::ADD_ACCEPTED_NEW)&&(rev.fastPropagate())) { - Address *a = (Address *)0; - Membership *m = (Membership *)0; - Hashtable::Iterator i(_memberships); - while (i.next(a,m)) { - if ((*a != sentFrom)&&(*a != rev.signer())) { - Packet outp(*a,RR->identity.address(),Packet::VERB_NETWORK_CREDENTIALS); - outp.append((uint8_t)0x00); // no COM - outp.append((uint16_t)0); // no capabilities - outp.append((uint16_t)0); // no tags - outp.append((uint16_t)1); // one revocation! - rev.serialize(outp); - outp.append((uint16_t)0); // no certificates of ownership - RR->sw->send(tPtr,outp,true); - } - } - } + if ((result == Membership::ADD_ACCEPTED_NEW) && (rev.fastPropagate())) { + Address* a = (Address*)0; + Membership* m = (Membership*)0; + Hashtable::Iterator i(_memberships); + while (i.next(a, m)) { + if ((*a != sentFrom) && (*a != rev.signer())) { + Packet outp(*a, RR->identity.address(), Packet::VERB_NETWORK_CREDENTIALS); + outp.append((uint8_t)0x00); // no COM + outp.append((uint16_t)0); // no capabilities + outp.append((uint16_t)0); // no tags + outp.append((uint16_t)1); // one revocation! + rev.serialize(outp); + outp.append((uint16_t)0); // no certificates of ownership + RR->sw->send(tPtr, outp, true); + } + } + } - return result; + return result; } void Network::destroy() { - Mutex::Lock _l(_lock); - _destroyed = true; + Mutex::Lock _l(_lock); + _destroyed = true; } ZT_VirtualNetworkStatus Network::_status() const { - // assumes _lock is locked - if (_portError) { - return ZT_NETWORK_STATUS_PORT_ERROR; - } - switch(_netconfFailure) { - case NETCONF_FAILURE_ACCESS_DENIED: - return ZT_NETWORK_STATUS_ACCESS_DENIED; - case NETCONF_FAILURE_NOT_FOUND: - return ZT_NETWORK_STATUS_NOT_FOUND; - case NETCONF_FAILURE_NONE: - return ((_config) ? ZT_NETWORK_STATUS_OK : ZT_NETWORK_STATUS_REQUESTING_CONFIGURATION); - case NETCONF_FAILURE_AUTHENTICATION_REQUIRED: - return ZT_NETWORK_STATUS_AUTHENTICATION_REQUIRED; - default: - return ZT_NETWORK_STATUS_PORT_ERROR; - } + // assumes _lock is locked + if (_portError) { + return ZT_NETWORK_STATUS_PORT_ERROR; + } + switch (_netconfFailure) { + case NETCONF_FAILURE_ACCESS_DENIED: + return ZT_NETWORK_STATUS_ACCESS_DENIED; + case NETCONF_FAILURE_NOT_FOUND: + return ZT_NETWORK_STATUS_NOT_FOUND; + case NETCONF_FAILURE_NONE: + return ((_config) ? ZT_NETWORK_STATUS_OK : ZT_NETWORK_STATUS_REQUESTING_CONFIGURATION); + case NETCONF_FAILURE_AUTHENTICATION_REQUIRED: + return ZT_NETWORK_STATUS_AUTHENTICATION_REQUIRED; + default: + return ZT_NETWORK_STATUS_PORT_ERROR; + } } -void Network::_externalConfig(ZT_VirtualNetworkConfig *ec) const +void Network::_externalConfig(ZT_VirtualNetworkConfig* ec) const { - // assumes _lock is locked - ec->nwid = _id; - ec->mac = _mac.toInt(); - if (_config) { - Utils::scopy(ec->name,sizeof(ec->name),_config.name); - } else { - ec->name[0] = (char)0; - } - ec->status = _status(); - ec->type = (_config) ? (_config.isPrivate() ? ZT_NETWORK_TYPE_PRIVATE : ZT_NETWORK_TYPE_PUBLIC) : ZT_NETWORK_TYPE_PRIVATE; - ec->mtu = (_config) ? _config.mtu : ZT_DEFAULT_MTU; - ec->dhcp = 0; - std::vector
ab(_config.activeBridges()); - ec->bridge = (std::find(ab.begin(),ab.end(),RR->identity.address()) != ab.end()) ? 1 : 0; - ec->broadcastEnabled = (_config) ? (_config.enableBroadcast() ? 1 : 0) : 0; - ec->portError = _portError; - ec->netconfRevision = (_config) ? (unsigned long)_config.revision : 0; + // assumes _lock is locked + ec->nwid = _id; + ec->mac = _mac.toInt(); + if (_config) { + Utils::scopy(ec->name, sizeof(ec->name), _config.name); + } + else { + ec->name[0] = (char)0; + } + ec->status = _status(); + ec->type = (_config) ? (_config.isPrivate() ? ZT_NETWORK_TYPE_PRIVATE : ZT_NETWORK_TYPE_PUBLIC) : ZT_NETWORK_TYPE_PRIVATE; + ec->mtu = (_config) ? _config.mtu : ZT_DEFAULT_MTU; + ec->dhcp = 0; + std::vector
ab(_config.activeBridges()); + ec->bridge = (std::find(ab.begin(), ab.end(), RR->identity.address()) != ab.end()) ? 1 : 0; + ec->broadcastEnabled = (_config) ? (_config.enableBroadcast() ? 1 : 0) : 0; + ec->portError = _portError; + ec->netconfRevision = (_config) ? (unsigned long)_config.revision : 0; - ec->assignedAddressCount = 0; - for(unsigned int i=0;iassignedAddresses[i]),&(_config.staticIps[i]),sizeof(struct sockaddr_storage)); - ++ec->assignedAddressCount; - } else { - memset(&(ec->assignedAddresses[i]),0,sizeof(struct sockaddr_storage)); - } - } + ec->assignedAddressCount = 0; + for (unsigned int i = 0; i < ZT_MAX_ZT_ASSIGNED_ADDRESSES; ++i) { + if (i < _config.staticIpCount) { + memcpy(&(ec->assignedAddresses[i]), &(_config.staticIps[i]), sizeof(struct sockaddr_storage)); + ++ec->assignedAddressCount; + } + else { + memset(&(ec->assignedAddresses[i]), 0, sizeof(struct sockaddr_storage)); + } + } - ec->routeCount = 0; - for(unsigned int i=0;iroutes[i]),&(_config.routes[i]),sizeof(ZT_VirtualNetworkRoute)); - ++ec->routeCount; - } else { - memset(&(ec->routes[i]),0,sizeof(ZT_VirtualNetworkRoute)); - } - } + ec->routeCount = 0; + for (unsigned int i = 0; i < ZT_MAX_NETWORK_ROUTES; ++i) { + if (i < _config.routeCount) { + memcpy(&(ec->routes[i]), &(_config.routes[i]), sizeof(ZT_VirtualNetworkRoute)); + ++ec->routeCount; + } + else { + memset(&(ec->routes[i]), 0, sizeof(ZT_VirtualNetworkRoute)); + } + } - ec->multicastSubscriptionCount = (unsigned int)_myMulticastGroups.size(); - for(unsigned long i=0;i<(unsigned long)_myMulticastGroups.size();++i) { - ec->multicastSubscriptions[i].mac = _myMulticastGroups[i].mac().toInt(); - ec->multicastSubscriptions[i].adi = _myMulticastGroups[i].adi(); - } + ec->multicastSubscriptionCount = (unsigned int)_myMulticastGroups.size(); + for (unsigned long i = 0; i < (unsigned long)_myMulticastGroups.size(); ++i) { + ec->multicastSubscriptions[i].mac = _myMulticastGroups[i].mac().toInt(); + ec->multicastSubscriptions[i].adi = _myMulticastGroups[i].adi(); + } - memcpy(&ec->dns, &_config.dns, sizeof(ZT_VirtualNetworkDNS)); + memcpy(&ec->dns, &_config.dns, sizeof(ZT_VirtualNetworkDNS)); - Utils::scopy(ec->authenticationURL, sizeof(ec->authenticationURL), _authenticationURL.c_str()); - ec->ssoVersion = _config.ssoVersion; - ec->authenticationExpiryTime = _config.authenticationExpiryTime; - ec->ssoEnabled = _config.ssoEnabled; - Utils::scopy(ec->centralAuthURL, sizeof(ec->centralAuthURL), _config.centralAuthURL); - Utils::scopy(ec->issuerURL, sizeof(ec->issuerURL), _config.issuerURL); - Utils::scopy(ec->ssoNonce, sizeof(ec->ssoNonce), _config.ssoNonce); - Utils::scopy(ec->ssoState, sizeof(ec->ssoState), _config.ssoState); - Utils::scopy(ec->ssoClientID, sizeof(ec->ssoClientID), _config.ssoClientID); - Utils::scopy(ec->ssoProvider, sizeof(ec->ssoProvider), _config.ssoProvider); + Utils::scopy(ec->authenticationURL, sizeof(ec->authenticationURL), _authenticationURL.c_str()); + ec->ssoVersion = _config.ssoVersion; + ec->authenticationExpiryTime = _config.authenticationExpiryTime; + ec->ssoEnabled = _config.ssoEnabled; + Utils::scopy(ec->centralAuthURL, sizeof(ec->centralAuthURL), _config.centralAuthURL); + Utils::scopy(ec->issuerURL, sizeof(ec->issuerURL), _config.issuerURL); + Utils::scopy(ec->ssoNonce, sizeof(ec->ssoNonce), _config.ssoNonce); + Utils::scopy(ec->ssoState, sizeof(ec->ssoState), _config.ssoState); + Utils::scopy(ec->ssoClientID, sizeof(ec->ssoClientID), _config.ssoClientID); + Utils::scopy(ec->ssoProvider, sizeof(ec->ssoProvider), _config.ssoProvider); } -void Network::_sendUpdatesToMembers(void *tPtr,const MulticastGroup *const newMulticastGroup) +void Network::_sendUpdatesToMembers(void* tPtr, const MulticastGroup* const newMulticastGroup) { - // Assumes _lock is locked - const int64_t now = RR->node->now(); + // Assumes _lock is locked + const int64_t now = RR->node->now(); - std::vector groups; - if (newMulticastGroup) { - groups.push_back(*newMulticastGroup); - } else { - groups = _allMulticastGroups(); - } + std::vector groups; + if (newMulticastGroup) { + groups.push_back(*newMulticastGroup); + } + else { + groups = _allMulticastGroups(); + } - std::vector
alwaysAnnounceTo; + std::vector
alwaysAnnounceTo; - if ((newMulticastGroup)||((now - _lastAnnouncedMulticastGroupsUpstream) >= ZT_MULTICAST_ANNOUNCE_PERIOD)) { - if (!newMulticastGroup) { - _lastAnnouncedMulticastGroupsUpstream = now; - } + if ((newMulticastGroup) || ((now - _lastAnnouncedMulticastGroupsUpstream) >= ZT_MULTICAST_ANNOUNCE_PERIOD)) { + if (! newMulticastGroup) { + _lastAnnouncedMulticastGroupsUpstream = now; + } - alwaysAnnounceTo = _config.alwaysContactAddresses(); - if (std::find(alwaysAnnounceTo.begin(),alwaysAnnounceTo.end(),controller()) == alwaysAnnounceTo.end()) { - alwaysAnnounceTo.push_back(controller()); - } - const std::vector
upstreams(RR->topology->upstreamAddresses()); - for(std::vector
::const_iterator a(upstreams.begin());a!=upstreams.end();++a) { - if (std::find(alwaysAnnounceTo.begin(),alwaysAnnounceTo.end(),*a) == alwaysAnnounceTo.end()) { - alwaysAnnounceTo.push_back(*a); - } - } - std::sort(alwaysAnnounceTo.begin(),alwaysAnnounceTo.end()); + alwaysAnnounceTo = _config.alwaysContactAddresses(); + if (std::find(alwaysAnnounceTo.begin(), alwaysAnnounceTo.end(), controller()) == alwaysAnnounceTo.end()) { + alwaysAnnounceTo.push_back(controller()); + } + const std::vector
upstreams(RR->topology->upstreamAddresses()); + for (std::vector
::const_iterator a(upstreams.begin()); a != upstreams.end(); ++a) { + if (std::find(alwaysAnnounceTo.begin(), alwaysAnnounceTo.end(), *a) == alwaysAnnounceTo.end()) { + alwaysAnnounceTo.push_back(*a); + } + } + std::sort(alwaysAnnounceTo.begin(), alwaysAnnounceTo.end()); - for(std::vector
::const_iterator a(alwaysAnnounceTo.begin());a!=alwaysAnnounceTo.end();++a) { - /* - // push COM to non-members so they can do multicast request auth - if ( (_config.com) && (!_memberships.contains(*a)) && (*a != RR->identity.address()) ) { - Packet outp(*a,RR->identity.address(),Packet::VERB_NETWORK_CREDENTIALS); - _config.com.serialize(outp); - outp.append((uint8_t)0x00); - outp.append((uint16_t)0); // no capabilities - outp.append((uint16_t)0); // no tags - outp.append((uint16_t)0); // no revocations - outp.append((uint16_t)0); // no certificates of ownership - RR->sw->send(tPtr,outp,true); - } - */ - _announceMulticastGroupsTo(tPtr,*a,groups); - } - } + for (std::vector
::const_iterator a(alwaysAnnounceTo.begin()); a != alwaysAnnounceTo.end(); ++a) { + /* + // push COM to non-members so they can do multicast request auth + if ( (_config.com) && (!_memberships.contains(*a)) && (*a != RR->identity.address()) ) { + Packet outp(*a,RR->identity.address(),Packet::VERB_NETWORK_CREDENTIALS); + _config.com.serialize(outp); + outp.append((uint8_t)0x00); + outp.append((uint16_t)0); // no capabilities + outp.append((uint16_t)0); // no tags + outp.append((uint16_t)0); // no revocations + outp.append((uint16_t)0); // no certificates of ownership + RR->sw->send(tPtr,outp,true); + } + */ + _announceMulticastGroupsTo(tPtr, *a, groups); + } + } - { - Address *a = (Address *)0; - Membership *m = (Membership *)0; - Hashtable::Iterator i(_memberships); - while (i.next(a,m)) { - const Identity remoteIdentity(RR->topology->getIdentity(tPtr, *a)); - if (remoteIdentity) { - if ( ( m->multicastLikeGate(now) || (newMulticastGroup) ) && (m->isAllowedOnNetwork(_config, remoteIdentity)) && (!std::binary_search(alwaysAnnounceTo.begin(),alwaysAnnounceTo.end(),*a)) ) { - _announceMulticastGroupsTo(tPtr,*a,groups); - } - } - } - } + { + Address* a = (Address*)0; + Membership* m = (Membership*)0; + Hashtable::Iterator i(_memberships); + while (i.next(a, m)) { + const Identity remoteIdentity(RR->topology->getIdentity(tPtr, *a)); + if (remoteIdentity) { + if ((m->multicastLikeGate(now) || (newMulticastGroup)) && (m->isAllowedOnNetwork(_config, remoteIdentity)) && (! std::binary_search(alwaysAnnounceTo.begin(), alwaysAnnounceTo.end(), *a))) { + _announceMulticastGroupsTo(tPtr, *a, groups); + } + } + } + } } -void Network::_announceMulticastGroupsTo(void *tPtr,const Address &peer,const std::vector &allMulticastGroups) +void Network::_announceMulticastGroupsTo(void* tPtr, const Address& peer, const std::vector& allMulticastGroups) { - // Assumes _lock is locked - Packet *const outp = new Packet(peer,RR->identity.address(),Packet::VERB_MULTICAST_LIKE); + // Assumes _lock is locked + Packet* const outp = new Packet(peer, RR->identity.address(), Packet::VERB_MULTICAST_LIKE); - for(std::vector::const_iterator mg(allMulticastGroups.begin());mg!=allMulticastGroups.end();++mg) { - if ((outp->size() + 24) >= ZT_PROTO_MAX_PACKET_LENGTH) { - outp->compress(); - RR->sw->send(tPtr,*outp,true); - outp->reset(peer,RR->identity.address(),Packet::VERB_MULTICAST_LIKE); - } + for (std::vector::const_iterator mg(allMulticastGroups.begin()); mg != allMulticastGroups.end(); ++mg) { + if ((outp->size() + 24) >= ZT_PROTO_MAX_PACKET_LENGTH) { + outp->compress(); + RR->sw->send(tPtr, *outp, true); + outp->reset(peer, RR->identity.address(), Packet::VERB_MULTICAST_LIKE); + } - // network ID, MAC, ADI - outp->append((uint64_t)_id); - mg->mac().appendTo(*outp); - outp->append((uint32_t)mg->adi()); - } + // network ID, MAC, ADI + outp->append((uint64_t)_id); + mg->mac().appendTo(*outp); + outp->append((uint32_t)mg->adi()); + } - if (outp->size() > ZT_PROTO_MIN_PACKET_LENGTH) { - outp->compress(); - RR->sw->send(tPtr,*outp,true); - } + if (outp->size() > ZT_PROTO_MIN_PACKET_LENGTH) { + outp->compress(); + RR->sw->send(tPtr, *outp, true); + } - delete outp; + delete outp; } std::vector Network::_allMulticastGroups() const { - // Assumes _lock is locked - std::vector mgs; - mgs.reserve(_myMulticastGroups.size() + _multicastGroupsBehindMe.size() + 1); - mgs.insert(mgs.end(),_myMulticastGroups.begin(),_myMulticastGroups.end()); - _multicastGroupsBehindMe.appendKeys(mgs); - if ((_config)&&(_config.enableBroadcast())) { - mgs.push_back(Network::BROADCAST); - } - std::sort(mgs.begin(),mgs.end()); - mgs.erase(std::unique(mgs.begin(),mgs.end()),mgs.end()); - return mgs; + // Assumes _lock is locked + std::vector mgs; + mgs.reserve(_myMulticastGroups.size() + _multicastGroupsBehindMe.size() + 1); + mgs.insert(mgs.end(), _myMulticastGroups.begin(), _myMulticastGroups.end()); + _multicastGroupsBehindMe.appendKeys(mgs); + if ((_config) && (_config.enableBroadcast())) { + mgs.push_back(Network::BROADCAST); + } + std::sort(mgs.begin(), mgs.end()); + mgs.erase(std::unique(mgs.begin(), mgs.end()), mgs.end()); + return mgs; } -Membership &Network::_membership(const Address &a) +Membership& Network::_membership(const Address& a) { - // assumes _lock is locked - return _memberships[a]; + // assumes _lock is locked + return _memberships[a]; } -void Network::setAuthenticationRequired(void *tPtr, const char* issuerURL, const char* centralEndpoint, const char* clientID, const char *ssoProvider, const char* nonce, const char* state) +void Network::setAuthenticationRequired(void* tPtr, const char* issuerURL, const char* centralEndpoint, const char* clientID, const char* ssoProvider, const char* nonce, const char* state) { - Mutex::Lock _l(_lock); - _netconfFailure = NETCONF_FAILURE_AUTHENTICATION_REQUIRED; - _config.ssoEnabled = true; - _config.ssoVersion = 1; + Mutex::Lock _l(_lock); + _netconfFailure = NETCONF_FAILURE_AUTHENTICATION_REQUIRED; + _config.ssoEnabled = true; + _config.ssoVersion = 1; - Utils::scopy(_config.issuerURL, sizeof(_config.issuerURL), issuerURL); - Utils::scopy(_config.centralAuthURL, sizeof(_config.centralAuthURL), centralEndpoint); - Utils::scopy(_config.ssoClientID, sizeof(_config.ssoClientID), clientID); - Utils::scopy(_config.ssoNonce, sizeof(_config.ssoNonce), nonce); - Utils::scopy(_config.ssoState, sizeof(_config.ssoState), state); - Utils::scopy(_config.ssoProvider, sizeof(_config.ssoProvider), ssoProvider); - _sendUpdateEvent(tPtr); + Utils::scopy(_config.issuerURL, sizeof(_config.issuerURL), issuerURL); + Utils::scopy(_config.centralAuthURL, sizeof(_config.centralAuthURL), centralEndpoint); + Utils::scopy(_config.ssoClientID, sizeof(_config.ssoClientID), clientID); + Utils::scopy(_config.ssoNonce, sizeof(_config.ssoNonce), nonce); + Utils::scopy(_config.ssoState, sizeof(_config.ssoState), state); + Utils::scopy(_config.ssoProvider, sizeof(_config.ssoProvider), ssoProvider); + _sendUpdateEvent(tPtr); } -void Network::_sendUpdateEvent(void *tPtr) { - ZT_VirtualNetworkConfig ctmp; - _externalConfig(&ctmp); - RR->node->configureVirtualNetworkPort(tPtr, _id, &_uPtr, (_portInitialized) ? ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_CONFIG_UPDATE : ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_UP, &ctmp); +void Network::_sendUpdateEvent(void* tPtr) +{ + ZT_VirtualNetworkConfig ctmp; + _externalConfig(&ctmp); + RR->node->configureVirtualNetworkPort(tPtr, _id, &_uPtr, (_portInitialized) ? ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_CONFIG_UPDATE : ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_UP, &ctmp); } -} // namespace ZeroTier +} // namespace ZeroTier diff --git a/node/Network.hpp b/node/Network.hpp index cc85b7d1..f1c46d40 100644 --- a/node/Network.hpp +++ b/node/Network.hpp @@ -14,33 +14,31 @@ #ifndef ZT_NETWORK_HPP #define ZT_NETWORK_HPP -#include - #include "../include/ZeroTierOne.h" - -#include -#include -#include -#include -#include - -#include "Constants.hpp" -#include "Hashtable.hpp" #include "Address.hpp" -#include "Mutex.hpp" -#include "SharedPtr.hpp" #include "AtomicCounter.hpp" -#include "MulticastGroup.hpp" -#include "MAC.hpp" -#include "Dictionary.hpp" -#include "Multicaster.hpp" -#include "Membership.hpp" -#include "NetworkConfig.hpp" #include "CertificateOfMembership.hpp" +#include "Constants.hpp" +#include "Dictionary.hpp" +#include "Hashtable.hpp" +#include "MAC.hpp" +#include "Membership.hpp" #include "Metrics.hpp" +#include "MulticastGroup.hpp" +#include "Multicaster.hpp" +#include "Mutex.hpp" +#include "NetworkConfig.hpp" +#include "SharedPtr.hpp" + +#include +#include +#include +#include +#include +#include #define ZT_NETWORK_MAX_INCOMING_UPDATES 3 -#define ZT_NETWORK_MAX_UPDATE_CHUNKS ((ZT_NETWORKCONFIG_DICT_CAPACITY / 1024) + 1) +#define ZT_NETWORK_MAX_UPDATE_CHUNKS ((ZT_NETWORKCONFIG_DICT_CAPACITY / 1024) + 1) namespace ZeroTier { @@ -50,445 +48,474 @@ class Peer; /** * A virtual LAN */ -class Network -{ - friend class SharedPtr; +class Network { + friend class SharedPtr; -public: - /** - * Broadcast multicast group: ff:ff:ff:ff:ff:ff / 0 - */ - static const MulticastGroup BROADCAST; + public: + /** + * Broadcast multicast group: ff:ff:ff:ff:ff:ff / 0 + */ + static const MulticastGroup BROADCAST; - /** - * Compute primary controller device ID from network ID - */ - static inline Address controllerFor(uint64_t nwid) { return Address(nwid >> 24); } + /** + * Compute primary controller device ID from network ID + */ + static inline Address controllerFor(uint64_t nwid) + { + return Address(nwid >> 24); + } - /** - * Construct a new network - * - * Note that init() should be called immediately after the network is - * constructed to actually configure the port. - * - * @param renv Runtime environment - * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call - * @param nwid Network ID - * @param uptr Arbitrary pointer used by externally-facing API (for user use) - * @param nconf Network config, if known - */ - Network(const RuntimeEnvironment *renv,void *tPtr,uint64_t nwid,void *uptr,const NetworkConfig *nconf); + /** + * Construct a new network + * + * Note that init() should be called immediately after the network is + * constructed to actually configure the port. + * + * @param renv Runtime environment + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call + * @param nwid Network ID + * @param uptr Arbitrary pointer used by externally-facing API (for user use) + * @param nconf Network config, if known + */ + Network(const RuntimeEnvironment* renv, void* tPtr, uint64_t nwid, void* uptr, const NetworkConfig* nconf); - ~Network(); + ~Network(); - inline uint64_t id() const { return _id; } - inline Address controller() const { return Address(_id >> 24); } - inline bool multicastEnabled() const { return (_config.multicastLimit > 0); } - inline bool hasConfig() const { return (_config); } - inline uint64_t lastConfigUpdate() const { return _lastConfigUpdate; } - inline ZT_VirtualNetworkStatus status() const { Mutex::Lock _l(_lock); return _status(); } - inline const NetworkConfig &config() const { return _config; } - inline const MAC &mac() const { return _mac; } + inline uint64_t id() const + { + return _id; + } + inline Address controller() const + { + return Address(_id >> 24); + } + inline bool multicastEnabled() const + { + return (_config.multicastLimit > 0); + } + inline bool hasConfig() const + { + return (_config); + } + inline uint64_t lastConfigUpdate() const + { + return _lastConfigUpdate; + } + inline ZT_VirtualNetworkStatus status() const + { + Mutex::Lock _l(_lock); + return _status(); + } + inline const NetworkConfig& config() const + { + return _config; + } + inline const MAC& mac() const + { + return _mac; + } - /** - * Apply filters to an outgoing packet - * - * This applies filters from our network config and, if that doesn't match, - * our capabilities in ascending order of capability ID. Additional actions - * such as TEE may be taken, and credentials may be pushed, so this is not - * side-effect-free. It's basically step one in sending something over VL2. - * - * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call - * @param noTee If true, do not TEE anything anywhere (for two-pass filtering as done with multicast and bridging) - * @param ztSource Source ZeroTier address - * @param ztDest Destination ZeroTier address - * @param macSource Ethernet layer source address - * @param macDest Ethernet layer destination address - * @param frameData Ethernet frame data - * @param frameLen Ethernet frame payload length - * @param etherType 16-bit ethernet type ID - * @param vlanId 16-bit VLAN ID - * @return True if packet should be sent, false if dropped or redirected - */ - bool filterOutgoingPacket( - void *tPtr, - const bool noTee, - const Address &ztSource, - const Address &ztDest, - const MAC &macSource, - const MAC &macDest, - const uint8_t *frameData, - const unsigned int frameLen, - const unsigned int etherType, - const unsigned int vlanId, - uint8_t &qosBucket); + /** + * Apply filters to an outgoing packet + * + * This applies filters from our network config and, if that doesn't match, + * our capabilities in ascending order of capability ID. Additional actions + * such as TEE may be taken, and credentials may be pushed, so this is not + * side-effect-free. It's basically step one in sending something over VL2. + * + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call + * @param noTee If true, do not TEE anything anywhere (for two-pass filtering as done with multicast and bridging) + * @param ztSource Source ZeroTier address + * @param ztDest Destination ZeroTier address + * @param macSource Ethernet layer source address + * @param macDest Ethernet layer destination address + * @param frameData Ethernet frame data + * @param frameLen Ethernet frame payload length + * @param etherType 16-bit ethernet type ID + * @param vlanId 16-bit VLAN ID + * @return True if packet should be sent, false if dropped or redirected + */ + bool filterOutgoingPacket( + void* tPtr, + const bool noTee, + const Address& ztSource, + const Address& ztDest, + const MAC& macSource, + const MAC& macDest, + const uint8_t* frameData, + const unsigned int frameLen, + const unsigned int etherType, + const unsigned int vlanId, + uint8_t& qosBucket); - /** - * Apply filters to an incoming packet - * - * This applies filters from our network config and, if that doesn't match, - * the peer's capabilities in ascending order of capability ID. If there is - * a match certain actions may be taken such as sending a copy of the packet - * to a TEE or REDIRECT target. - * - * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call - * @param sourcePeer Source Peer - * @param ztDest Destination ZeroTier address - * @param macSource Ethernet layer source address - * @param macDest Ethernet layer destination address - * @param frameData Ethernet frame data - * @param frameLen Ethernet frame payload length - * @param etherType 16-bit ethernet type ID - * @param vlanId 16-bit VLAN ID - * @return 0 == drop, 1 == accept, 2 == accept even if bridged - */ - int filterIncomingPacket( - void *tPtr, - const SharedPtr &sourcePeer, - const Address &ztDest, - const MAC &macSource, - const MAC &macDest, - const uint8_t *frameData, - const unsigned int frameLen, - const unsigned int etherType, - const unsigned int vlanId); + /** + * Apply filters to an incoming packet + * + * This applies filters from our network config and, if that doesn't match, + * the peer's capabilities in ascending order of capability ID. If there is + * a match certain actions may be taken such as sending a copy of the packet + * to a TEE or REDIRECT target. + * + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call + * @param sourcePeer Source Peer + * @param ztDest Destination ZeroTier address + * @param macSource Ethernet layer source address + * @param macDest Ethernet layer destination address + * @param frameData Ethernet frame data + * @param frameLen Ethernet frame payload length + * @param etherType 16-bit ethernet type ID + * @param vlanId 16-bit VLAN ID + * @return 0 == drop, 1 == accept, 2 == accept even if bridged + */ + int filterIncomingPacket( + void* tPtr, + const SharedPtr& sourcePeer, + const Address& ztDest, + const MAC& macSource, + const MAC& macDest, + const uint8_t* frameData, + const unsigned int frameLen, + const unsigned int etherType, + const unsigned int vlanId); - /** - * Check whether we are subscribed to a multicast group - * - * @param mg Multicast group - * @param includeBridgedGroups If true, also check groups we've learned via bridging - * @return True if this network endpoint / peer is a member - */ - bool subscribedToMulticastGroup(const MulticastGroup &mg,bool includeBridgedGroups) const; + /** + * Check whether we are subscribed to a multicast group + * + * @param mg Multicast group + * @param includeBridgedGroups If true, also check groups we've learned via bridging + * @return True if this network endpoint / peer is a member + */ + bool subscribedToMulticastGroup(const MulticastGroup& mg, bool includeBridgedGroups) const; - /** - * Subscribe to a multicast group - * - * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call - * @param mg New multicast group - */ - void multicastSubscribe(void *tPtr,const MulticastGroup &mg); + /** + * Subscribe to a multicast group + * + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call + * @param mg New multicast group + */ + void multicastSubscribe(void* tPtr, const MulticastGroup& mg); - /** - * Unsubscribe from a multicast group - * - * @param mg Multicast group - */ - void multicastUnsubscribe(const MulticastGroup &mg); + /** + * Unsubscribe from a multicast group + * + * @param mg Multicast group + */ + void multicastUnsubscribe(const MulticastGroup& mg); - /** - * Handle an inbound network config chunk - * - * This is called from IncomingPacket to handle incoming network config - * chunks via OK(NETWORK_CONFIG_REQUEST) or NETWORK_CONFIG. It verifies - * each chunk and once assembled applies the configuration. - * - * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call - * @param packetId Packet ID or 0 if none (e.g. via cluster path) - * @param source Address of sender of chunk or NULL if none (e.g. via cluster path) - * @param chunk Buffer containing chunk - * @param ptr Index of chunk and related fields in packet - * @return Update ID if update was fully assembled and accepted or 0 otherwise - */ - uint64_t handleConfigChunk(void *tPtr,const uint64_t packetId,const Address &source,const Buffer &chunk,unsigned int ptr); + /** + * Handle an inbound network config chunk + * + * This is called from IncomingPacket to handle incoming network config + * chunks via OK(NETWORK_CONFIG_REQUEST) or NETWORK_CONFIG. It verifies + * each chunk and once assembled applies the configuration. + * + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call + * @param packetId Packet ID or 0 if none (e.g. via cluster path) + * @param source Address of sender of chunk or NULL if none (e.g. via cluster path) + * @param chunk Buffer containing chunk + * @param ptr Index of chunk and related fields in packet + * @return Update ID if update was fully assembled and accepted or 0 otherwise + */ + uint64_t handleConfigChunk(void* tPtr, const uint64_t packetId, const Address& source, const Buffer& chunk, unsigned int ptr); - /** - * Set network configuration - * - * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call - * @param nconf Network configuration - * @param saveToDisk Save to disk? Used during loading, should usually be true otherwise. - * @return 0 == bad, 1 == accepted but duplicate/unchanged, 2 == accepted and new - */ - int setConfiguration(void *tPtr,const NetworkConfig &nconf,bool saveToDisk); + /** + * Set network configuration + * + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call + * @param nconf Network configuration + * @param saveToDisk Save to disk? Used during loading, should usually be true otherwise. + * @return 0 == bad, 1 == accepted but duplicate/unchanged, 2 == accepted and new + */ + int setConfiguration(void* tPtr, const NetworkConfig& nconf, bool saveToDisk); - /** - * Set netconf failure to 'access denied' -- called in IncomingPacket when controller reports this - */ - inline void setAccessDenied(void *tPtr) - { - Mutex::Lock _l(_lock); - _netconfFailure = NETCONF_FAILURE_ACCESS_DENIED; + /** + * Set netconf failure to 'access denied' -- called in IncomingPacket when controller reports this + */ + inline void setAccessDenied(void* tPtr) + { + Mutex::Lock _l(_lock); + _netconfFailure = NETCONF_FAILURE_ACCESS_DENIED; - _sendUpdateEvent(tPtr); - } + _sendUpdateEvent(tPtr); + } - /** - * Set netconf failure to 'not found' -- called by IncomingPacket when controller reports this - */ - inline void setNotFound(void *tPtr) - { - Mutex::Lock _l(_lock); - _netconfFailure = NETCONF_FAILURE_NOT_FOUND; + /** + * Set netconf failure to 'not found' -- called by IncomingPacket when controller reports this + */ + inline void setNotFound(void* tPtr) + { + Mutex::Lock _l(_lock); + _netconfFailure = NETCONF_FAILURE_NOT_FOUND; - _sendUpdateEvent(tPtr); - } + _sendUpdateEvent(tPtr); + } - /** - * Set netconf failure to 'authentication required' possibly with an authorization URL - */ - inline void setAuthenticationRequired(void *tPtr, const char *url) - { - Mutex::Lock _l(_lock); - _netconfFailure = NETCONF_FAILURE_AUTHENTICATION_REQUIRED; - _authenticationURL = (url) ? url : ""; - _config.ssoEnabled = true; - _config.ssoVersion = 0; - _sendUpdateEvent(tPtr); - } + /** + * Set netconf failure to 'authentication required' possibly with an authorization URL + */ + inline void setAuthenticationRequired(void* tPtr, const char* url) + { + Mutex::Lock _l(_lock); + _netconfFailure = NETCONF_FAILURE_AUTHENTICATION_REQUIRED; + _authenticationURL = (url) ? url : ""; + _config.ssoEnabled = true; + _config.ssoVersion = 0; + _sendUpdateEvent(tPtr); + } - /** - * set netconf failure to 'authentication required' along with info needed - * for sso full flow authentication. - */ - void setAuthenticationRequired(void *tPtr, const char* issuerURL, const char* centralEndpoint, const char* clientID, const char *ssoProvider, const char* nonce, const char* state); + /** + * set netconf failure to 'authentication required' along with info needed + * for sso full flow authentication. + */ + void setAuthenticationRequired(void* tPtr, const char* issuerURL, const char* centralEndpoint, const char* clientID, const char* ssoProvider, const char* nonce, const char* state); - /** - * Causes this network to request an updated configuration from its master node now - * - * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call - */ - void requestConfiguration(void *tPtr); + /** + * Causes this network to request an updated configuration from its master node now + * + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call + */ + void requestConfiguration(void* tPtr); - /** - * Determine whether this peer is permitted to communicate on this network - * - * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call - * @param peer Peer to check - */ - bool gate(void *tPtr,const SharedPtr &peer); + /** + * Determine whether this peer is permitted to communicate on this network + * + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call + * @param peer Peer to check + */ + bool gate(void* tPtr, const SharedPtr& peer); - /** - * Check whether a given peer has recently had an association with this network - * - * This checks whether a peer has communicated with us recently about this - * network and has possessed a valid certificate of membership. This may return - * true even if the peer has been offline for a while or no longer has a valid - * certificate of membership but had one recently. - * - * @param addr Peer address - * @return True if peer has recently associated - */ - bool recentlyAssociatedWith(const Address &addr); + /** + * Check whether a given peer has recently had an association with this network + * + * This checks whether a peer has communicated with us recently about this + * network and has possessed a valid certificate of membership. This may return + * true even if the peer has been offline for a while or no longer has a valid + * certificate of membership but had one recently. + * + * @param addr Peer address + * @return True if peer has recently associated + */ + bool recentlyAssociatedWith(const Address& addr); - /** - * Do periodic cleanup and housekeeping tasks - */ - void clean(); + /** + * Do periodic cleanup and housekeeping tasks + */ + void clean(); - /** - * Push state to members such as multicast group memberships and latest COM (if needed) - * - * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call - */ - inline void sendUpdatesToMembers(void *tPtr) - { - Mutex::Lock _l(_lock); - _sendUpdatesToMembers(tPtr,(const MulticastGroup *)0); - } + /** + * Push state to members such as multicast group memberships and latest COM (if needed) + * + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call + */ + inline void sendUpdatesToMembers(void* tPtr) + { + Mutex::Lock _l(_lock); + _sendUpdatesToMembers(tPtr, (const MulticastGroup*)0); + } - /** - * Find the node on this network that has this MAC behind it (if any) - * - * @param mac MAC address - * @return ZeroTier address of bridge to this MAC - */ - inline Address findBridgeTo(const MAC &mac) const - { - Mutex::Lock _l(_lock); - const Address *const br = _remoteBridgeRoutes.get(mac); - return ((br) ? *br : Address()); - } + /** + * Find the node on this network that has this MAC behind it (if any) + * + * @param mac MAC address + * @return ZeroTier address of bridge to this MAC + */ + inline Address findBridgeTo(const MAC& mac) const + { + Mutex::Lock _l(_lock); + const Address* const br = _remoteBridgeRoutes.get(mac); + return ((br) ? *br : Address()); + } - /** - * @return True if QoS is in effect for this network - */ - inline bool qosEnabled() { return false; } + /** + * @return True if QoS is in effect for this network + */ + inline bool qosEnabled() + { + return false; + } - /** - * Set a bridge route - * - * @param mac MAC address of destination - * @param addr Bridge this MAC is reachable behind - */ - void learnBridgeRoute(const MAC &mac,const Address &addr); + /** + * Set a bridge route + * + * @param mac MAC address of destination + * @param addr Bridge this MAC is reachable behind + */ + void learnBridgeRoute(const MAC& mac, const Address& addr); - /** - * Learn a multicast group that is bridged to our tap device - * - * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call - * @param mg Multicast group - * @param now Current time - */ - void learnBridgedMulticastGroup(void *tPtr,const MulticastGroup &mg,int64_t now); + /** + * Learn a multicast group that is bridged to our tap device + * + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call + * @param mg Multicast group + * @param now Current time + */ + void learnBridgedMulticastGroup(void* tPtr, const MulticastGroup& mg, int64_t now); - /** - * Validate a credential and learn it if it passes certificate and other checks - */ - Membership::AddCredentialResult addCredential(void *tPtr,const CertificateOfMembership &com); + /** + * Validate a credential and learn it if it passes certificate and other checks + */ + Membership::AddCredentialResult addCredential(void* tPtr, const CertificateOfMembership& com); - /** - * Validate a credential and learn it if it passes certificate and other checks - */ - inline Membership::AddCredentialResult addCredential(void *tPtr,const Capability &cap) - { - if (cap.networkId() != _id) { - return Membership::ADD_REJECTED; - } - Mutex::Lock _l(_lock); - return _membership(cap.issuedTo()).addCredential(RR,tPtr,_config,cap); - } + /** + * Validate a credential and learn it if it passes certificate and other checks + */ + inline Membership::AddCredentialResult addCredential(void* tPtr, const Capability& cap) + { + if (cap.networkId() != _id) { + return Membership::ADD_REJECTED; + } + Mutex::Lock _l(_lock); + return _membership(cap.issuedTo()).addCredential(RR, tPtr, _config, cap); + } - /** - * Validate a credential and learn it if it passes certificate and other checks - */ - inline Membership::AddCredentialResult addCredential(void *tPtr,const Tag &tag) - { - if (tag.networkId() != _id) { - return Membership::ADD_REJECTED; - } - Mutex::Lock _l(_lock); - return _membership(tag.issuedTo()).addCredential(RR,tPtr,_config,tag); - } + /** + * Validate a credential and learn it if it passes certificate and other checks + */ + inline Membership::AddCredentialResult addCredential(void* tPtr, const Tag& tag) + { + if (tag.networkId() != _id) { + return Membership::ADD_REJECTED; + } + Mutex::Lock _l(_lock); + return _membership(tag.issuedTo()).addCredential(RR, tPtr, _config, tag); + } - /** - * Validate a credential and learn it if it passes certificate and other checks - */ - Membership::AddCredentialResult addCredential(void *tPtr,const Address &sentFrom,const Revocation &rev); + /** + * Validate a credential and learn it if it passes certificate and other checks + */ + Membership::AddCredentialResult addCredential(void* tPtr, const Address& sentFrom, const Revocation& rev); - /** - * Validate a credential and learn it if it passes certificate and other checks - */ - inline Membership::AddCredentialResult addCredential(void *tPtr,const CertificateOfOwnership &coo) - { - if (coo.networkId() != _id) { - return Membership::ADD_REJECTED; - } - Mutex::Lock _l(_lock); - return _membership(coo.issuedTo()).addCredential(RR,tPtr,_config,coo); - } + /** + * Validate a credential and learn it if it passes certificate and other checks + */ + inline Membership::AddCredentialResult addCredential(void* tPtr, const CertificateOfOwnership& coo) + { + if (coo.networkId() != _id) { + return Membership::ADD_REJECTED; + } + Mutex::Lock _l(_lock); + return _membership(coo.issuedTo()).addCredential(RR, tPtr, _config, coo); + } - /** - * Force push credentials (COM, etc.) to a peer now - * - * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call - * @param to Destination peer address - * @param now Current time - */ - inline void peerRequestedCredentials(void *tPtr,const Address &to,const int64_t now) - { - Mutex::Lock _l(_lock); - Membership &m = _membership(to); - const int64_t lastPushed = m.lastPushedCredentials(); - if ((lastPushed < _lastConfigUpdate)||((now - lastPushed) > ZT_PEER_CREDENTIALS_REQUEST_RATE_LIMIT)) { - m.pushCredentials(RR,tPtr,now,to,_config); - } - } + /** + * Force push credentials (COM, etc.) to a peer now + * + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call + * @param to Destination peer address + * @param now Current time + */ + inline void peerRequestedCredentials(void* tPtr, const Address& to, const int64_t now) + { + Mutex::Lock _l(_lock); + Membership& m = _membership(to); + const int64_t lastPushed = m.lastPushedCredentials(); + if ((lastPushed < _lastConfigUpdate) || ((now - lastPushed) > ZT_PEER_CREDENTIALS_REQUEST_RATE_LIMIT)) { + m.pushCredentials(RR, tPtr, now, to, _config); + } + } - /** - * Push credentials if we haven't done so in a very long time - * - * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call - * @param to Destination peer address - * @param now Current time - */ - inline void pushCredentialsIfNeeded(void *tPtr,const Address &to,const int64_t now) - { - Mutex::Lock _l(_lock); - Membership &m = _membership(to); - const int64_t lastPushed = m.lastPushedCredentials(); - if ((lastPushed < _lastConfigUpdate)||((now - lastPushed) > ZT_PEER_ACTIVITY_TIMEOUT)) { - m.pushCredentials(RR,tPtr,now,to,_config); - } - } + /** + * Push credentials if we haven't done so in a very long time + * + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call + * @param to Destination peer address + * @param now Current time + */ + inline void pushCredentialsIfNeeded(void* tPtr, const Address& to, const int64_t now) + { + Mutex::Lock _l(_lock); + Membership& m = _membership(to); + const int64_t lastPushed = m.lastPushedCredentials(); + if ((lastPushed < _lastConfigUpdate) || ((now - lastPushed) > ZT_PEER_ACTIVITY_TIMEOUT)) { + m.pushCredentials(RR, tPtr, now, to, _config); + } + } - /** - * Destroy this network - * - * This sets the network to completely remove itself on delete. This also prevents the - * call of the normal port shutdown event on delete. - */ - void destroy(); + /** + * Destroy this network + * + * This sets the network to completely remove itself on delete. This also prevents the + * call of the normal port shutdown event on delete. + */ + void destroy(); - /** - * Get this network's config for export via the ZT core API - * - * @param ec Buffer to fill with externally-visible network configuration - */ - inline void externalConfig(ZT_VirtualNetworkConfig *ec) const - { - Mutex::Lock _l(_lock); - _externalConfig(ec); - } + /** + * Get this network's config for export via the ZT core API + * + * @param ec Buffer to fill with externally-visible network configuration + */ + inline void externalConfig(ZT_VirtualNetworkConfig* ec) const + { + Mutex::Lock _l(_lock); + _externalConfig(ec); + } - /** - * @return Externally usable pointer-to-pointer exported via the core API - */ - inline void **userPtr() { return &_uPtr; } + /** + * @return Externally usable pointer-to-pointer exported via the core API + */ + inline void** userPtr() + { + return &_uPtr; + } -private: - ZT_VirtualNetworkStatus _status() const; - void _externalConfig(ZT_VirtualNetworkConfig *ec) const; // assumes _lock is locked - bool _gate(const SharedPtr &peer); - void _sendUpdatesToMembers(void *tPtr,const MulticastGroup *const newMulticastGroup); - void _announceMulticastGroupsTo(void *tPtr,const Address &peer,const std::vector &allMulticastGroups); - std::vector _allMulticastGroups() const; - Membership &_membership(const Address &a); - void _sendUpdateEvent(void *tPtr); + private: + ZT_VirtualNetworkStatus _status() const; + void _externalConfig(ZT_VirtualNetworkConfig* ec) const; // assumes _lock is locked + bool _gate(const SharedPtr& peer); + void _sendUpdatesToMembers(void* tPtr, const MulticastGroup* const newMulticastGroup); + void _announceMulticastGroupsTo(void* tPtr, const Address& peer, const std::vector& allMulticastGroups); + std::vector _allMulticastGroups() const; + Membership& _membership(const Address& a); + void _sendUpdateEvent(void* tPtr); - const RuntimeEnvironment *const RR; - void *_uPtr; - const uint64_t _id; - std::string _nwidStr; - uint64_t _lastAnnouncedMulticastGroupsUpstream; - MAC _mac; // local MAC address - bool _portInitialized; + const RuntimeEnvironment* const RR; + void* _uPtr; + const uint64_t _id; + std::string _nwidStr; + uint64_t _lastAnnouncedMulticastGroupsUpstream; + MAC _mac; // local MAC address + bool _portInitialized; - std::vector< MulticastGroup > _myMulticastGroups; // multicast groups that we belong to (according to tap) - Hashtable< MulticastGroup,uint64_t > _multicastGroupsBehindMe; // multicast groups that seem to be behind us and when we last saw them (if we are a bridge) - Hashtable< MAC,Address > _remoteBridgeRoutes; // remote addresses where given MACs are reachable (for tracking devices behind remote bridges) + std::vector _myMulticastGroups; // multicast groups that we belong to (according to tap) + Hashtable _multicastGroupsBehindMe; // multicast groups that seem to be behind us and when we last saw them (if we are a bridge) + Hashtable _remoteBridgeRoutes; // remote addresses where given MACs are reachable (for tracking devices behind remote bridges) - NetworkConfig _config; - int64_t _lastConfigUpdate; + NetworkConfig _config; + int64_t _lastConfigUpdate; - struct _IncomingConfigChunk - { - _IncomingConfigChunk() { memset(this,0,sizeof(_IncomingConfigChunk)); } - uint64_t ts; - uint64_t updateId; - uint64_t haveChunkIds[ZT_NETWORK_MAX_UPDATE_CHUNKS]; - unsigned long haveChunks; - unsigned long haveBytes; - Dictionary data; - }; - _IncomingConfigChunk _incomingConfigChunks[ZT_NETWORK_MAX_INCOMING_UPDATES]; + struct _IncomingConfigChunk { + _IncomingConfigChunk() + { + memset(this, 0, sizeof(_IncomingConfigChunk)); + } + uint64_t ts; + uint64_t updateId; + uint64_t haveChunkIds[ZT_NETWORK_MAX_UPDATE_CHUNKS]; + unsigned long haveChunks; + unsigned long haveBytes; + Dictionary data; + }; + _IncomingConfigChunk _incomingConfigChunks[ZT_NETWORK_MAX_INCOMING_UPDATES]; - bool _destroyed; + bool _destroyed; - enum { - NETCONF_FAILURE_NONE, - NETCONF_FAILURE_ACCESS_DENIED, - NETCONF_FAILURE_NOT_FOUND, - NETCONF_FAILURE_INIT_FAILED, - NETCONF_FAILURE_AUTHENTICATION_REQUIRED - } _netconfFailure; - int _portError; // return value from port config callback - std::string _authenticationURL; + enum { NETCONF_FAILURE_NONE, NETCONF_FAILURE_ACCESS_DENIED, NETCONF_FAILURE_NOT_FOUND, NETCONF_FAILURE_INIT_FAILED, NETCONF_FAILURE_AUTHENTICATION_REQUIRED } _netconfFailure; + int _portError; // return value from port config callback + std::string _authenticationURL; - Hashtable _memberships; + Hashtable _memberships; - Mutex _lock; + Mutex _lock; - AtomicCounter __refCount; + AtomicCounter __refCount; - prometheus::simpleapi::gauge_metric_t _num_multicast_groups; - prometheus::simpleapi::counter_metric_t _incoming_packets_accepted; - prometheus::simpleapi::counter_metric_t _incoming_packets_dropped; - prometheus::simpleapi::counter_metric_t _outgoing_packets_accepted; - prometheus::simpleapi::counter_metric_t _outgoing_packets_dropped; + prometheus::simpleapi::gauge_metric_t _num_multicast_groups; + prometheus::simpleapi::counter_metric_t _incoming_packets_accepted; + prometheus::simpleapi::counter_metric_t _incoming_packets_dropped; + prometheus::simpleapi::counter_metric_t _outgoing_packets_accepted; + prometheus::simpleapi::counter_metric_t _outgoing_packets_dropped; }; -} // namespace ZeroTier +} // namespace ZeroTier #endif diff --git a/node/NetworkConfig.cpp b/node/NetworkConfig.cpp index b1c687c6..a65b6998 100644 --- a/node/NetworkConfig.cpp +++ b/node/NetworkConfig.cpp @@ -11,567 +11,583 @@ */ /****/ -#include +#include "NetworkConfig.hpp" #include - -#include "NetworkConfig.hpp" +#include namespace ZeroTier { -bool NetworkConfig::toDictionary(Dictionary &d,bool includeLegacy) const +bool NetworkConfig::toDictionary(Dictionary& d, bool includeLegacy) const { - Buffer *tmp = new Buffer(); - char tmp2[128] = {0}; + Buffer* tmp = new Buffer(); + char tmp2[128] = { 0 }; - try { - d.clear(); + try { + d.clear(); - // Try to put the more human-readable fields first + // Try to put the more human-readable fields first - if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_VERSION,(uint64_t)ZT_NETWORKCONFIG_VERSION)) { - delete tmp; - return false; - } - if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_NETWORK_ID,this->networkId)) { - delete tmp; - return false; - } - if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_TIMESTAMP,this->timestamp)) { - delete tmp; - return false; - } - if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_CREDENTIAL_TIME_MAX_DELTA,this->credentialTimeMaxDelta)) { - delete tmp; - return false; - } - if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_REVISION,this->revision)) { - delete tmp; - return false; - } - if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_ISSUED_TO,this->issuedTo.toString(tmp2))) { - delete tmp; - return false; - } - if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_REMOTE_TRACE_TARGET,this->remoteTraceTarget.toString(tmp2))) { - delete tmp; - return false; - } - if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_REMOTE_TRACE_LEVEL,(uint64_t)this->remoteTraceLevel)) { - delete tmp; - return false; - } - if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_FLAGS,this->flags)) { - delete tmp; - return false; - } - if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_MULTICAST_LIMIT,(uint64_t)this->multicastLimit)) { - delete tmp; - return false; - } - if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_TYPE,(uint64_t)this->type)) { - delete tmp; - return false; - } - if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_NAME,this->name)) { - delete tmp; - return false; - } - if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_MTU,(uint64_t)this->mtu)) { - delete tmp; - return false; - } + if (! d.add(ZT_NETWORKCONFIG_DICT_KEY_VERSION, (uint64_t)ZT_NETWORKCONFIG_VERSION)) { + delete tmp; + return false; + } + if (! d.add(ZT_NETWORKCONFIG_DICT_KEY_NETWORK_ID, this->networkId)) { + delete tmp; + return false; + } + if (! d.add(ZT_NETWORKCONFIG_DICT_KEY_TIMESTAMP, this->timestamp)) { + delete tmp; + return false; + } + if (! d.add(ZT_NETWORKCONFIG_DICT_KEY_CREDENTIAL_TIME_MAX_DELTA, this->credentialTimeMaxDelta)) { + delete tmp; + return false; + } + if (! d.add(ZT_NETWORKCONFIG_DICT_KEY_REVISION, this->revision)) { + delete tmp; + return false; + } + if (! d.add(ZT_NETWORKCONFIG_DICT_KEY_ISSUED_TO, this->issuedTo.toString(tmp2))) { + delete tmp; + return false; + } + if (! d.add(ZT_NETWORKCONFIG_DICT_KEY_REMOTE_TRACE_TARGET, this->remoteTraceTarget.toString(tmp2))) { + delete tmp; + return false; + } + if (! d.add(ZT_NETWORKCONFIG_DICT_KEY_REMOTE_TRACE_LEVEL, (uint64_t)this->remoteTraceLevel)) { + delete tmp; + return false; + } + if (! d.add(ZT_NETWORKCONFIG_DICT_KEY_FLAGS, this->flags)) { + delete tmp; + return false; + } + if (! d.add(ZT_NETWORKCONFIG_DICT_KEY_MULTICAST_LIMIT, (uint64_t)this->multicastLimit)) { + delete tmp; + return false; + } + if (! d.add(ZT_NETWORKCONFIG_DICT_KEY_TYPE, (uint64_t)this->type)) { + delete tmp; + return false; + } + if (! d.add(ZT_NETWORKCONFIG_DICT_KEY_NAME, this->name)) { + delete tmp; + return false; + } + if (! d.add(ZT_NETWORKCONFIG_DICT_KEY_MTU, (uint64_t)this->mtu)) { + delete tmp; + return false; + } #ifdef ZT_SUPPORT_OLD_STYLE_NETCONF - if (includeLegacy) { - if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_ENABLE_BROADCAST_OLD,this->enableBroadcast())) { - return false; - } - if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_PRIVATE_OLD,this->isPrivate())) { - return false; - } + if (includeLegacy) { + if (! d.add(ZT_NETWORKCONFIG_DICT_KEY_ENABLE_BROADCAST_OLD, this->enableBroadcast())) { + return false; + } + if (! d.add(ZT_NETWORKCONFIG_DICT_KEY_PRIVATE_OLD, this->isPrivate())) { + return false; + } - std::string v4s; - for(unsigned int i=0;istaticIps[i].ss_family == AF_INET) { - if (v4s.length() > 0) { - v4s.push_back(','); - } - char buf[64]; - v4s.append(this->staticIps[i].toString(buf)); - } - } - if (v4s.length() > 0) { - if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_IPV4_STATIC_OLD,v4s.c_str())) { - return false; - } - } - std::string v6s; - for(unsigned int i=0;istaticIps[i].ss_family == AF_INET6) { - if (v6s.length() > 0) { - v6s.push_back(','); - } - char buf[64]; - v6s.append(this->staticIps[i].toString(buf)); - } - } - if (v6s.length() > 0) { - if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_IPV6_STATIC_OLD,v6s.c_str())) { - return false; - } - } + std::string v4s; + for (unsigned int i = 0; i < staticIpCount; ++i) { + if (this->staticIps[i].ss_family == AF_INET) { + if (v4s.length() > 0) { + v4s.push_back(','); + } + char buf[64]; + v4s.append(this->staticIps[i].toString(buf)); + } + } + if (v4s.length() > 0) { + if (! d.add(ZT_NETWORKCONFIG_DICT_KEY_IPV4_STATIC_OLD, v4s.c_str())) { + return false; + } + } + std::string v6s; + for (unsigned int i = 0; i < staticIpCount; ++i) { + if (this->staticIps[i].ss_family == AF_INET6) { + if (v6s.length() > 0) { + v6s.push_back(','); + } + char buf[64]; + v6s.append(this->staticIps[i].toString(buf)); + } + } + if (v6s.length() > 0) { + if (! d.add(ZT_NETWORKCONFIG_DICT_KEY_IPV6_STATIC_OLD, v6s.c_str())) { + return false; + } + } - std::string ets; - unsigned int et = 0; - ZT_VirtualNetworkRuleType lastrt = ZT_NETWORK_RULE_ACTION_ACCEPT; - for(unsigned int i=0;i 0) { - ets.push_back(','); - } - char tmp2[16] = {0}; - ets.append(Utils::hex((uint16_t)et,tmp2)); - } - et = 0; - } - lastrt = rt; - } - if (ets.length() > 0) { - if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_ALLOWED_ETHERNET_TYPES_OLD,ets.c_str())) { - return false; - } - } + std::string ets; + unsigned int et = 0; + ZT_VirtualNetworkRuleType lastrt = ZT_NETWORK_RULE_ACTION_ACCEPT; + for (unsigned int i = 0; i < ruleCount; ++i) { + ZT_VirtualNetworkRuleType rt = (ZT_VirtualNetworkRuleType)(rules[i].t & 0x7f); + if (rt == ZT_NETWORK_RULE_MATCH_ETHERTYPE) { + et = rules[i].v.etherType; + } + else if (rt == ZT_NETWORK_RULE_ACTION_ACCEPT) { + if (((int)lastrt < 32) || (lastrt == ZT_NETWORK_RULE_MATCH_ETHERTYPE)) { + if (ets.length() > 0) { + ets.push_back(','); + } + char tmp2[16] = { 0 }; + ets.append(Utils::hex((uint16_t)et, tmp2)); + } + et = 0; + } + lastrt = rt; + } + if (ets.length() > 0) { + if (! d.add(ZT_NETWORKCONFIG_DICT_KEY_ALLOWED_ETHERNET_TYPES_OLD, ets.c_str())) { + return false; + } + } - if (this->com) { - if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_CERTIFICATE_OF_MEMBERSHIP_OLD,this->com.toString().c_str())) { - return false; - } - } + if (this->com) { + if (! d.add(ZT_NETWORKCONFIG_DICT_KEY_CERTIFICATE_OF_MEMBERSHIP_OLD, this->com.toString().c_str())) { + return false; + } + } - std::string ab; - for(unsigned int i=0;ispecialistCount;++i) { - if ((this->specialists[i] & ZT_NETWORKCONFIG_SPECIALIST_TYPE_ACTIVE_BRIDGE) != 0) { - if (ab.length() > 0) { - ab.push_back(','); - } - char tmp2[16] = {0}; - ab.append(Address(this->specialists[i]).toString(tmp2)); - } - } - if (ab.length() > 0) { - if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_ACTIVE_BRIDGES_OLD,ab.c_str())) { - return false; - } - } - } -#endif // ZT_SUPPORT_OLD_STYLE_NETCONF + std::string ab; + for (unsigned int i = 0; i < this->specialistCount; ++i) { + if ((this->specialists[i] & ZT_NETWORKCONFIG_SPECIALIST_TYPE_ACTIVE_BRIDGE) != 0) { + if (ab.length() > 0) { + ab.push_back(','); + } + char tmp2[16] = { 0 }; + ab.append(Address(this->specialists[i]).toString(tmp2)); + } + } + if (ab.length() > 0) { + if (! d.add(ZT_NETWORKCONFIG_DICT_KEY_ACTIVE_BRIDGES_OLD, ab.c_str())) { + return false; + } + } + } +#endif // ZT_SUPPORT_OLD_STYLE_NETCONF - // Then add binary blobs + // Then add binary blobs - if (this->com) { - tmp->clear(); - this->com.serialize(*tmp); - if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_COM,*tmp)) { - return false; - } - } + if (this->com) { + tmp->clear(); + this->com.serialize(*tmp); + if (! d.add(ZT_NETWORKCONFIG_DICT_KEY_COM, *tmp)) { + return false; + } + } - tmp->clear(); - for(unsigned int i=0;icapabilityCount;++i) { - this->capabilities[i].serialize(*tmp); - } - if (tmp->size()) { - if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_CAPABILITIES,*tmp)) { - return false; - } - } + tmp->clear(); + for (unsigned int i = 0; i < this->capabilityCount; ++i) { + this->capabilities[i].serialize(*tmp); + } + if (tmp->size()) { + if (! d.add(ZT_NETWORKCONFIG_DICT_KEY_CAPABILITIES, *tmp)) { + return false; + } + } - tmp->clear(); - for(unsigned int i=0;itagCount;++i) { - this->tags[i].serialize(*tmp); - } - if (tmp->size()) { - if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_TAGS,*tmp)) { - return false; - } - } + tmp->clear(); + for (unsigned int i = 0; i < this->tagCount; ++i) { + this->tags[i].serialize(*tmp); + } + if (tmp->size()) { + if (! d.add(ZT_NETWORKCONFIG_DICT_KEY_TAGS, *tmp)) { + return false; + } + } - tmp->clear(); - for(unsigned int i=0;icertificateOfOwnershipCount;++i) { - this->certificatesOfOwnership[i].serialize(*tmp); - } - if (tmp->size()) { - if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_CERTIFICATES_OF_OWNERSHIP,*tmp)) { - return false; - } - } + tmp->clear(); + for (unsigned int i = 0; i < this->certificateOfOwnershipCount; ++i) { + this->certificatesOfOwnership[i].serialize(*tmp); + } + if (tmp->size()) { + if (! d.add(ZT_NETWORKCONFIG_DICT_KEY_CERTIFICATES_OF_OWNERSHIP, *tmp)) { + return false; + } + } - tmp->clear(); - for(unsigned int i=0;ispecialistCount;++i) { - tmp->append((uint64_t)this->specialists[i]); - } - if (tmp->size()) { - if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_SPECIALISTS,*tmp)) { - return false; - } - } + tmp->clear(); + for (unsigned int i = 0; i < this->specialistCount; ++i) { + tmp->append((uint64_t)this->specialists[i]); + } + if (tmp->size()) { + if (! d.add(ZT_NETWORKCONFIG_DICT_KEY_SPECIALISTS, *tmp)) { + return false; + } + } - tmp->clear(); - for(unsigned int i=0;irouteCount;++i) { - reinterpret_cast(&(this->routes[i].target))->serialize(*tmp); - reinterpret_cast(&(this->routes[i].via))->serialize(*tmp); - tmp->append((uint16_t)this->routes[i].flags); - tmp->append((uint16_t)this->routes[i].metric); - } - if (tmp->size()) { - if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_ROUTES,*tmp)) { - return false; - } - } + tmp->clear(); + for (unsigned int i = 0; i < this->routeCount; ++i) { + reinterpret_cast(&(this->routes[i].target))->serialize(*tmp); + reinterpret_cast(&(this->routes[i].via))->serialize(*tmp); + tmp->append((uint16_t)this->routes[i].flags); + tmp->append((uint16_t)this->routes[i].metric); + } + if (tmp->size()) { + if (! d.add(ZT_NETWORKCONFIG_DICT_KEY_ROUTES, *tmp)) { + return false; + } + } - tmp->clear(); - for(unsigned int i=0;istaticIpCount;++i) { - this->staticIps[i].serialize(*tmp); - } - if (tmp->size()) { - if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_STATIC_IPS,*tmp)) { - return false; - } - } + tmp->clear(); + for (unsigned int i = 0; i < this->staticIpCount; ++i) { + this->staticIps[i].serialize(*tmp); + } + if (tmp->size()) { + if (! d.add(ZT_NETWORKCONFIG_DICT_KEY_STATIC_IPS, *tmp)) { + return false; + } + } - if (this->ruleCount) { - tmp->clear(); - Capability::serializeRules(*tmp,rules,ruleCount); - if (tmp->size()) { - if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_RULES,*tmp)) { - return false; - } - } - } + if (this->ruleCount) { + tmp->clear(); + Capability::serializeRules(*tmp, rules, ruleCount); + if (tmp->size()) { + if (! d.add(ZT_NETWORKCONFIG_DICT_KEY_RULES, *tmp)) { + return false; + } + } + } - tmp->clear(); - DNS::serializeDNS(*tmp, &dns); - if (tmp->size()) { - if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_DNS,*tmp)) { - return false; - } - } + tmp->clear(); + DNS::serializeDNS(*tmp, &dns); + if (tmp->size()) { + if (! d.add(ZT_NETWORKCONFIG_DICT_KEY_DNS, *tmp)) { + return false; + } + } - if (this->ssoVersion == 0) { - if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_SSO_VERSION, this->ssoVersion)) { - return false; - } - if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_SSO_ENABLED, this->ssoEnabled)) { - return false; - } + if (this->ssoVersion == 0) { + if (! d.add(ZT_NETWORKCONFIG_DICT_KEY_SSO_VERSION, this->ssoVersion)) { + return false; + } + if (! d.add(ZT_NETWORKCONFIG_DICT_KEY_SSO_ENABLED, this->ssoEnabled)) { + return false; + } - if (this->ssoEnabled) { - if (this->authenticationURL[0]) { - if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_AUTHENTICATION_URL, this->authenticationURL)) { - return false; - } - } - if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_AUTHENTICATION_EXPIRY_TIME, this->authenticationExpiryTime)) { - return false; - } - } - } else if(this->ssoVersion == 1) { - if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_SSO_VERSION, this->ssoVersion)) { - return false; - } - if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_SSO_ENABLED, this->ssoEnabled)) { - return false; - } - //if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_AUTHENTICATION_URL, this->authenticationURL)) return false; - if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_ISSUER_URL, this->issuerURL)) { - return false; - } - if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_CENTRAL_ENDPOINT_URL, this->centralAuthURL)) { - return false; - } - if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_NONCE, this->ssoNonce)) { - return false; - } - if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_STATE, this->ssoState)) { - return false; - } - if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_CLIENT_ID, this->ssoClientID)) { - return false; - } - if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_SSO_PROVIDER, this->ssoProvider)) { - return false; - } - } + if (this->ssoEnabled) { + if (this->authenticationURL[0]) { + if (! d.add(ZT_NETWORKCONFIG_DICT_KEY_AUTHENTICATION_URL, this->authenticationURL)) { + return false; + } + } + if (! d.add(ZT_NETWORKCONFIG_DICT_KEY_AUTHENTICATION_EXPIRY_TIME, this->authenticationExpiryTime)) { + return false; + } + } + } + else if (this->ssoVersion == 1) { + if (! d.add(ZT_NETWORKCONFIG_DICT_KEY_SSO_VERSION, this->ssoVersion)) { + return false; + } + if (! d.add(ZT_NETWORKCONFIG_DICT_KEY_SSO_ENABLED, this->ssoEnabled)) { + return false; + } + // if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_AUTHENTICATION_URL, this->authenticationURL)) return false; + if (! d.add(ZT_NETWORKCONFIG_DICT_KEY_ISSUER_URL, this->issuerURL)) { + return false; + } + if (! d.add(ZT_NETWORKCONFIG_DICT_KEY_CENTRAL_ENDPOINT_URL, this->centralAuthURL)) { + return false; + } + if (! d.add(ZT_NETWORKCONFIG_DICT_KEY_NONCE, this->ssoNonce)) { + return false; + } + if (! d.add(ZT_NETWORKCONFIG_DICT_KEY_STATE, this->ssoState)) { + return false; + } + if (! d.add(ZT_NETWORKCONFIG_DICT_KEY_CLIENT_ID, this->ssoClientID)) { + return false; + } + if (! d.add(ZT_NETWORKCONFIG_DICT_KEY_SSO_PROVIDER, this->ssoProvider)) { + return false; + } + } - delete tmp; - } catch ( ... ) { - delete tmp; - throw; - } + delete tmp; + } + catch (...) { + delete tmp; + throw; + } - return true; + return true; } -bool NetworkConfig::fromDictionary(const Dictionary &d) +bool NetworkConfig::fromDictionary(const Dictionary& d) { - static const NetworkConfig NIL_NC; - Buffer *tmp = new Buffer(); + static const NetworkConfig NIL_NC; + Buffer* tmp = new Buffer(); - try { - *this = NIL_NC; + try { + *this = NIL_NC; - // Fields that are always present, new or old - this->networkId = d.getUI(ZT_NETWORKCONFIG_DICT_KEY_NETWORK_ID,0); - if (!this->networkId) { - delete tmp; - return false; - } - this->timestamp = d.getUI(ZT_NETWORKCONFIG_DICT_KEY_TIMESTAMP,0); - this->credentialTimeMaxDelta = d.getUI(ZT_NETWORKCONFIG_DICT_KEY_CREDENTIAL_TIME_MAX_DELTA,0); - this->revision = d.getUI(ZT_NETWORKCONFIG_DICT_KEY_REVISION,0); - this->issuedTo = d.getUI(ZT_NETWORKCONFIG_DICT_KEY_ISSUED_TO,0); - if (!this->issuedTo) { - delete tmp; - return false; - } - this->remoteTraceTarget = d.getUI(ZT_NETWORKCONFIG_DICT_KEY_REMOTE_TRACE_TARGET); - this->remoteTraceLevel = (Trace::Level)d.getUI(ZT_NETWORKCONFIG_DICT_KEY_REMOTE_TRACE_LEVEL); - this->multicastLimit = (unsigned int)d.getUI(ZT_NETWORKCONFIG_DICT_KEY_MULTICAST_LIMIT,0); - d.get(ZT_NETWORKCONFIG_DICT_KEY_NAME,this->name,sizeof(this->name)); + // Fields that are always present, new or old + this->networkId = d.getUI(ZT_NETWORKCONFIG_DICT_KEY_NETWORK_ID, 0); + if (! this->networkId) { + delete tmp; + return false; + } + this->timestamp = d.getUI(ZT_NETWORKCONFIG_DICT_KEY_TIMESTAMP, 0); + this->credentialTimeMaxDelta = d.getUI(ZT_NETWORKCONFIG_DICT_KEY_CREDENTIAL_TIME_MAX_DELTA, 0); + this->revision = d.getUI(ZT_NETWORKCONFIG_DICT_KEY_REVISION, 0); + this->issuedTo = d.getUI(ZT_NETWORKCONFIG_DICT_KEY_ISSUED_TO, 0); + if (! this->issuedTo) { + delete tmp; + return false; + } + this->remoteTraceTarget = d.getUI(ZT_NETWORKCONFIG_DICT_KEY_REMOTE_TRACE_TARGET); + this->remoteTraceLevel = (Trace::Level)d.getUI(ZT_NETWORKCONFIG_DICT_KEY_REMOTE_TRACE_LEVEL); + this->multicastLimit = (unsigned int)d.getUI(ZT_NETWORKCONFIG_DICT_KEY_MULTICAST_LIMIT, 0); + d.get(ZT_NETWORKCONFIG_DICT_KEY_NAME, this->name, sizeof(this->name)); - this->mtu = (unsigned int)d.getUI(ZT_NETWORKCONFIG_DICT_KEY_MTU,ZT_DEFAULT_MTU); - if (this->mtu < 1280) { - this->mtu = 1280; // minimum MTU allowed by IPv6 standard and others - } else if (this->mtu > ZT_MAX_MTU) { - this->mtu = ZT_MAX_MTU; - } + this->mtu = (unsigned int)d.getUI(ZT_NETWORKCONFIG_DICT_KEY_MTU, ZT_DEFAULT_MTU); + if (this->mtu < 1280) { + this->mtu = 1280; // minimum MTU allowed by IPv6 standard and others + } + else if (this->mtu > ZT_MAX_MTU) { + this->mtu = ZT_MAX_MTU; + } - if (d.getUI(ZT_NETWORKCONFIG_DICT_KEY_VERSION,0) < 6) { - #ifdef ZT_SUPPORT_OLD_STYLE_NETCONF - char tmp2[1024] = {0}; + if (d.getUI(ZT_NETWORKCONFIG_DICT_KEY_VERSION, 0) < 6) { +#ifdef ZT_SUPPORT_OLD_STYLE_NETCONF + char tmp2[1024] = { 0 }; - // Decode legacy fields if version is old - if (d.getB(ZT_NETWORKCONFIG_DICT_KEY_ENABLE_BROADCAST_OLD)) { - this->flags |= ZT_NETWORKCONFIG_FLAG_ENABLE_BROADCAST; - } - this->flags |= ZT_NETWORKCONFIG_FLAG_ENABLE_IPV6_NDP_EMULATION; // always enable for old-style netconf - this->type = (d.getB(ZT_NETWORKCONFIG_DICT_KEY_PRIVATE_OLD,true)) ? ZT_NETWORK_TYPE_PRIVATE : ZT_NETWORK_TYPE_PUBLIC; + // Decode legacy fields if version is old + if (d.getB(ZT_NETWORKCONFIG_DICT_KEY_ENABLE_BROADCAST_OLD)) { + this->flags |= ZT_NETWORKCONFIG_FLAG_ENABLE_BROADCAST; + } + this->flags |= ZT_NETWORKCONFIG_FLAG_ENABLE_IPV6_NDP_EMULATION; // always enable for old-style netconf + this->type = (d.getB(ZT_NETWORKCONFIG_DICT_KEY_PRIVATE_OLD, true)) ? ZT_NETWORK_TYPE_PRIVATE : ZT_NETWORK_TYPE_PUBLIC; - if (d.get(ZT_NETWORKCONFIG_DICT_KEY_IPV4_STATIC_OLD,tmp2,sizeof(tmp2)) > 0) { - char *saveptr = (char *)0; - for(char *f=Utils::stok(tmp2,",",&saveptr);(f);f=Utils::stok((char *)0,",",&saveptr)) { - if (this->staticIpCount >= ZT_MAX_ZT_ASSIGNED_ADDRESSES) { - break; - } - InetAddress ip(f); - if (!ip.isNetwork()) { - this->staticIps[this->staticIpCount++] = ip; - } - } - } - if (d.get(ZT_NETWORKCONFIG_DICT_KEY_IPV6_STATIC_OLD,tmp2,sizeof(tmp2)) > 0) { - char *saveptr = (char *)0; - for(char *f=Utils::stok(tmp2,",",&saveptr);(f);f=Utils::stok((char *)0,",",&saveptr)) { - if (this->staticIpCount >= ZT_MAX_ZT_ASSIGNED_ADDRESSES) { - break; - } - InetAddress ip(f); - if (!ip.isNetwork()) { - this->staticIps[this->staticIpCount++] = ip; - } - } - } + if (d.get(ZT_NETWORKCONFIG_DICT_KEY_IPV4_STATIC_OLD, tmp2, sizeof(tmp2)) > 0) { + char* saveptr = (char*)0; + for (char* f = Utils::stok(tmp2, ",", &saveptr); (f); f = Utils::stok((char*)0, ",", &saveptr)) { + if (this->staticIpCount >= ZT_MAX_ZT_ASSIGNED_ADDRESSES) { + break; + } + InetAddress ip(f); + if (! ip.isNetwork()) { + this->staticIps[this->staticIpCount++] = ip; + } + } + } + if (d.get(ZT_NETWORKCONFIG_DICT_KEY_IPV6_STATIC_OLD, tmp2, sizeof(tmp2)) > 0) { + char* saveptr = (char*)0; + for (char* f = Utils::stok(tmp2, ",", &saveptr); (f); f = Utils::stok((char*)0, ",", &saveptr)) { + if (this->staticIpCount >= ZT_MAX_ZT_ASSIGNED_ADDRESSES) { + break; + } + InetAddress ip(f); + if (! ip.isNetwork()) { + this->staticIps[this->staticIpCount++] = ip; + } + } + } - if (d.get(ZT_NETWORKCONFIG_DICT_KEY_CERTIFICATE_OF_MEMBERSHIP_OLD,tmp2,sizeof(tmp2)) > 0) { - this->com.fromString(tmp2); - } + if (d.get(ZT_NETWORKCONFIG_DICT_KEY_CERTIFICATE_OF_MEMBERSHIP_OLD, tmp2, sizeof(tmp2)) > 0) { + this->com.fromString(tmp2); + } - if (d.get(ZT_NETWORKCONFIG_DICT_KEY_ALLOWED_ETHERNET_TYPES_OLD,tmp2,sizeof(tmp2)) > 0) { - char *saveptr = (char *)0; - for(char *f=Utils::stok(tmp2,",",&saveptr);(f);f=Utils::stok((char *)0,",",&saveptr)) { - unsigned int et = Utils::hexStrToUInt(f) & 0xffff; - if ((this->ruleCount + 2) > ZT_MAX_NETWORK_RULES) { - break; - } - if (et > 0) { - this->rules[this->ruleCount].t = (uint8_t)ZT_NETWORK_RULE_MATCH_ETHERTYPE; - this->rules[this->ruleCount].v.etherType = (uint16_t)et; - ++this->ruleCount; - } - this->rules[this->ruleCount++].t = (uint8_t)ZT_NETWORK_RULE_ACTION_ACCEPT; - } - } else { - this->rules[0].t = ZT_NETWORK_RULE_ACTION_ACCEPT; - this->ruleCount = 1; - } + if (d.get(ZT_NETWORKCONFIG_DICT_KEY_ALLOWED_ETHERNET_TYPES_OLD, tmp2, sizeof(tmp2)) > 0) { + char* saveptr = (char*)0; + for (char* f = Utils::stok(tmp2, ",", &saveptr); (f); f = Utils::stok((char*)0, ",", &saveptr)) { + unsigned int et = Utils::hexStrToUInt(f) & 0xffff; + if ((this->ruleCount + 2) > ZT_MAX_NETWORK_RULES) { + break; + } + if (et > 0) { + this->rules[this->ruleCount].t = (uint8_t)ZT_NETWORK_RULE_MATCH_ETHERTYPE; + this->rules[this->ruleCount].v.etherType = (uint16_t)et; + ++this->ruleCount; + } + this->rules[this->ruleCount++].t = (uint8_t)ZT_NETWORK_RULE_ACTION_ACCEPT; + } + } + else { + this->rules[0].t = ZT_NETWORK_RULE_ACTION_ACCEPT; + this->ruleCount = 1; + } - if (d.get(ZT_NETWORKCONFIG_DICT_KEY_ACTIVE_BRIDGES_OLD,tmp2,sizeof(tmp2)) > 0) { - char *saveptr = (char *)0; - for(char *f=Utils::stok(tmp2,",",&saveptr);(f);f=Utils::stok((char *)0,",",&saveptr)) { - this->addSpecialist(Address(Utils::hexStrToU64(f)),ZT_NETWORKCONFIG_SPECIALIST_TYPE_ACTIVE_BRIDGE); - } - } - #else - delete tmp; - return false; - #endif // ZT_SUPPORT_OLD_STYLE_NETCONF - } else { - // Otherwise we can use the new fields - this->flags = d.getUI(ZT_NETWORKCONFIG_DICT_KEY_FLAGS,0); - this->type = (ZT_VirtualNetworkType)d.getUI(ZT_NETWORKCONFIG_DICT_KEY_TYPE,(uint64_t)ZT_NETWORK_TYPE_PRIVATE); + if (d.get(ZT_NETWORKCONFIG_DICT_KEY_ACTIVE_BRIDGES_OLD, tmp2, sizeof(tmp2)) > 0) { + char* saveptr = (char*)0; + for (char* f = Utils::stok(tmp2, ",", &saveptr); (f); f = Utils::stok((char*)0, ",", &saveptr)) { + this->addSpecialist(Address(Utils::hexStrToU64(f)), ZT_NETWORKCONFIG_SPECIALIST_TYPE_ACTIVE_BRIDGE); + } + } +#else + delete tmp; + return false; +#endif // ZT_SUPPORT_OLD_STYLE_NETCONF + } + else { + // Otherwise we can use the new fields + this->flags = d.getUI(ZT_NETWORKCONFIG_DICT_KEY_FLAGS, 0); + this->type = (ZT_VirtualNetworkType)d.getUI(ZT_NETWORKCONFIG_DICT_KEY_TYPE, (uint64_t)ZT_NETWORK_TYPE_PRIVATE); - if (d.get(ZT_NETWORKCONFIG_DICT_KEY_COM,*tmp)) { - this->com.deserialize(*tmp,0); - } + if (d.get(ZT_NETWORKCONFIG_DICT_KEY_COM, *tmp)) { + this->com.deserialize(*tmp, 0); + } - if (d.get(ZT_NETWORKCONFIG_DICT_KEY_CAPABILITIES,*tmp)) { - try { - unsigned int p = 0; - while (p < tmp->size()) { - Capability cap; - p += cap.deserialize(*tmp,p); - this->capabilities[this->capabilityCount++] = cap; - } - } catch ( ... ) {} - std::sort(&(this->capabilities[0]),&(this->capabilities[this->capabilityCount])); - } + if (d.get(ZT_NETWORKCONFIG_DICT_KEY_CAPABILITIES, *tmp)) { + try { + unsigned int p = 0; + while (p < tmp->size()) { + Capability cap; + p += cap.deserialize(*tmp, p); + this->capabilities[this->capabilityCount++] = cap; + } + } + catch (...) { + } + std::sort(&(this->capabilities[0]), &(this->capabilities[this->capabilityCount])); + } - if (d.get(ZT_NETWORKCONFIG_DICT_KEY_TAGS,*tmp)) { - try { - unsigned int p = 0; - while (p < tmp->size()) { - Tag tag; - p += tag.deserialize(*tmp,p); - this->tags[this->tagCount++] = tag; - } - } catch ( ... ) {} - std::sort(&(this->tags[0]),&(this->tags[this->tagCount])); - } + if (d.get(ZT_NETWORKCONFIG_DICT_KEY_TAGS, *tmp)) { + try { + unsigned int p = 0; + while (p < tmp->size()) { + Tag tag; + p += tag.deserialize(*tmp, p); + this->tags[this->tagCount++] = tag; + } + } + catch (...) { + } + std::sort(&(this->tags[0]), &(this->tags[this->tagCount])); + } - if (d.get(ZT_NETWORKCONFIG_DICT_KEY_CERTIFICATES_OF_OWNERSHIP,*tmp)) { - unsigned int p = 0; - while (p < tmp->size()) { - if (certificateOfOwnershipCount < ZT_MAX_CERTIFICATES_OF_OWNERSHIP) { - p += certificatesOfOwnership[certificateOfOwnershipCount++].deserialize(*tmp,p); - } else { - CertificateOfOwnership foo; - p += foo.deserialize(*tmp,p); - } - } - } + if (d.get(ZT_NETWORKCONFIG_DICT_KEY_CERTIFICATES_OF_OWNERSHIP, *tmp)) { + unsigned int p = 0; + while (p < tmp->size()) { + if (certificateOfOwnershipCount < ZT_MAX_CERTIFICATES_OF_OWNERSHIP) { + p += certificatesOfOwnership[certificateOfOwnershipCount++].deserialize(*tmp, p); + } + else { + CertificateOfOwnership foo; + p += foo.deserialize(*tmp, p); + } + } + } - if (d.get(ZT_NETWORKCONFIG_DICT_KEY_SPECIALISTS,*tmp)) { - unsigned int p = 0; - while ((p + 8) <= tmp->size()) { - if (specialistCount < ZT_MAX_NETWORK_SPECIALISTS) { - this->specialists[this->specialistCount++] = tmp->at(p); - } - p += 8; - } - } + if (d.get(ZT_NETWORKCONFIG_DICT_KEY_SPECIALISTS, *tmp)) { + unsigned int p = 0; + while ((p + 8) <= tmp->size()) { + if (specialistCount < ZT_MAX_NETWORK_SPECIALISTS) { + this->specialists[this->specialistCount++] = tmp->at(p); + } + p += 8; + } + } - if (d.get(ZT_NETWORKCONFIG_DICT_KEY_ROUTES,*tmp)) { - unsigned int p = 0; - while ((p < tmp->size())&&(routeCount < ZT_MAX_NETWORK_ROUTES)) { - p += reinterpret_cast(&(this->routes[this->routeCount].target))->deserialize(*tmp,p); - p += reinterpret_cast(&(this->routes[this->routeCount].via))->deserialize(*tmp,p); - this->routes[this->routeCount].flags = tmp->at(p); - p += 2; - this->routes[this->routeCount].metric = tmp->at(p); - p += 2; - ++this->routeCount; - } - } + if (d.get(ZT_NETWORKCONFIG_DICT_KEY_ROUTES, *tmp)) { + unsigned int p = 0; + while ((p < tmp->size()) && (routeCount < ZT_MAX_NETWORK_ROUTES)) { + p += reinterpret_cast(&(this->routes[this->routeCount].target))->deserialize(*tmp, p); + p += reinterpret_cast(&(this->routes[this->routeCount].via))->deserialize(*tmp, p); + this->routes[this->routeCount].flags = tmp->at(p); + p += 2; + this->routes[this->routeCount].metric = tmp->at(p); + p += 2; + ++this->routeCount; + } + } - if (d.get(ZT_NETWORKCONFIG_DICT_KEY_STATIC_IPS,*tmp)) { - unsigned int p = 0; - while ((p < tmp->size())&&(staticIpCount < ZT_MAX_ZT_ASSIGNED_ADDRESSES)) { - p += this->staticIps[this->staticIpCount++].deserialize(*tmp,p); - } - } + if (d.get(ZT_NETWORKCONFIG_DICT_KEY_STATIC_IPS, *tmp)) { + unsigned int p = 0; + while ((p < tmp->size()) && (staticIpCount < ZT_MAX_ZT_ASSIGNED_ADDRESSES)) { + p += this->staticIps[this->staticIpCount++].deserialize(*tmp, p); + } + } - if (d.get(ZT_NETWORKCONFIG_DICT_KEY_RULES,*tmp)) { - this->ruleCount = 0; - unsigned int p = 0; - Capability::deserializeRules(*tmp,p,this->rules,this->ruleCount,ZT_MAX_NETWORK_RULES); - } + if (d.get(ZT_NETWORKCONFIG_DICT_KEY_RULES, *tmp)) { + this->ruleCount = 0; + unsigned int p = 0; + Capability::deserializeRules(*tmp, p, this->rules, this->ruleCount, ZT_MAX_NETWORK_RULES); + } - if (d.get(ZT_NETWORKCONFIG_DICT_KEY_DNS, *tmp)) { - unsigned int p = 0; - DNS::deserializeDNS(*tmp, p, &dns); - } + if (d.get(ZT_NETWORKCONFIG_DICT_KEY_DNS, *tmp)) { + unsigned int p = 0; + DNS::deserializeDNS(*tmp, p, &dns); + } - this->ssoVersion = d.getUI(ZT_NETWORKCONFIG_DICT_KEY_SSO_VERSION, 0ULL); - this->ssoEnabled = d.getB(ZT_NETWORKCONFIG_DICT_KEY_SSO_ENABLED, false); + this->ssoVersion = d.getUI(ZT_NETWORKCONFIG_DICT_KEY_SSO_VERSION, 0ULL); + this->ssoEnabled = d.getB(ZT_NETWORKCONFIG_DICT_KEY_SSO_ENABLED, false); - if (this->ssoVersion == 0) { - // implicit flow - if (this->ssoEnabled) { - if (d.get(ZT_NETWORKCONFIG_DICT_KEY_AUTHENTICATION_URL, this->authenticationURL, (unsigned int)sizeof(this->authenticationURL)) > 0) { - this->authenticationURL[sizeof(this->authenticationURL) - 1] = 0; // ensure null terminated - } else { - this->authenticationURL[0] = 0; - } - this->authenticationExpiryTime = d.getI(ZT_NETWORKCONFIG_DICT_KEY_AUTHENTICATION_EXPIRY_TIME, 0); - } else { - this->authenticationURL[0] = 0; - this->authenticationExpiryTime = 0; - } - } else if (this->ssoVersion == 1) { - // full flow - if (this->ssoEnabled) { - if (d.get(ZT_NETWORKCONFIG_DICT_KEY_AUTHENTICATION_URL, this->authenticationURL, (unsigned int)sizeof(this->authenticationURL)) > 0) { - this->authenticationURL[sizeof(this->authenticationURL) - 1] = 0; - } - if (d.get(ZT_NETWORKCONFIG_DICT_KEY_ISSUER_URL, this->issuerURL, (unsigned int)sizeof(this->issuerURL)) > 0) { - this->issuerURL[sizeof(this->issuerURL) - 1] = 0; - } - if (d.get(ZT_NETWORKCONFIG_DICT_KEY_CENTRAL_ENDPOINT_URL, this->centralAuthURL, (unsigned int)sizeof(this->centralAuthURL)) > 0) { - this->centralAuthURL[sizeof(this->centralAuthURL) - 1] = 0; - } - if (d.get(ZT_NETWORKCONFIG_DICT_KEY_NONCE, this->ssoNonce, (unsigned int)sizeof(this->ssoNonce)) > 0) { - this->ssoNonce[sizeof(this->ssoNonce) - 1] = 0; - } - if (d.get(ZT_NETWORKCONFIG_DICT_KEY_STATE, this->ssoState, (unsigned int)sizeof(this->ssoState)) > 0) { - this->ssoState[sizeof(this->ssoState) - 1] = 0; - } - if (d.get(ZT_NETWORKCONFIG_DICT_KEY_CLIENT_ID, this->ssoClientID, (unsigned int)sizeof(this->ssoClientID)) > 0) { - this->ssoClientID[sizeof(this->ssoClientID) - 1] = 0; - } - if (d.get(ZT_NETWORKCONFIG_DICT_KEY_SSO_PROVIDER, this->ssoProvider, (unsigned int)(sizeof(this->ssoProvider))) > 0) { - this->ssoProvider[sizeof(this->ssoProvider) - 1] = 0; - } else { - strncpy(this->ssoProvider, "default", sizeof(this->ssoProvider)); - this->ssoProvider[sizeof(this->ssoProvider) - 1] = 0; - } - } else { - this->authenticationURL[0] = 0; - this->authenticationExpiryTime = 0; - this->centralAuthURL[0] = 0; - this->ssoNonce[0] = 0; - this->ssoState[0] = 0; - this->ssoClientID[0] = 0; - this->issuerURL[0] = 0; - this->ssoProvider[0] = 0; - } - } - } + if (this->ssoVersion == 0) { + // implicit flow + if (this->ssoEnabled) { + if (d.get(ZT_NETWORKCONFIG_DICT_KEY_AUTHENTICATION_URL, this->authenticationURL, (unsigned int)sizeof(this->authenticationURL)) > 0) { + this->authenticationURL[sizeof(this->authenticationURL) - 1] = 0; // ensure null terminated + } + else { + this->authenticationURL[0] = 0; + } + this->authenticationExpiryTime = d.getI(ZT_NETWORKCONFIG_DICT_KEY_AUTHENTICATION_EXPIRY_TIME, 0); + } + else { + this->authenticationURL[0] = 0; + this->authenticationExpiryTime = 0; + } + } + else if (this->ssoVersion == 1) { + // full flow + if (this->ssoEnabled) { + if (d.get(ZT_NETWORKCONFIG_DICT_KEY_AUTHENTICATION_URL, this->authenticationURL, (unsigned int)sizeof(this->authenticationURL)) > 0) { + this->authenticationURL[sizeof(this->authenticationURL) - 1] = 0; + } + if (d.get(ZT_NETWORKCONFIG_DICT_KEY_ISSUER_URL, this->issuerURL, (unsigned int)sizeof(this->issuerURL)) > 0) { + this->issuerURL[sizeof(this->issuerURL) - 1] = 0; + } + if (d.get(ZT_NETWORKCONFIG_DICT_KEY_CENTRAL_ENDPOINT_URL, this->centralAuthURL, (unsigned int)sizeof(this->centralAuthURL)) > 0) { + this->centralAuthURL[sizeof(this->centralAuthURL) - 1] = 0; + } + if (d.get(ZT_NETWORKCONFIG_DICT_KEY_NONCE, this->ssoNonce, (unsigned int)sizeof(this->ssoNonce)) > 0) { + this->ssoNonce[sizeof(this->ssoNonce) - 1] = 0; + } + if (d.get(ZT_NETWORKCONFIG_DICT_KEY_STATE, this->ssoState, (unsigned int)sizeof(this->ssoState)) > 0) { + this->ssoState[sizeof(this->ssoState) - 1] = 0; + } + if (d.get(ZT_NETWORKCONFIG_DICT_KEY_CLIENT_ID, this->ssoClientID, (unsigned int)sizeof(this->ssoClientID)) > 0) { + this->ssoClientID[sizeof(this->ssoClientID) - 1] = 0; + } + if (d.get(ZT_NETWORKCONFIG_DICT_KEY_SSO_PROVIDER, this->ssoProvider, (unsigned int)(sizeof(this->ssoProvider))) > 0) { + this->ssoProvider[sizeof(this->ssoProvider) - 1] = 0; + } + else { + strncpy(this->ssoProvider, "default", sizeof(this->ssoProvider)); + this->ssoProvider[sizeof(this->ssoProvider) - 1] = 0; + } + } + else { + this->authenticationURL[0] = 0; + this->authenticationExpiryTime = 0; + this->centralAuthURL[0] = 0; + this->ssoNonce[0] = 0; + this->ssoState[0] = 0; + this->ssoClientID[0] = 0; + this->issuerURL[0] = 0; + this->ssoProvider[0] = 0; + } + } + } - //printf("~~~\n%s\n~~~\n",d.data()); - //dump(); - //printf("~~~\n"); + // printf("~~~\n%s\n~~~\n",d.data()); + // dump(); + // printf("~~~\n"); - delete tmp; - return true; - } catch ( ... ) { - delete tmp; - return false; - } + delete tmp; + return true; + } + catch (...) { + delete tmp; + return false; + } } -} // namespace ZeroTier +} // namespace ZeroTier diff --git a/node/NetworkConfig.hpp b/node/NetworkConfig.hpp index 65e4c836..7f9c4d9a 100644 --- a/node/NetworkConfig.hpp +++ b/node/NetworkConfig.hpp @@ -14,31 +14,29 @@ #ifndef ZT_NETWORKCONFIG_HPP #define ZT_NETWORKCONFIG_HPP -#include -#include -#include - -#include -#include -#include - #include "../include/ZeroTierOne.h" - -#include "Constants.hpp" -#include "Buffer.hpp" -#include "DNS.hpp" -#include "InetAddress.hpp" -#include "MulticastGroup.hpp" #include "Address.hpp" +#include "Buffer.hpp" +#include "Capability.hpp" #include "CertificateOfMembership.hpp" #include "CertificateOfOwnership.hpp" -#include "Capability.hpp" -#include "Tag.hpp" +#include "Constants.hpp" +#include "DNS.hpp" #include "Dictionary.hpp" #include "Hashtable.hpp" #include "Identity.hpp" -#include "Utils.hpp" +#include "InetAddress.hpp" +#include "MulticastGroup.hpp" +#include "Tag.hpp" #include "Trace.hpp" +#include "Utils.hpp" + +#include +#include +#include +#include +#include +#include /** * Default time delta for COMs, tags, and capabilities @@ -93,7 +91,9 @@ namespace ZeroTier { // Dictionary capacity needed for max size network config -#define ZT_NETWORKCONFIG_DICT_CAPACITY (4096 + (sizeof(ZT_VirtualNetworkConfig)) + (sizeof(ZT_VirtualNetworkRule) * ZT_MAX_NETWORK_RULES) + (sizeof(Capability) * ZT_MAX_NETWORK_CAPABILITIES) + (sizeof(Tag) * ZT_MAX_NETWORK_TAGS) + (sizeof(CertificateOfOwnership) * ZT_MAX_CERTIFICATES_OF_OWNERSHIP)) +#define ZT_NETWORKCONFIG_DICT_CAPACITY \ + (4096 + (sizeof(ZT_VirtualNetworkConfig)) + (sizeof(ZT_VirtualNetworkRule) * ZT_MAX_NETWORK_RULES) + (sizeof(Capability) * ZT_MAX_NETWORK_CAPABILITIES) + (sizeof(Tag) * ZT_MAX_NETWORK_TAGS) \ + + (sizeof(CertificateOfOwnership) * ZT_MAX_CERTIFICATES_OF_OWNERSHIP)) // Dictionary capacity needed for max size network meta-data #define ZT_NETWORKCONFIG_METADATA_DICT_CAPACITY 1024 @@ -248,487 +248,507 @@ namespace ZeroTier { * This is a memcpy()'able structure and is safe (in a crash sense) to modify * without locks. */ -class NetworkConfig -{ -public: - NetworkConfig() : - networkId(0), - timestamp(0), - credentialTimeMaxDelta(0), - revision(0), - issuedTo(), - remoteTraceTarget(), - flags(0), - remoteTraceLevel(Trace::LEVEL_NORMAL), - mtu(0), - multicastLimit(0), - specialistCount(0), - routeCount(0), - staticIpCount(0), - ruleCount(0), - capabilityCount(0), - tagCount(0), - certificateOfOwnershipCount(0), - capabilities(), - tags(), - certificatesOfOwnership(), - type(ZT_NETWORK_TYPE_PRIVATE), - dnsCount(0), - ssoEnabled(false), - authenticationURL(), - authenticationExpiryTime(0), - issuerURL(), - centralAuthURL(), - ssoNonce(), - ssoState(), - ssoClientID() - { - name[0] = 0; - memset(specialists, 0, sizeof(uint64_t)*ZT_MAX_NETWORK_SPECIALISTS); - memset(routes, 0, sizeof(ZT_VirtualNetworkRoute)*ZT_MAX_NETWORK_ROUTES); - memset(staticIps, 0, sizeof(InetAddress)*ZT_MAX_ZT_ASSIGNED_ADDRESSES); - memset(rules, 0, sizeof(ZT_VirtualNetworkRule)*ZT_MAX_NETWORK_RULES); - memset(&dns, 0, sizeof(ZT_VirtualNetworkDNS)); - memset(authenticationURL, 0, sizeof(authenticationURL)); - memset(issuerURL, 0, sizeof(issuerURL)); - memset(centralAuthURL, 0, sizeof(centralAuthURL)); - memset(ssoNonce, 0, sizeof(ssoNonce)); - memset(ssoState, 0, sizeof(ssoState)); - memset(ssoClientID, 0, sizeof(ssoClientID)); - strncpy(ssoProvider, "default", sizeof(ssoProvider)); - } +class NetworkConfig { + public: + NetworkConfig() + : networkId(0) + , timestamp(0) + , credentialTimeMaxDelta(0) + , revision(0) + , issuedTo() + , remoteTraceTarget() + , flags(0) + , remoteTraceLevel(Trace::LEVEL_NORMAL) + , mtu(0) + , multicastLimit(0) + , specialistCount(0) + , routeCount(0) + , staticIpCount(0) + , ruleCount(0) + , capabilityCount(0) + , tagCount(0) + , certificateOfOwnershipCount(0) + , capabilities() + , tags() + , certificatesOfOwnership() + , type(ZT_NETWORK_TYPE_PRIVATE) + , dnsCount(0) + , ssoEnabled(false) + , authenticationURL() + , authenticationExpiryTime(0) + , issuerURL() + , centralAuthURL() + , ssoNonce() + , ssoState() + , ssoClientID() + { + name[0] = 0; + memset(specialists, 0, sizeof(uint64_t) * ZT_MAX_NETWORK_SPECIALISTS); + memset(routes, 0, sizeof(ZT_VirtualNetworkRoute) * ZT_MAX_NETWORK_ROUTES); + memset(staticIps, 0, sizeof(InetAddress) * ZT_MAX_ZT_ASSIGNED_ADDRESSES); + memset(rules, 0, sizeof(ZT_VirtualNetworkRule) * ZT_MAX_NETWORK_RULES); + memset(&dns, 0, sizeof(ZT_VirtualNetworkDNS)); + memset(authenticationURL, 0, sizeof(authenticationURL)); + memset(issuerURL, 0, sizeof(issuerURL)); + memset(centralAuthURL, 0, sizeof(centralAuthURL)); + memset(ssoNonce, 0, sizeof(ssoNonce)); + memset(ssoState, 0, sizeof(ssoState)); + memset(ssoClientID, 0, sizeof(ssoClientID)); + strncpy(ssoProvider, "default", sizeof(ssoProvider)); + } - /** - * Write this network config to a dictionary for transport - * - * @param d Dictionary - * @param includeLegacy If true, include legacy fields for old node versions - * @return True if dictionary was successfully created, false if e.g. overflow - */ - bool toDictionary(Dictionary &d,bool includeLegacy) const; + /** + * Write this network config to a dictionary for transport + * + * @param d Dictionary + * @param includeLegacy If true, include legacy fields for old node versions + * @return True if dictionary was successfully created, false if e.g. overflow + */ + bool toDictionary(Dictionary& d, bool includeLegacy) const; - /** - * Read this network config from a dictionary - * - * @param d Dictionary (non-const since it might be modified during parse, should not be used after call) - * @return True if dictionary was valid and network config successfully initialized - */ - bool fromDictionary(const Dictionary &d); + /** + * Read this network config from a dictionary + * + * @param d Dictionary (non-const since it might be modified during parse, should not be used after call) + * @return True if dictionary was valid and network config successfully initialized + */ + bool fromDictionary(const Dictionary& d); - /** - * @return True if broadcast (ff:ff:ff:ff:ff:ff) address should work on this network - */ - inline bool enableBroadcast() const { return ((this->flags & ZT_NETWORKCONFIG_FLAG_ENABLE_BROADCAST) != 0); } + /** + * @return True if broadcast (ff:ff:ff:ff:ff:ff) address should work on this network + */ + inline bool enableBroadcast() const + { + return ((this->flags & ZT_NETWORKCONFIG_FLAG_ENABLE_BROADCAST) != 0); + } - /** - * @return True if IPv6 NDP emulation should be allowed for certain "magic" IPv6 address patterns - */ - inline bool ndpEmulation() const { return ((this->flags & ZT_NETWORKCONFIG_FLAG_ENABLE_IPV6_NDP_EMULATION) != 0); } + /** + * @return True if IPv6 NDP emulation should be allowed for certain "magic" IPv6 address patterns + */ + inline bool ndpEmulation() const + { + return ((this->flags & ZT_NETWORKCONFIG_FLAG_ENABLE_IPV6_NDP_EMULATION) != 0); + } - /** - * @return True if frames should not be compressed - */ - inline bool disableCompression() const - { + /** + * @return True if frames should not be compressed + */ + inline bool disableCompression() const + { #ifndef ZT_DISABLE_COMPRESSION - return ((this->flags & ZT_NETWORKCONFIG_FLAG_DISABLE_COMPRESSION) != 0); + return ((this->flags & ZT_NETWORKCONFIG_FLAG_DISABLE_COMPRESSION) != 0); #else - /* Compression is disabled for libzt builds since it causes non-obvious chaotic - interference with lwIP's TCP congestion algorithm. Compression is also disabled - for some NAS builds due to the usage of low-performance processors in certain - older and budget models. */ - return false; + /* Compression is disabled for libzt builds since it causes non-obvious chaotic + interference with lwIP's TCP congestion algorithm. Compression is also disabled + for some NAS builds due to the usage of low-performance processors in certain + older and budget models. */ + return false; #endif - } + } - /** - * @return Network type is public (no access control) - */ - inline bool isPublic() const { return (this->type == ZT_NETWORK_TYPE_PUBLIC); } + /** + * @return Network type is public (no access control) + */ + inline bool isPublic() const + { + return (this->type == ZT_NETWORK_TYPE_PUBLIC); + } - /** - * @return Network type is private (certificate access control) - */ - inline bool isPrivate() const { return (this->type == ZT_NETWORK_TYPE_PRIVATE); } + /** + * @return Network type is private (certificate access control) + */ + inline bool isPrivate() const + { + return (this->type == ZT_NETWORK_TYPE_PRIVATE); + } - /** - * @return ZeroTier addresses of devices on this network designated as active bridges - */ - inline std::vector
activeBridges() const - { - std::vector
r; - for(unsigned int i=0;i activeBridges() const + { + std::vector
r; + for (unsigned int i = 0; i < specialistCount; ++i) { + if ((specialists[i] & ZT_NETWORKCONFIG_SPECIALIST_TYPE_ACTIVE_BRIDGE) != 0) { + r.push_back(Address(specialists[i])); + } + } + return r; + } - inline unsigned int activeBridges(Address ab[ZT_MAX_NETWORK_SPECIALISTS]) const - { - unsigned int c = 0; - for(unsigned int i=0;i anchors() const - { - std::vector
r; - for(unsigned int i=0;i anchors() const + { + std::vector
r; + for (unsigned int i = 0; i < specialistCount; ++i) { + if ((specialists[i] & ZT_NETWORKCONFIG_SPECIALIST_TYPE_ANCHOR) != 0) { + r.push_back(Address(specialists[i])); + } + } + return r; + } - inline std::vector
multicastReplicators() const - { - std::vector
r; - for(unsigned int i=0;i multicastReplicators() const + { + std::vector
r; + for (unsigned int i = 0; i < specialistCount; ++i) { + if ((specialists[i] & ZT_NETWORKCONFIG_SPECIALIST_TYPE_MULTICAST_REPLICATOR) != 0) { + r.push_back(Address(specialists[i])); + } + } + return r; + } - inline unsigned int multicastReplicators(Address mr[ZT_MAX_NETWORK_SPECIALISTS]) const - { - unsigned int c = 0; - for(unsigned int i=0;i alwaysContactAddresses() const - { - std::vector
r; - for(unsigned int i=0;i alwaysContactAddresses() const + { + std::vector
r; + for (unsigned int i = 0; i < specialistCount; ++i) { + if ((specialists[i] & (ZT_NETWORKCONFIG_SPECIALIST_TYPE_ANCHOR | ZT_NETWORKCONFIG_SPECIALIST_TYPE_MULTICAST_REPLICATOR)) != 0) { + r.push_back(Address(specialists[i])); + } + } + return r; + } - inline unsigned int alwaysContactAddresses(Address ac[ZT_MAX_NETWORK_SPECIALISTS]) const - { - unsigned int c = 0; - for(unsigned int i=0;i > &a) const - { - for(unsigned int i=0;i >& a) const + { + for (unsigned int i = 0; i < specialistCount; ++i) { + if ((specialists[i] & (ZT_NETWORKCONFIG_SPECIALIST_TYPE_ANCHOR | ZT_NETWORKCONFIG_SPECIALIST_TYPE_MULTICAST_REPLICATOR)) != 0) { + a[Address(specialists[i])]; + } + } + } - /** - * @param fromPeer Peer attempting to bridge other Ethernet peers onto network - * @return True if this network allows bridging - */ - inline bool permitsBridging(const Address &fromPeer) const - { - for(unsigned int i=0;i= 1 - */ - uint64_t authenticationExpiryTime; + /** + * Time current authentication expires or 0 if external authentication is disabled + * + * Not used if authVersion >= 1 + */ + uint64_t authenticationExpiryTime; - /** - * OIDC issuer URL - */ - char issuerURL[2048]; + /** + * OIDC issuer URL + */ + char issuerURL[2048]; - /** - * central base URL. - */ - char centralAuthURL[2048]; + /** + * central base URL. + */ + char centralAuthURL[2048]; - /** - * sso nonce - */ - char ssoNonce[128]; + /** + * sso nonce + */ + char ssoNonce[128]; - /** - * sso state - */ - char ssoState[256]; + /** + * sso state + */ + char ssoState[256]; - /** - * oidc client id - */ - char ssoClientID[256]; + /** + * oidc client id + */ + char ssoClientID[256]; - /** - * oidc provider - * - * because certain providers require specific scopes to be requested - * and others to be not requested in order to make everything work - * correctly - **/ - char ssoProvider[64]; + /** + * oidc provider + * + * because certain providers require specific scopes to be requested + * and others to be not requested in order to make everything work + * correctly + **/ + char ssoProvider[64]; }; -} // namespace ZeroTier +} // namespace ZeroTier #endif diff --git a/node/NetworkController.hpp b/node/NetworkController.hpp index bae63c8c..8a9c04bc 100644 --- a/node/NetworkController.hpp +++ b/node/NetworkController.hpp @@ -14,13 +14,13 @@ #ifndef ZT_NETWORKCONFIGMASTER_HPP #define ZT_NETWORKCONFIGMASTER_HPP -#include - +#include "Address.hpp" #include "Constants.hpp" #include "Dictionary.hpp" #include "NetworkConfig.hpp" #include "Revocation.hpp" -#include "Address.hpp" + +#include namespace ZeroTier { @@ -30,88 +30,78 @@ struct InetAddress; /** * Interface for network controller implementations */ -class NetworkController -{ -public: - enum ErrorCode - { - NC_ERROR_NONE = 0, - NC_ERROR_OBJECT_NOT_FOUND = 1, - NC_ERROR_ACCESS_DENIED = 2, - NC_ERROR_INTERNAL_SERVER_ERROR = 3, - NC_ERROR_AUTHENTICATION_REQUIRED = 4 - }; +class NetworkController { + public: + enum ErrorCode { NC_ERROR_NONE = 0, NC_ERROR_OBJECT_NOT_FOUND = 1, NC_ERROR_ACCESS_DENIED = 2, NC_ERROR_INTERNAL_SERVER_ERROR = 3, NC_ERROR_AUTHENTICATION_REQUIRED = 4 }; - /** - * Interface for sender used to send pushes and replies - */ - class Sender - { - public: - /** - * Send a configuration to a remote peer - * - * @param nwid Network ID - * @param requestPacketId Request packet ID to send OK(NETWORK_CONFIG_REQUEST) or 0 to send NETWORK_CONFIG (push) - * @param destination Destination peer Address - * @param nc Network configuration to send - * @param sendLegacyFormatConfig If true, send an old-format network config - */ - virtual void ncSendConfig(uint64_t nwid,uint64_t requestPacketId,const Address &destination,const NetworkConfig &nc,bool sendLegacyFormatConfig) = 0; + /** + * Interface for sender used to send pushes and replies + */ + class Sender { + public: + /** + * Send a configuration to a remote peer + * + * @param nwid Network ID + * @param requestPacketId Request packet ID to send OK(NETWORK_CONFIG_REQUEST) or 0 to send NETWORK_CONFIG (push) + * @param destination Destination peer Address + * @param nc Network configuration to send + * @param sendLegacyFormatConfig If true, send an old-format network config + */ + virtual void ncSendConfig(uint64_t nwid, uint64_t requestPacketId, const Address& destination, const NetworkConfig& nc, bool sendLegacyFormatConfig) = 0; - /** - * Send revocation to a node - * - * @param destination Destination node address - * @param rev Revocation to send - */ - virtual void ncSendRevocation(const Address &destination,const Revocation &rev) = 0; + /** + * Send revocation to a node + * + * @param destination Destination node address + * @param rev Revocation to send + */ + virtual void ncSendRevocation(const Address& destination, const Revocation& rev) = 0; - /** - * Send a network configuration request error - * - * If errorData/errorDataSize are provided they must point to a valid serialized - * Dictionary containing error data. They can be null/zero if not specified. - * - * @param nwid Network ID - * @param requestPacketId Request packet ID or 0 if none - * @param destination Destination peer Address - * @param errorCode Error code - * @param errorData Data associated with error or NULL if none - * @param errorDataSize Size of errorData in bytes - */ - virtual void ncSendError(uint64_t nwid,uint64_t requestPacketId,const Address &destination,NetworkController::ErrorCode errorCode, const void *errorData, unsigned int errorDataSize) = 0; - }; + /** + * Send a network configuration request error + * + * If errorData/errorDataSize are provided they must point to a valid serialized + * Dictionary containing error data. They can be null/zero if not specified. + * + * @param nwid Network ID + * @param requestPacketId Request packet ID or 0 if none + * @param destination Destination peer Address + * @param errorCode Error code + * @param errorData Data associated with error or NULL if none + * @param errorDataSize Size of errorData in bytes + */ + virtual void ncSendError(uint64_t nwid, uint64_t requestPacketId, const Address& destination, NetworkController::ErrorCode errorCode, const void* errorData, unsigned int errorDataSize) = 0; + }; - NetworkController() {} - virtual ~NetworkController() {} + NetworkController() + { + } + virtual ~NetworkController() + { + } - /** - * Called when this is added to a Node to initialize and supply info - * - * @param signingId Identity for signing of network configurations, certs, etc. - * @param sender Sender implementation for sending replies or config pushes - */ - virtual void init(const Identity &signingId,Sender *sender) = 0; + /** + * Called when this is added to a Node to initialize and supply info + * + * @param signingId Identity for signing of network configurations, certs, etc. + * @param sender Sender implementation for sending replies or config pushes + */ + virtual void init(const Identity& signingId, Sender* sender) = 0; - /** - * Handle a network configuration request - * - * @param nwid 64-bit network ID - * @param fromAddr Originating wire address or null address if packet is not direct (or from self) - * @param requestPacketId Packet ID of request packet or 0 if not initiated by remote request - * @param identity ZeroTier identity of originating peer - * @param metaData Meta-data bundled with request (if any) - * @return Returns NETCONF_QUERY_OK if result 'nc' is valid, or an error code on error - */ - virtual void request( - uint64_t nwid, - const InetAddress &fromAddr, - uint64_t requestPacketId, - const Identity &identity, - const Dictionary &metaData) = 0; + /** + * Handle a network configuration request + * + * @param nwid 64-bit network ID + * @param fromAddr Originating wire address or null address if packet is not direct (or from self) + * @param requestPacketId Packet ID of request packet or 0 if not initiated by remote request + * @param identity ZeroTier identity of originating peer + * @param metaData Meta-data bundled with request (if any) + * @return Returns NETCONF_QUERY_OK if result 'nc' is valid, or an error code on error + */ + virtual void request(uint64_t nwid, const InetAddress& fromAddr, uint64_t requestPacketId, const Identity& identity, const Dictionary& metaData) = 0; }; -} // namespace ZeroTier +} // namespace ZeroTier #endif diff --git a/node/Node.cpp b/node/Node.cpp index 1f377c54..47e6e5ed 100644 --- a/node/Node.cpp +++ b/node/Node.cpp @@ -11,31 +11,32 @@ */ /****/ -#include -#include -#include -#include -#include +#include "Node.hpp" #include "../version.h" - -#include "Constants.hpp" -#include "SharedPtr.hpp" -#include "Node.hpp" -#include "RuntimeEnvironment.hpp" -#include "NetworkController.hpp" -#include "Switch.hpp" -#include "Multicaster.hpp" -#include "Topology.hpp" -#include "Buffer.hpp" -#include "Packet.hpp" #include "Address.hpp" +#include "Buffer.hpp" +#include "Constants.hpp" +#include "ECC.hpp" #include "Identity.hpp" -#include "SelfAwareness.hpp" -#include "Network.hpp" -#include "Trace.hpp" #include "Metrics.hpp" +#include "Multicaster.hpp" +#include "Network.hpp" +#include "NetworkController.hpp" +#include "Packet.hpp" #include "PacketMultiplexer.hpp" +#include "RuntimeEnvironment.hpp" +#include "SelfAwareness.hpp" +#include "SharedPtr.hpp" +#include "Switch.hpp" +#include "Topology.hpp" +#include "Trace.hpp" + +#include +#include +#include +#include +#include // FIXME: remove this suppression and actually fix warnings #ifdef __GNUC__ @@ -48,864 +49,873 @@ namespace ZeroTier { /* Public Node interface (C++, exposed via CAPI bindings) */ /****************************************************************************/ -Node::Node(void *uptr,void *tptr,const struct ZT_Node_Callbacks *callbacks,int64_t now) : - _RR(this), - RR(&_RR), - _uPtr(uptr), - _networks(8), - _now(now), - _lastPingCheck(0), - _lastGratuitousPingCheck(0), - _lastHousekeepingRun(0), - _lastMemoizedTraceSettings(0), - _lowBandwidthMode(false) +Node::Node(void* uptr, void* tptr, const struct ZT_Node_Callbacks* callbacks, int64_t now) + : _RR(this) + , RR(&_RR) + , _uPtr(uptr) + , _networks(8) + , _now(now) + , _lastPingCheck(0) + , _lastGratuitousPingCheck(0) + , _lastHousekeepingRun(0) + , _lastMemoizedTraceSettings(0) + , _lowBandwidthMode(false) { - if (callbacks->version != 0) { - throw ZT_EXCEPTION_INVALID_ARGUMENT; - } - memcpy(&_cb,callbacks,sizeof(ZT_Node_Callbacks)); + if (callbacks->version != 0) { + throw ZT_EXCEPTION_INVALID_ARGUMENT; + } + memcpy(&_cb, callbacks, sizeof(ZT_Node_Callbacks)); - // Initialize non-cryptographic PRNG from a good random source - Utils::getSecureRandom((void *)_prngState,sizeof(_prngState)); + // Initialize non-cryptographic PRNG from a good random source + Utils::getSecureRandom((void*)_prngState, sizeof(_prngState)); - _online = false; + _online = false; - memset(_expectingRepliesToBucketPtr,0,sizeof(_expectingRepliesToBucketPtr)); - memset(_expectingRepliesTo,0,sizeof(_expectingRepliesTo)); - memset(_lastIdentityVerification,0,sizeof(_lastIdentityVerification)); - memset((void *)(&_stats),0,sizeof(_stats)); + memset(_expectingRepliesToBucketPtr, 0, sizeof(_expectingRepliesToBucketPtr)); + memset(_expectingRepliesTo, 0, sizeof(_expectingRepliesTo)); + memset(_lastIdentityVerification, 0, sizeof(_lastIdentityVerification)); + memset((void*)(&_stats), 0, sizeof(_stats)); - uint64_t idtmp[2]; - idtmp[0] = 0; - idtmp[1] = 0; - char tmp[2048]; - int n = stateObjectGet(tptr,ZT_STATE_OBJECT_IDENTITY_SECRET,idtmp,tmp,sizeof(tmp) - 1); - if (n > 0) { - tmp[n] = (char)0; - if (RR->identity.fromString(tmp)) { - RR->identity.toString(false,RR->publicIdentityStr); - RR->identity.toString(true,RR->secretIdentityStr); - } else { - throw ZT_EXCEPTION_INVALID_IDENTITY; - } + uint64_t idtmp[2]; + idtmp[0] = 0; + idtmp[1] = 0; + char tmp[2048]; + int n = stateObjectGet(tptr, ZT_STATE_OBJECT_IDENTITY_SECRET, idtmp, tmp, sizeof(tmp) - 1); + if (n > 0) { + tmp[n] = (char)0; + if (RR->identity.fromString(tmp)) { + RR->identity.toString(false, RR->publicIdentityStr); + RR->identity.toString(true, RR->secretIdentityStr); + } + else { + throw ZT_EXCEPTION_INVALID_IDENTITY; + } - if (!RR->identity.locallyValidate()) { - throw ZT_EXCEPTION_INVALID_IDENTITY; - } - } + if (! RR->identity.locallyValidate()) { + throw ZT_EXCEPTION_INVALID_IDENTITY; + } + } - if (n <= 0) { - RR->identity.generate(); - RR->identity.toString(false,RR->publicIdentityStr); - RR->identity.toString(true,RR->secretIdentityStr); - idtmp[0] = RR->identity.address().toInt(); - idtmp[1] = 0; - stateObjectPut(tptr,ZT_STATE_OBJECT_IDENTITY_SECRET,idtmp,RR->secretIdentityStr,(unsigned int)strlen(RR->secretIdentityStr)); - stateObjectPut(tptr,ZT_STATE_OBJECT_IDENTITY_PUBLIC,idtmp,RR->publicIdentityStr,(unsigned int)strlen(RR->publicIdentityStr)); - } else { - idtmp[0] = RR->identity.address().toInt(); - idtmp[1] = 0; - n = stateObjectGet(tptr,ZT_STATE_OBJECT_IDENTITY_PUBLIC,idtmp,tmp,sizeof(tmp) - 1); - if ((n > 0)&&(n < (int)sizeof(RR->publicIdentityStr))&&(n < (int)sizeof(tmp))) { - if (memcmp(tmp,RR->publicIdentityStr,n)) { - stateObjectPut(tptr,ZT_STATE_OBJECT_IDENTITY_PUBLIC,idtmp,RR->publicIdentityStr,(unsigned int)strlen(RR->publicIdentityStr)); - } - } - } + if (n <= 0) { + RR->identity.generate(); + RR->identity.toString(false, RR->publicIdentityStr); + RR->identity.toString(true, RR->secretIdentityStr); + idtmp[0] = RR->identity.address().toInt(); + idtmp[1] = 0; + stateObjectPut(tptr, ZT_STATE_OBJECT_IDENTITY_SECRET, idtmp, RR->secretIdentityStr, (unsigned int)strlen(RR->secretIdentityStr)); + stateObjectPut(tptr, ZT_STATE_OBJECT_IDENTITY_PUBLIC, idtmp, RR->publicIdentityStr, (unsigned int)strlen(RR->publicIdentityStr)); + } + else { + idtmp[0] = RR->identity.address().toInt(); + idtmp[1] = 0; + n = stateObjectGet(tptr, ZT_STATE_OBJECT_IDENTITY_PUBLIC, idtmp, tmp, sizeof(tmp) - 1); + if ((n > 0) && (n < (int)sizeof(RR->publicIdentityStr)) && (n < (int)sizeof(tmp))) { + if (memcmp(tmp, RR->publicIdentityStr, n)) { + stateObjectPut(tptr, ZT_STATE_OBJECT_IDENTITY_PUBLIC, idtmp, RR->publicIdentityStr, (unsigned int)strlen(RR->publicIdentityStr)); + } + } + } - char *m = (char *)0; - try { - const unsigned long ts = sizeof(Trace) + (((sizeof(Trace) & 0xf) != 0) ? (16 - (sizeof(Trace) & 0xf)) : 0); - const unsigned long sws = sizeof(Switch) + (((sizeof(Switch) & 0xf) != 0) ? (16 - (sizeof(Switch) & 0xf)) : 0); - const unsigned long mcs = sizeof(Multicaster) + (((sizeof(Multicaster) & 0xf) != 0) ? (16 - (sizeof(Multicaster) & 0xf)) : 0); - const unsigned long topologys = sizeof(Topology) + (((sizeof(Topology) & 0xf) != 0) ? (16 - (sizeof(Topology) & 0xf)) : 0); - const unsigned long sas = sizeof(SelfAwareness) + (((sizeof(SelfAwareness) & 0xf) != 0) ? (16 - (sizeof(SelfAwareness) & 0xf)) : 0); - const unsigned long bcs = sizeof(Bond) + (((sizeof(Bond) & 0xf) != 0) ? (16 - (sizeof(Bond) & 0xf)) : 0); - const unsigned long pms = sizeof(PacketMultiplexer) + (((sizeof(PacketMultiplexer) & 0xf) != 0) ? (16 - (sizeof(PacketMultiplexer) & 0xf)) : 0); + char* m = (char*)0; + try { + const unsigned long ts = sizeof(Trace) + (((sizeof(Trace) & 0xf) != 0) ? (16 - (sizeof(Trace) & 0xf)) : 0); + const unsigned long sws = sizeof(Switch) + (((sizeof(Switch) & 0xf) != 0) ? (16 - (sizeof(Switch) & 0xf)) : 0); + const unsigned long mcs = sizeof(Multicaster) + (((sizeof(Multicaster) & 0xf) != 0) ? (16 - (sizeof(Multicaster) & 0xf)) : 0); + const unsigned long topologys = sizeof(Topology) + (((sizeof(Topology) & 0xf) != 0) ? (16 - (sizeof(Topology) & 0xf)) : 0); + const unsigned long sas = sizeof(SelfAwareness) + (((sizeof(SelfAwareness) & 0xf) != 0) ? (16 - (sizeof(SelfAwareness) & 0xf)) : 0); + const unsigned long bcs = sizeof(Bond) + (((sizeof(Bond) & 0xf) != 0) ? (16 - (sizeof(Bond) & 0xf)) : 0); + const unsigned long pms = sizeof(PacketMultiplexer) + (((sizeof(PacketMultiplexer) & 0xf) != 0) ? (16 - (sizeof(PacketMultiplexer) & 0xf)) : 0); - m = reinterpret_cast(::malloc(16 + ts + sws + mcs + topologys + sas + bcs + pms)); - if (!m) { - throw std::bad_alloc(); - } - RR->rtmem = m; - while (((uintptr_t)m & 0xf) != 0) { - ++m; - } + m = reinterpret_cast(::malloc(16 + ts + sws + mcs + topologys + sas + bcs + pms)); + if (! m) { + throw std::bad_alloc(); + } + RR->rtmem = m; + while (((uintptr_t)m & 0xf) != 0) { + ++m; + } - RR->t = new (m) Trace(RR); - m += ts; - RR->sw = new (m) Switch(RR); - m += sws; - RR->mc = new (m) Multicaster(RR); - m += mcs; - RR->topology = new (m) Topology(RR,tptr); - m += topologys; - RR->sa = new (m) SelfAwareness(RR); - m += sas; - RR->bc = new (m) Bond(RR); - m += bcs; - RR->pm = new (m) PacketMultiplexer(RR); - } catch ( ... ) { - if (RR->sa) { - RR->sa->~SelfAwareness(); - } - if (RR->topology) { - RR->topology->~Topology(); - } - if (RR->mc) { - RR->mc->~Multicaster(); - } - if (RR->sw) { - RR->sw->~Switch(); - } - if (RR->t) { - RR->t->~Trace(); - } - if (RR->bc) { - RR->bc->~Bond(); - } - if (RR->pm) { - RR->pm->~PacketMultiplexer(); - } - ::free(m); - throw; - } + RR->t = new (m) Trace(RR); + m += ts; + RR->sw = new (m) Switch(RR); + m += sws; + RR->mc = new (m) Multicaster(RR); + m += mcs; + RR->topology = new (m) Topology(RR, tptr); + m += topologys; + RR->sa = new (m) SelfAwareness(RR); + m += sas; + RR->bc = new (m) Bond(RR); + m += bcs; + RR->pm = new (m) PacketMultiplexer(RR); + } + catch (...) { + if (RR->sa) { + RR->sa->~SelfAwareness(); + } + if (RR->topology) { + RR->topology->~Topology(); + } + if (RR->mc) { + RR->mc->~Multicaster(); + } + if (RR->sw) { + RR->sw->~Switch(); + } + if (RR->t) { + RR->t->~Trace(); + } + if (RR->bc) { + RR->bc->~Bond(); + } + if (RR->pm) { + RR->pm->~PacketMultiplexer(); + } + ::free(m); + throw; + } - postEvent(tptr,ZT_EVENT_UP); + postEvent(tptr, ZT_EVENT_UP); } Node::~Node() { - { - Mutex::Lock _l(_networks_m); - _networks.clear(); // destroy all networks before shutdown - } - if (RR->sa) { - RR->sa->~SelfAwareness(); - } - if (RR->topology) { - RR->topology->~Topology(); - } - if (RR->mc) { - RR->mc->~Multicaster(); - } - if (RR->sw) { - RR->sw->~Switch(); - } - if (RR->t) { - RR->t->~Trace(); - } - if (RR->bc) { - RR->bc->~Bond(); - } - if (RR->pm) { - RR->pm->~PacketMultiplexer(); - } - ::free(RR->rtmem); + { + Mutex::Lock _l(_networks_m); + _networks.clear(); // destroy all networks before shutdown + } + if (RR->sa) { + RR->sa->~SelfAwareness(); + } + if (RR->topology) { + RR->topology->~Topology(); + } + if (RR->mc) { + RR->mc->~Multicaster(); + } + if (RR->sw) { + RR->sw->~Switch(); + } + if (RR->t) { + RR->t->~Trace(); + } + if (RR->bc) { + RR->bc->~Bond(); + } + if (RR->pm) { + RR->pm->~PacketMultiplexer(); + } + ::free(RR->rtmem); } -ZT_ResultCode Node::processWirePacket( - void *tptr, - int64_t now, - int64_t localSocket, - const struct sockaddr_storage *remoteAddress, - const void *packetData, - unsigned int packetLength, - volatile int64_t *nextBackgroundTaskDeadline) +ZT_ResultCode Node::processWirePacket(void* tptr, int64_t now, int64_t localSocket, const struct sockaddr_storage* remoteAddress, const void* packetData, unsigned int packetLength, volatile int64_t* nextBackgroundTaskDeadline) { - _now = now; - RR->sw->onRemotePacket(tptr,localSocket,*(reinterpret_cast(remoteAddress)),packetData,packetLength); - return ZT_RESULT_OK; + _now = now; + RR->sw->onRemotePacket(tptr, localSocket, *(reinterpret_cast(remoteAddress)), packetData, packetLength); + return ZT_RESULT_OK; } ZT_ResultCode Node::processVirtualNetworkFrame( - void *tptr, - int64_t now, - uint64_t nwid, - uint64_t sourceMac, - uint64_t destMac, - unsigned int etherType, - unsigned int vlanId, - const void *frameData, - unsigned int frameLength, - volatile int64_t *nextBackgroundTaskDeadline) + void* tptr, + int64_t now, + uint64_t nwid, + uint64_t sourceMac, + uint64_t destMac, + unsigned int etherType, + unsigned int vlanId, + const void* frameData, + unsigned int frameLength, + volatile int64_t* nextBackgroundTaskDeadline) { - _now = now; - SharedPtr nw(this->network(nwid)); - if (nw) { - RR->sw->onLocalEthernet(tptr,nw,MAC(sourceMac),MAC(destMac),etherType,vlanId,frameData,frameLength); - return ZT_RESULT_OK; - } else { - return ZT_RESULT_ERROR_NETWORK_NOT_FOUND; - } + _now = now; + SharedPtr nw(this->network(nwid)); + if (nw) { + RR->sw->onLocalEthernet(tptr, nw, MAC(sourceMac), MAC(destMac), etherType, vlanId, frameData, frameLength); + return ZT_RESULT_OK; + } + else { + return ZT_RESULT_ERROR_NETWORK_NOT_FOUND; + } } void Node::initMultithreading(unsigned int concurrency, bool cpuPinningEnabled) { - RR->pm->setUpPostDecodeReceiveThreads(concurrency, cpuPinningEnabled); + RR->pm->setUpPostDecodeReceiveThreads(concurrency, cpuPinningEnabled); } // Closure used to ping upstream and active/online peers -class _PingPeersThatNeedPing -{ -public: - _PingPeersThatNeedPing(const RuntimeEnvironment *renv,void *tPtr,Hashtable< Address,std::vector > &alwaysContact,int64_t now) : - RR(renv), - _tPtr(tPtr), - _alwaysContact(alwaysContact), - _now(now), - _bestCurrentUpstream(RR->topology->getUpstreamPeer()) - { - } +class _PingPeersThatNeedPing { + public: + _PingPeersThatNeedPing(const RuntimeEnvironment* renv, void* tPtr, Hashtable >& alwaysContact, int64_t now) + : RR(renv) + , _tPtr(tPtr) + , _alwaysContact(alwaysContact) + , _now(now) + , _bestCurrentUpstream(RR->topology->getUpstreamPeer()) + { + } - inline void operator()(Topology &t,const SharedPtr &p) - { - const std::vector *const alwaysContactEndpoints = _alwaysContact.get(p->address()); - if (alwaysContactEndpoints) { + inline void operator()(Topology& t, const SharedPtr& p) + { + const std::vector* const alwaysContactEndpoints = _alwaysContact.get(p->address()); + if (alwaysContactEndpoints) { + ZT_PeerRole role = RR->topology->role(p->address()); - ZT_PeerRole role = RR->topology->role(p->address()); + // Contact upstream peers as infrequently as possible + int roleBasedTimerScale = (role == ZT_PEER_ROLE_LEAF) ? 2 : 16; - // Contact upstream peers as infrequently as possible - int roleBasedTimerScale = (role == ZT_PEER_ROLE_LEAF) ? 2 : 16; + // Unless we don't any have paths to the roots, then we shouldn't wait a long time to contact them + bool hasPaths = p->paths(RR->node->now()).size() > 0; + roleBasedTimerScale = (role != ZT_PEER_ROLE_LEAF && ! hasPaths) ? 0 : roleBasedTimerScale; - // Unless we don't any have paths to the roots, then we shouldn't wait a long time to contact them - bool hasPaths = p->paths(RR->node->now()).size() > 0; - roleBasedTimerScale = (role != ZT_PEER_ROLE_LEAF && !hasPaths) ? 0 : roleBasedTimerScale; + if ((RR->node->now() - p->lastSentFullHello()) <= (ZT_PATH_HEARTBEAT_PERIOD * roleBasedTimerScale)) { + return; + } - if ((RR->node->now() - p->lastSentFullHello()) <= (ZT_PATH_HEARTBEAT_PERIOD * roleBasedTimerScale)) { - return; - } + const unsigned int sent = p->doPingAndKeepalive(_tPtr, _now); + bool contacted = (sent != 0); - const unsigned int sent = p->doPingAndKeepalive(_tPtr,_now); - bool contacted = (sent != 0); + if ((sent & 0x1) == 0) { // bit 0x1 == IPv4 sent + for (unsigned long k = 0, ptr = (unsigned long)RR->node->prng(); k < (unsigned long)alwaysContactEndpoints->size(); ++k) { + const InetAddress& addr = (*alwaysContactEndpoints)[ptr++ % alwaysContactEndpoints->size()]; + if (addr.ss_family == AF_INET) { + p->sendHELLO(_tPtr, -1, addr, _now); + contacted = true; + break; + } + } + } - if ((sent & 0x1) == 0) { // bit 0x1 == IPv4 sent - for(unsigned long k=0,ptr=(unsigned long)RR->node->prng();k<(unsigned long)alwaysContactEndpoints->size();++k) { - const InetAddress &addr = (*alwaysContactEndpoints)[ptr++ % alwaysContactEndpoints->size()]; - if (addr.ss_family == AF_INET) { - p->sendHELLO(_tPtr,-1,addr,_now); - contacted = true; - break; - } - } - } + if ((sent & 0x2) == 0) { // bit 0x2 == IPv6 sent + for (unsigned long k = 0, ptr = (unsigned long)RR->node->prng(); k < (unsigned long)alwaysContactEndpoints->size(); ++k) { + const InetAddress& addr = (*alwaysContactEndpoints)[ptr++ % alwaysContactEndpoints->size()]; + if (addr.ss_family == AF_INET6) { + p->sendHELLO(_tPtr, -1, addr, _now); + contacted = true; + break; + } + } + } - if ((sent & 0x2) == 0) { // bit 0x2 == IPv6 sent - for(unsigned long k=0,ptr=(unsigned long)RR->node->prng();k<(unsigned long)alwaysContactEndpoints->size();++k) { - const InetAddress &addr = (*alwaysContactEndpoints)[ptr++ % alwaysContactEndpoints->size()]; - if (addr.ss_family == AF_INET6) { - p->sendHELLO(_tPtr,-1,addr,_now); - contacted = true; - break; - } - } - } + if ((! contacted) && (_bestCurrentUpstream)) { + const SharedPtr up(_bestCurrentUpstream->getAppropriatePath(_now, true)); + if (up) { + p->sendHELLO(_tPtr, up->localSocket(), up->address(), _now); + } + } - if ((!contacted)&&(_bestCurrentUpstream)) { - const SharedPtr up(_bestCurrentUpstream->getAppropriatePath(_now,true)); - if (up) { - p->sendHELLO(_tPtr,up->localSocket(),up->address(),_now); - } - } + _alwaysContact.erase(p->address()); // after this we'll WHOIS all upstreams that remain + } + else if (p->isActive(_now)) { + p->doPingAndKeepalive(_tPtr, _now); + } + } - _alwaysContact.erase(p->address()); // after this we'll WHOIS all upstreams that remain - } else if (p->isActive(_now)) { - p->doPingAndKeepalive(_tPtr,_now); - } - } - -private: - const RuntimeEnvironment *RR; - void *_tPtr; - Hashtable< Address,std::vector > &_alwaysContact; - const int64_t _now; - const SharedPtr _bestCurrentUpstream; + private: + const RuntimeEnvironment* RR; + void* _tPtr; + Hashtable >& _alwaysContact; + const int64_t _now; + const SharedPtr _bestCurrentUpstream; }; -ZT_ResultCode Node::processBackgroundTasks(void *tptr,int64_t now,volatile int64_t *nextBackgroundTaskDeadline) +ZT_ResultCode Node::processBackgroundTasks(void* tptr, int64_t now, volatile int64_t* nextBackgroundTaskDeadline) { - _now = now; - Mutex::Lock bl(_backgroundTasksLock); + _now = now; + Mutex::Lock bl(_backgroundTasksLock); - // Process background bond tasks - unsigned long bondCheckInterval = ZT_PING_CHECK_INTERVAL; - if (RR->bc->inUse()) { - bondCheckInterval = std::max(RR->bc->minReqMonitorInterval(), ZT_CORE_TIMER_TASK_GRANULARITY); - if ((now - _lastGratuitousPingCheck) >= ZT_CORE_TIMER_TASK_GRANULARITY) { - _lastGratuitousPingCheck = now; - RR->bc->processBackgroundTasks(tptr, now); - } - } + // Process background bond tasks + unsigned long bondCheckInterval = ZT_PING_CHECK_INTERVAL; + if (RR->bc->inUse()) { + bondCheckInterval = std::max(RR->bc->minReqMonitorInterval(), ZT_CORE_TIMER_TASK_GRANULARITY); + if ((now - _lastGratuitousPingCheck) >= ZT_CORE_TIMER_TASK_GRANULARITY) { + _lastGratuitousPingCheck = now; + RR->bc->processBackgroundTasks(tptr, now); + } + } - unsigned long timeUntilNextPingCheck = _lowBandwidthMode ? (ZT_PING_CHECK_INTERVAL * 5) : ZT_PING_CHECK_INTERVAL; - const int64_t timeSinceLastPingCheck = now - _lastPingCheck; - if (timeSinceLastPingCheck >= timeUntilNextPingCheck) { - try { - _lastPingCheck = now; + unsigned long timeUntilNextPingCheck = _lowBandwidthMode ? (ZT_PING_CHECK_INTERVAL * 5) : ZT_PING_CHECK_INTERVAL; + const int64_t timeSinceLastPingCheck = now - _lastPingCheck; + if (timeSinceLastPingCheck >= timeUntilNextPingCheck) { + try { + _lastPingCheck = now; - // Get designated VL1 upstreams - Hashtable< Address,std::vector > alwaysContact; - RR->topology->getUpstreamsToContact(alwaysContact); + // Get designated VL1 upstreams + Hashtable > alwaysContact; + RR->topology->getUpstreamsToContact(alwaysContact); - // Uncomment to dump stats - /* - for(unsigned int i=0;i<32;i++) { - if (_stats.inVerbCounts[i] > 0) - printf("%.2x\t%12lld %lld\n",i,(unsigned long long)_stats.inVerbCounts[i],(unsigned long long)_stats.inVerbBytes[i]); - } - printf("\n"); - */ + // Uncomment to dump stats + /* + for(unsigned int i=0;i<32;i++) { + if (_stats.inVerbCounts[i] > 0) + printf("%.2x\t%12lld %lld\n",i,(unsigned long long)_stats.inVerbCounts[i],(unsigned long long)_stats.inVerbBytes[i]); + } + printf("\n"); + */ - // Check last receive time on designated upstreams to see if we seem to be online - int64_t lastReceivedFromUpstream = 0; - { - Hashtable< Address,std::vector >::Iterator i(alwaysContact); - Address *upstreamAddress = (Address *)0; - std::vector *upstreamStableEndpoints = (std::vector *)0; - while (i.next(upstreamAddress,upstreamStableEndpoints)) { - SharedPtr p(RR->topology->getPeerNoCache(*upstreamAddress)); - if (p) { - lastReceivedFromUpstream = std::max(p->lastReceive(),lastReceivedFromUpstream); - } - } - } + // Check last receive time on designated upstreams to see if we seem to be online + int64_t lastReceivedFromUpstream = 0; + { + Hashtable >::Iterator i(alwaysContact); + Address* upstreamAddress = (Address*)0; + std::vector* upstreamStableEndpoints = (std::vector*)0; + while (i.next(upstreamAddress, upstreamStableEndpoints)) { + SharedPtr p(RR->topology->getPeerNoCache(*upstreamAddress)); + if (p) { + lastReceivedFromUpstream = std::max(p->lastReceive(), lastReceivedFromUpstream); + } + } + } - // Clean up any old local controller auth memorizations. - { - _localControllerAuthorizations_m.lock(); - Hashtable< _LocalControllerAuth,int64_t >::Iterator i(_localControllerAuthorizations); - _LocalControllerAuth *k = (_LocalControllerAuth *)0; - int64_t *v = (int64_t *)0; - while (i.next(k,v)) { - if ((*v - now) > (ZT_NETWORK_AUTOCONF_DELAY * 3)) { - _localControllerAuthorizations.erase(*k); - } - } - _localControllerAuthorizations_m.unlock(); - } + // Clean up any old local controller auth memorizations. + { + _localControllerAuthorizations_m.lock(); + Hashtable<_LocalControllerAuth, int64_t>::Iterator i(_localControllerAuthorizations); + _LocalControllerAuth* k = (_LocalControllerAuth*)0; + int64_t* v = (int64_t*)0; + while (i.next(k, v)) { + if ((*v - now) > (ZT_NETWORK_AUTOCONF_DELAY * 3)) { + _localControllerAuthorizations.erase(*k); + } + } + _localControllerAuthorizations_m.unlock(); + } - // Get peers we should stay connected to according to network configs - // Also get networks and whether they need config so we only have to do one pass over networks - int timerScale = _lowBandwidthMode ? 64 : 1; - std::vector< std::pair< SharedPtr,bool > > networkConfigNeeded; - { - Mutex::Lock l(_networks_m); - Hashtable< uint64_t,SharedPtr >::Iterator i(_networks); - uint64_t *nwid = (uint64_t *)0; - SharedPtr *network = (SharedPtr *)0; - while (i.next(nwid,network)) { - (*network)->config().alwaysContactAddresses(alwaysContact); - networkConfigNeeded.push_back( std::pair< SharedPtr,bool >(*network,(((now - (*network)->lastConfigUpdate()) >= ZT_NETWORK_AUTOCONF_DELAY * timerScale)||(!(*network)->hasConfig()))) ); - } - } + // Get peers we should stay connected to according to network configs + // Also get networks and whether they need config so we only have to do one pass over networks + int timerScale = _lowBandwidthMode ? 64 : 1; + std::vector, bool> > networkConfigNeeded; + { + Mutex::Lock l(_networks_m); + Hashtable >::Iterator i(_networks); + uint64_t* nwid = (uint64_t*)0; + SharedPtr* network = (SharedPtr*)0; + while (i.next(nwid, network)) { + (*network)->config().alwaysContactAddresses(alwaysContact); + networkConfigNeeded.push_back(std::pair, bool>(*network, (((now - (*network)->lastConfigUpdate()) >= ZT_NETWORK_AUTOCONF_DELAY * timerScale) || (! (*network)->hasConfig())))); + } + } - // Ping active peers, upstreams, and others that we should always contact - _PingPeersThatNeedPing pfunc(RR,tptr,alwaysContact,now); - RR->topology->eachPeer<_PingPeersThatNeedPing &>(pfunc); + // Ping active peers, upstreams, and others that we should always contact + _PingPeersThatNeedPing pfunc(RR, tptr, alwaysContact, now); + RR->topology->eachPeer<_PingPeersThatNeedPing&>(pfunc); - // Run WHOIS to create Peer for alwaysContact addresses that could not be contacted - { - Hashtable< Address,std::vector >::Iterator i(alwaysContact); - Address *upstreamAddress = (Address *)0; - std::vector *upstreamStableEndpoints = (std::vector *)0; - while (i.next(upstreamAddress,upstreamStableEndpoints)) { - RR->sw->requestWhois(tptr,now,*upstreamAddress); - } - } + // Run WHOIS to create Peer for alwaysContact addresses that could not be contacted + { + Hashtable >::Iterator i(alwaysContact); + Address* upstreamAddress = (Address*)0; + std::vector* upstreamStableEndpoints = (std::vector*)0; + while (i.next(upstreamAddress, upstreamStableEndpoints)) { + RR->sw->requestWhois(tptr, now, *upstreamAddress); + } + } - // Refresh network config or broadcast network updates to members as needed - for(std::vector< std::pair< SharedPtr,bool > >::const_iterator n(networkConfigNeeded.begin());n!=networkConfigNeeded.end();++n) { - if (n->second) { - n->first->requestConfiguration(tptr); - } - if (! _lowBandwidthMode) { - n->first->sendUpdatesToMembers(tptr); - } - } + // Refresh network config or broadcast network updates to members as needed + for (std::vector, bool> >::const_iterator n(networkConfigNeeded.begin()); n != networkConfigNeeded.end(); ++n) { + if (n->second) { + n->first->requestConfiguration(tptr); + } + if (! _lowBandwidthMode) { + n->first->sendUpdatesToMembers(tptr); + } + } - // Update online status, post status change as event - const bool oldOnline = _online; - _online = (((now - lastReceivedFromUpstream) < ZT_PEER_ACTIVITY_TIMEOUT)||(RR->topology->amUpstream())); - if (oldOnline != _online) { - postEvent(tptr,_online ? ZT_EVENT_ONLINE : ZT_EVENT_OFFLINE); - } - } catch ( ... ) { - return ZT_RESULT_FATAL_ERROR_INTERNAL; - } - } else { - timeUntilNextPingCheck -= (unsigned long)timeSinceLastPingCheck; - } + // Update online status, post status change as event + const bool oldOnline = _online; + _online = (((now - lastReceivedFromUpstream) < ZT_PEER_ACTIVITY_TIMEOUT) || (RR->topology->amUpstream())); + if (oldOnline != _online) { + postEvent(tptr, _online ? ZT_EVENT_ONLINE : ZT_EVENT_OFFLINE); + } + } + catch (...) { + return ZT_RESULT_FATAL_ERROR_INTERNAL; + } + } + else { + timeUntilNextPingCheck -= (unsigned long)timeSinceLastPingCheck; + } - if ((now - _lastMemoizedTraceSettings) >= (ZT_HOUSEKEEPING_PERIOD / 4)) { - _lastMemoizedTraceSettings = now; - RR->t->updateMemoizedSettings(); - } + if ((now - _lastMemoizedTraceSettings) >= (ZT_HOUSEKEEPING_PERIOD / 4)) { + _lastMemoizedTraceSettings = now; + RR->t->updateMemoizedSettings(); + } - if ((now - _lastHousekeepingRun) >= ZT_HOUSEKEEPING_PERIOD) { - _lastHousekeepingRun = now; - try { - RR->topology->doPeriodicTasks(tptr,now); - RR->sa->clean(now); - RR->mc->clean(now); - } catch ( ... ) { - return ZT_RESULT_FATAL_ERROR_INTERNAL; - } - } + if ((now - _lastHousekeepingRun) >= ZT_HOUSEKEEPING_PERIOD) { + _lastHousekeepingRun = now; + try { + RR->topology->doPeriodicTasks(tptr, now); + RR->sa->clean(now); + RR->mc->clean(now); + } + catch (...) { + return ZT_RESULT_FATAL_ERROR_INTERNAL; + } + } - try { - *nextBackgroundTaskDeadline = now + (int64_t)std::max(std::min(bondCheckInterval,std::min(timeUntilNextPingCheck,RR->sw->doTimerTasks(tptr,now))),(unsigned long)ZT_CORE_TIMER_TASK_GRANULARITY); - } catch ( ... ) { - return ZT_RESULT_FATAL_ERROR_INTERNAL; - } + try { + *nextBackgroundTaskDeadline = now + (int64_t)std::max(std::min(bondCheckInterval, std::min(timeUntilNextPingCheck, RR->sw->doTimerTasks(tptr, now))), (unsigned long)ZT_CORE_TIMER_TASK_GRANULARITY); + } + catch (...) { + return ZT_RESULT_FATAL_ERROR_INTERNAL; + } - return ZT_RESULT_OK; + return ZT_RESULT_OK; } -ZT_ResultCode Node::join(uint64_t nwid,void *uptr,void *tptr) +ZT_ResultCode Node::join(uint64_t nwid, void* uptr, void* tptr) { - Mutex::Lock _l(_networks_m); - SharedPtr &nw = _networks[nwid]; - if (!nw) { - nw = SharedPtr(new Network(RR,tptr,nwid,uptr,(const NetworkConfig *)0)); - } - return ZT_RESULT_OK; + Mutex::Lock _l(_networks_m); + SharedPtr& nw = _networks[nwid]; + if (! nw) { + nw = SharedPtr(new Network(RR, tptr, nwid, uptr, (const NetworkConfig*)0)); + } + return ZT_RESULT_OK; } -ZT_ResultCode Node::leave(uint64_t nwid,void **uptr,void *tptr) +ZT_ResultCode Node::leave(uint64_t nwid, void** uptr, void* tptr) { - ZT_VirtualNetworkConfig ctmp; - void **nUserPtr = (void **)0; - { - Mutex::Lock _l(_networks_m); - SharedPtr *nw = _networks.get(nwid); - RR->sw->removeNetworkQoSControlBlock(nwid); - if (!nw) { - return ZT_RESULT_OK; - } - if (uptr) { - *uptr = (*nw)->userPtr(); - } - (*nw)->externalConfig(&ctmp); - (*nw)->destroy(); - nUserPtr = (*nw)->userPtr(); - } + ZT_VirtualNetworkConfig ctmp; + void** nUserPtr = (void**)0; + { + Mutex::Lock _l(_networks_m); + SharedPtr* nw = _networks.get(nwid); + RR->sw->removeNetworkQoSControlBlock(nwid); + if (! nw) { + return ZT_RESULT_OK; + } + if (uptr) { + *uptr = (*nw)->userPtr(); + } + (*nw)->externalConfig(&ctmp); + (*nw)->destroy(); + nUserPtr = (*nw)->userPtr(); + } - if (nUserPtr) { - RR->node->configureVirtualNetworkPort(tptr,nwid,nUserPtr,ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_DESTROY,&ctmp); - } + if (nUserPtr) { + RR->node->configureVirtualNetworkPort(tptr, nwid, nUserPtr, ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_DESTROY, &ctmp); + } - { - Mutex::Lock _l(_networks_m); - _networks.erase(nwid); - } + { + Mutex::Lock _l(_networks_m); + _networks.erase(nwid); + } - uint64_t tmp[2]; - tmp[0] = nwid; - tmp[1] = 0; - RR->node->stateObjectDelete(tptr,ZT_STATE_OBJECT_NETWORK_CONFIG,tmp); + uint64_t tmp[2]; + tmp[0] = nwid; + tmp[1] = 0; + RR->node->stateObjectDelete(tptr, ZT_STATE_OBJECT_NETWORK_CONFIG, tmp); - return ZT_RESULT_OK; + return ZT_RESULT_OK; } -ZT_ResultCode Node::multicastSubscribe(void *tptr,uint64_t nwid,uint64_t multicastGroup,unsigned long multicastAdi) +ZT_ResultCode Node::multicastSubscribe(void* tptr, uint64_t nwid, uint64_t multicastGroup, unsigned long multicastAdi) { - SharedPtr nw(this->network(nwid)); - if (nw) { - nw->multicastSubscribe(tptr,MulticastGroup(MAC(multicastGroup),(uint32_t)(multicastAdi & 0xffffffff))); - return ZT_RESULT_OK; - } else { - return ZT_RESULT_ERROR_NETWORK_NOT_FOUND; - } + SharedPtr nw(this->network(nwid)); + if (nw) { + nw->multicastSubscribe(tptr, MulticastGroup(MAC(multicastGroup), (uint32_t)(multicastAdi & 0xffffffff))); + return ZT_RESULT_OK; + } + else { + return ZT_RESULT_ERROR_NETWORK_NOT_FOUND; + } } -ZT_ResultCode Node::multicastUnsubscribe(uint64_t nwid,uint64_t multicastGroup,unsigned long multicastAdi) +ZT_ResultCode Node::multicastUnsubscribe(uint64_t nwid, uint64_t multicastGroup, unsigned long multicastAdi) { - SharedPtr nw(this->network(nwid)); - if (nw) { - nw->multicastUnsubscribe(MulticastGroup(MAC(multicastGroup),(uint32_t)(multicastAdi & 0xffffffff))); - return ZT_RESULT_OK; - } else { - return ZT_RESULT_ERROR_NETWORK_NOT_FOUND; - } + SharedPtr nw(this->network(nwid)); + if (nw) { + nw->multicastUnsubscribe(MulticastGroup(MAC(multicastGroup), (uint32_t)(multicastAdi & 0xffffffff))); + return ZT_RESULT_OK; + } + else { + return ZT_RESULT_ERROR_NETWORK_NOT_FOUND; + } } -ZT_ResultCode Node::orbit(void *tptr,uint64_t moonWorldId,uint64_t moonSeed) +ZT_ResultCode Node::orbit(void* tptr, uint64_t moonWorldId, uint64_t moonSeed) { - RR->topology->addMoon(tptr,moonWorldId,Address(moonSeed)); - return ZT_RESULT_OK; + RR->topology->addMoon(tptr, moonWorldId, Address(moonSeed)); + return ZT_RESULT_OK; } -ZT_ResultCode Node::deorbit(void *tptr,uint64_t moonWorldId) +ZT_ResultCode Node::deorbit(void* tptr, uint64_t moonWorldId) { - RR->topology->removeMoon(tptr,moonWorldId); - return ZT_RESULT_OK; + RR->topology->removeMoon(tptr, moonWorldId); + return ZT_RESULT_OK; } uint64_t Node::address() const { - return RR->identity.address().toInt(); + return RR->identity.address().toInt(); } -void Node::status(ZT_NodeStatus *status) const +void Node::status(ZT_NodeStatus* status) const { - status->address = RR->identity.address().toInt(); - status->publicIdentity = RR->publicIdentityStr; - status->secretIdentity = RR->secretIdentityStr; - status->online = _online ? 1 : 0; + status->address = RR->identity.address().toInt(); + status->publicIdentity = RR->publicIdentityStr; + status->secretIdentity = RR->secretIdentityStr; + status->online = _online ? 1 : 0; } -ZT_PeerList *Node::peers() const +ZT_PeerList* Node::peers() const { - std::vector< std::pair< Address,SharedPtr > > peers(RR->topology->allPeers()); - std::sort(peers.begin(),peers.end()); + std::vector > > peers(RR->topology->allPeers()); + std::sort(peers.begin(), peers.end()); - char *buf = (char *)::malloc(sizeof(ZT_PeerList) + (sizeof(ZT_Peer) * peers.size())); - if (!buf) { - return (ZT_PeerList *)0; - } - ZT_PeerList *pl = (ZT_PeerList *)buf; - pl->peers = (ZT_Peer *)(buf + sizeof(ZT_PeerList)); + char* buf = (char*)::malloc(sizeof(ZT_PeerList) + (sizeof(ZT_Peer) * peers.size())); + if (! buf) { + return (ZT_PeerList*)0; + } + ZT_PeerList* pl = (ZT_PeerList*)buf; + pl->peers = (ZT_Peer*)(buf + sizeof(ZT_PeerList)); - pl->peerCount = 0; - for(std::vector< std::pair< Address,SharedPtr > >::iterator pi(peers.begin());pi!=peers.end();++pi) { - ZT_Peer *p = &(pl->peers[pl->peerCount++]); - p->address = pi->second->address().toInt(); - p->isBonded = 0; - if (pi->second->remoteVersionKnown()) { - p->versionMajor = pi->second->remoteVersionMajor(); - p->versionMinor = pi->second->remoteVersionMinor(); - p->versionRev = pi->second->remoteVersionRevision(); - } else { - p->versionMajor = -1; - p->versionMinor = -1; - p->versionRev = -1; - } - p->latency = pi->second->latency(_now); - if (p->latency >= 0xffff) { - p->latency = -1; - } - p->role = RR->topology->role(pi->second->identity().address()); + pl->peerCount = 0; + for (std::vector > >::iterator pi(peers.begin()); pi != peers.end(); ++pi) { + ZT_Peer* p = &(pl->peers[pl->peerCount++]); + p->address = pi->second->address().toInt(); + p->isBonded = 0; + if (pi->second->remoteVersionKnown()) { + p->versionMajor = pi->second->remoteVersionMajor(); + p->versionMinor = pi->second->remoteVersionMinor(); + p->versionRev = pi->second->remoteVersionRevision(); + } + else { + p->versionMajor = -1; + p->versionMinor = -1; + p->versionRev = -1; + } + p->latency = pi->second->latency(_now); + if (p->latency >= 0xffff) { + p->latency = -1; + } + p->role = RR->topology->role(pi->second->identity().address()); - std::vector< SharedPtr > paths(pi->second->paths(_now)); - SharedPtr bestp(pi->second->getAppropriatePath(_now,false)); - p->pathCount = 0; - for(std::vector< SharedPtr >::iterator path(paths.begin());path!=paths.end();++path) { - if((*path)->valid()) { - memcpy(&(p->paths[p->pathCount].address),&((*path)->address()),sizeof(struct sockaddr_storage)); - p->paths[p->pathCount].localSocket = (*path)->localSocket(); - p->paths[p->pathCount].localPort = (*path)->localPort(); - p->paths[p->pathCount].lastSend = (*path)->lastOut(); - p->paths[p->pathCount].lastReceive = (*path)->lastIn(); - p->paths[p->pathCount].trustedPathId = RR->topology->getOutboundPathTrust((*path)->address()); - p->paths[p->pathCount].expired = 0; - p->paths[p->pathCount].preferred = ((*path) == bestp) ? 1 : 0; - p->paths[p->pathCount].scope = (*path)->ipScope(); - if (pi->second->bond()) { - p->paths[p->pathCount].latencyMean = (*path)->latencyMean(); - p->paths[p->pathCount].latencyVariance = (*path)->latencyVariance(); - p->paths[p->pathCount].packetLossRatio = (*path)->packetLossRatio(); - p->paths[p->pathCount].packetErrorRatio = (*path)->packetErrorRatio(); - p->paths[p->pathCount].assignedFlowCount = (*path)->assignedFlowCount(); - p->paths[p->pathCount].relativeQuality = (*path)->relativeQuality(); - p->paths[p->pathCount].linkSpeed = (*path)->givenLinkSpeed(); - p->paths[p->pathCount].bonded = (*path)->bonded(); - p->paths[p->pathCount].eligible = (*path)->eligible(); - std::string ifname = std::string((*path)->ifname()); - memset(p->paths[p->pathCount].ifname, 0x0, std::min((int)ifname.length() + 1, ZT_MAX_PHYSIFNAME)); - memcpy(p->paths[p->pathCount].ifname, ifname.c_str(), std::min((int)ifname.length(), ZT_MAX_PHYSIFNAME)); - } - ++p->pathCount; - } - } - if (pi->second->bond()) { - p->isBonded = pi->second->bond(); - p->bondingPolicy = pi->second->bondingPolicy(); - p->numAliveLinks = pi->second->getNumAliveLinks(); - p->numTotalLinks = pi->second->getNumTotalLinks(); - } - } + std::vector > paths(pi->second->paths(_now)); + SharedPtr bestp(pi->second->getAppropriatePath(_now, false)); + p->pathCount = 0; + for (std::vector >::iterator path(paths.begin()); path != paths.end(); ++path) { + if ((*path)->valid()) { + memcpy(&(p->paths[p->pathCount].address), &((*path)->address()), sizeof(struct sockaddr_storage)); + p->paths[p->pathCount].localSocket = (*path)->localSocket(); + p->paths[p->pathCount].localPort = (*path)->localPort(); + p->paths[p->pathCount].lastSend = (*path)->lastOut(); + p->paths[p->pathCount].lastReceive = (*path)->lastIn(); + p->paths[p->pathCount].trustedPathId = RR->topology->getOutboundPathTrust((*path)->address()); + p->paths[p->pathCount].expired = 0; + p->paths[p->pathCount].preferred = ((*path) == bestp) ? 1 : 0; + p->paths[p->pathCount].scope = (*path)->ipScope(); + if (pi->second->bond()) { + p->paths[p->pathCount].latencyMean = (*path)->latencyMean(); + p->paths[p->pathCount].latencyVariance = (*path)->latencyVariance(); + p->paths[p->pathCount].packetLossRatio = (*path)->packetLossRatio(); + p->paths[p->pathCount].packetErrorRatio = (*path)->packetErrorRatio(); + p->paths[p->pathCount].assignedFlowCount = (*path)->assignedFlowCount(); + p->paths[p->pathCount].relativeQuality = (*path)->relativeQuality(); + p->paths[p->pathCount].linkSpeed = (*path)->givenLinkSpeed(); + p->paths[p->pathCount].bonded = (*path)->bonded(); + p->paths[p->pathCount].eligible = (*path)->eligible(); + std::string ifname = std::string((*path)->ifname()); + memset(p->paths[p->pathCount].ifname, 0x0, std::min((int)ifname.length() + 1, ZT_MAX_PHYSIFNAME)); + memcpy(p->paths[p->pathCount].ifname, ifname.c_str(), std::min((int)ifname.length(), ZT_MAX_PHYSIFNAME)); + } + ++p->pathCount; + } + } + if (pi->second->bond()) { + p->isBonded = pi->second->bond(); + p->bondingPolicy = pi->second->bondingPolicy(); + p->numAliveLinks = pi->second->getNumAliveLinks(); + p->numTotalLinks = pi->second->getNumTotalLinks(); + } + } - return pl; + return pl; } -ZT_VirtualNetworkConfig *Node::networkConfig(uint64_t nwid) const +ZT_VirtualNetworkConfig* Node::networkConfig(uint64_t nwid) const { - Mutex::Lock _l(_networks_m); - const SharedPtr *nw = _networks.get(nwid); - if (nw) { - ZT_VirtualNetworkConfig *nc = (ZT_VirtualNetworkConfig *)::malloc(sizeof(ZT_VirtualNetworkConfig)); - (*nw)->externalConfig(nc); - return nc; - } - return (ZT_VirtualNetworkConfig *)0; + Mutex::Lock _l(_networks_m); + const SharedPtr* nw = _networks.get(nwid); + if (nw) { + ZT_VirtualNetworkConfig* nc = (ZT_VirtualNetworkConfig*)::malloc(sizeof(ZT_VirtualNetworkConfig)); + (*nw)->externalConfig(nc); + return nc; + } + return (ZT_VirtualNetworkConfig*)0; } -ZT_VirtualNetworkList *Node::networks() const +ZT_VirtualNetworkList* Node::networks() const { - Mutex::Lock _l(_networks_m); + Mutex::Lock _l(_networks_m); - char *buf = (char *)::malloc(sizeof(ZT_VirtualNetworkList) + (sizeof(ZT_VirtualNetworkConfig) * _networks.size())); - if (!buf) { - return (ZT_VirtualNetworkList *)0; - } - ZT_VirtualNetworkList *nl = (ZT_VirtualNetworkList *)buf; - nl->networks = (ZT_VirtualNetworkConfig *)(buf + sizeof(ZT_VirtualNetworkList)); + char* buf = (char*)::malloc(sizeof(ZT_VirtualNetworkList) + (sizeof(ZT_VirtualNetworkConfig) * _networks.size())); + if (! buf) { + return (ZT_VirtualNetworkList*)0; + } + ZT_VirtualNetworkList* nl = (ZT_VirtualNetworkList*)buf; + nl->networks = (ZT_VirtualNetworkConfig*)(buf + sizeof(ZT_VirtualNetworkList)); - nl->networkCount = 0; - Hashtable< uint64_t,SharedPtr >::Iterator i(*const_cast< Hashtable< uint64_t,SharedPtr > *>(&_networks)); - uint64_t *k = (uint64_t *)0; - SharedPtr *v = (SharedPtr *)0; - while (i.next(k,v)) { - (*v)->externalConfig(&(nl->networks[nl->networkCount++])); - } + nl->networkCount = 0; + Hashtable >::Iterator i(*const_cast >*>(&_networks)); + uint64_t* k = (uint64_t*)0; + SharedPtr* v = (SharedPtr*)0; + while (i.next(k, v)) { + (*v)->externalConfig(&(nl->networks[nl->networkCount++])); + } - return nl; + return nl; } -void Node::freeQueryResult(void *qr) +void Node::freeQueryResult(void* qr) { - if (qr) { - ::free(qr); - } + if (qr) { + ::free(qr); + } } -int Node::addLocalInterfaceAddress(const struct sockaddr_storage *addr) +int Node::addLocalInterfaceAddress(const struct sockaddr_storage* addr) { - if (Path::isAddressValidForPath(*(reinterpret_cast(addr)))) { - Mutex::Lock _l(_directPaths_m); - if (std::find(_directPaths.begin(),_directPaths.end(),*(reinterpret_cast(addr))) == _directPaths.end()) { - _directPaths.push_back(*(reinterpret_cast(addr))); - return 1; - } - } - return 0; + if (Path::isAddressValidForPath(*(reinterpret_cast(addr)))) { + Mutex::Lock _l(_directPaths_m); + if (std::find(_directPaths.begin(), _directPaths.end(), *(reinterpret_cast(addr))) == _directPaths.end()) { + _directPaths.push_back(*(reinterpret_cast(addr))); + return 1; + } + } + return 0; } void Node::clearLocalInterfaceAddresses() { - Mutex::Lock _l(_directPaths_m); - _directPaths.clear(); + Mutex::Lock _l(_directPaths_m); + _directPaths.clear(); } -int Node::sendUserMessage(void *tptr,uint64_t dest,uint64_t typeId,const void *data,unsigned int len) +int Node::sendUserMessage(void* tptr, uint64_t dest, uint64_t typeId, const void* data, unsigned int len) { - try { - if (RR->identity.address().toInt() != dest) { - Packet outp(Address(dest),RR->identity.address(),Packet::VERB_USER_MESSAGE); - outp.append(typeId); - outp.append(data,len); - outp.compress(); - RR->sw->send(tptr,outp,true); - return 1; - } - } catch ( ... ) {} - return 0; + try { + if (RR->identity.address().toInt() != dest) { + Packet outp(Address(dest), RR->identity.address(), Packet::VERB_USER_MESSAGE); + outp.append(typeId); + outp.append(data, len); + outp.compress(); + RR->sw->send(tptr, outp, true); + return 1; + } + } + catch (...) { + } + return 0; } -void Node::setNetconfMaster(void *networkControllerInstance) +void Node::setNetconfMaster(void* networkControllerInstance) { - RR->localNetworkController = reinterpret_cast(networkControllerInstance); - if (networkControllerInstance) { - RR->localNetworkController->init(RR->identity, this); - } + RR->localNetworkController = reinterpret_cast(networkControllerInstance); + if (networkControllerInstance) { + RR->localNetworkController->init(RR->identity, this); + } } /****************************************************************************/ /* Node methods used only within node/ */ /****************************************************************************/ -bool Node::shouldUsePathForZeroTierTraffic(void *tPtr,const Address &ztaddr,const int64_t localSocket,const InetAddress &remoteAddress) +bool Node::shouldUsePathForZeroTierTraffic(void* tPtr, const Address& ztaddr, const int64_t localSocket, const InetAddress& remoteAddress) { - if (!Path::isAddressValidForPath(remoteAddress)) { - return false; - } + if (! Path::isAddressValidForPath(remoteAddress)) { + return false; + } - if (RR->topology->isProhibitedEndpoint(ztaddr,remoteAddress)) { - return false; - } + if (RR->topology->isProhibitedEndpoint(ztaddr, remoteAddress)) { + return false; + } - { - Mutex::Lock _l(_networks_m); - Hashtable< uint64_t,SharedPtr >::Iterator i(_networks); - uint64_t *k = (uint64_t *)0; - SharedPtr *v = (SharedPtr *)0; - while (i.next(k,v)) { - if ((*v)->hasConfig()) { - for(unsigned int k=0;k<(*v)->config().staticIpCount;++k) { - if ((*v)->config().staticIps[k].containsAddress(remoteAddress)) { - return false; - } - } - } - } - } + { + Mutex::Lock _l(_networks_m); + Hashtable >::Iterator i(_networks); + uint64_t* k = (uint64_t*)0; + SharedPtr* v = (SharedPtr*)0; + while (i.next(k, v)) { + if ((*v)->hasConfig()) { + for (unsigned int k = 0; k < (*v)->config().staticIpCount; ++k) { + if ((*v)->config().staticIps[k].containsAddress(remoteAddress)) { + return false; + } + } + } + } + } - return ( (_cb.pathCheckFunction) ? (_cb.pathCheckFunction(reinterpret_cast(this),_uPtr,tPtr,ztaddr.toInt(),localSocket,reinterpret_cast(&remoteAddress)) != 0) : true); + return ((_cb.pathCheckFunction) ? (_cb.pathCheckFunction(reinterpret_cast(this), _uPtr, tPtr, ztaddr.toInt(), localSocket, reinterpret_cast(&remoteAddress)) != 0) : true); } uint64_t Node::prng() { - // https://en.wikipedia.org/wiki/Xorshift#xorshift.2B - uint64_t x = _prngState[0]; - const uint64_t y = _prngState[1]; - _prngState[0] = y; - x ^= x << 23; - const uint64_t z = x ^ y ^ (x >> 17) ^ (y >> 26); - _prngState[1] = z; - return z + y; + // https://en.wikipedia.org/wiki/Xorshift#xorshift.2B + uint64_t x = _prngState[0]; + const uint64_t y = _prngState[1]; + _prngState[0] = y; + x ^= x << 23; + const uint64_t z = x ^ y ^ (x >> 17) ^ (y >> 26); + _prngState[1] = z; + return z + y; } -ZT_ResultCode Node::setPhysicalPathConfiguration(const struct sockaddr_storage *pathNetwork, const ZT_PhysicalPathConfiguration *pathConfig) +ZT_ResultCode Node::setPhysicalPathConfiguration(const struct sockaddr_storage* pathNetwork, const ZT_PhysicalPathConfiguration* pathConfig) { - RR->topology->setPhysicalPathConfiguration(pathNetwork,pathConfig); - return ZT_RESULT_OK; + RR->topology->setPhysicalPathConfiguration(pathNetwork, pathConfig); + return ZT_RESULT_OK; } World Node::planet() const { - return RR->topology->planet(); + return RR->topology->planet(); } std::vector Node::moons() const { - return RR->topology->moons(); + return RR->topology->moons(); } -void Node::ncSendConfig(uint64_t nwid,uint64_t requestPacketId,const Address &destination,const NetworkConfig &nc,bool sendLegacyFormatConfig) +void Node::ncSendConfig(uint64_t nwid, uint64_t requestPacketId, const Address& destination, const NetworkConfig& nc, bool sendLegacyFormatConfig) { - _localControllerAuthorizations_m.lock(); - _localControllerAuthorizations[_LocalControllerAuth(nwid,destination)] = now(); - _localControllerAuthorizations_m.unlock(); + _localControllerAuthorizations_m.lock(); + _localControllerAuthorizations[_LocalControllerAuth(nwid, destination)] = now(); + _localControllerAuthorizations_m.unlock(); - if (destination == RR->identity.address()) { - SharedPtr n(network(nwid)); - if (!n) { - return; - } - n->setConfiguration((void *)0,nc,true); - } else { - Dictionary *dconf = new Dictionary(); - try { - if (nc.toDictionary(*dconf,sendLegacyFormatConfig)) { - uint64_t configUpdateId = prng(); - if (!configUpdateId) { - ++configUpdateId; - } + if (destination == RR->identity.address()) { + SharedPtr n(network(nwid)); + if (! n) { + return; + } + n->setConfiguration((void*)0, nc, true); + } + else { + Dictionary* dconf = new Dictionary(); + try { + if (nc.toDictionary(*dconf, sendLegacyFormatConfig)) { + uint64_t configUpdateId = prng(); + if (! configUpdateId) { + ++configUpdateId; + } - const unsigned int totalSize = dconf->sizeBytes(); - unsigned int chunkIndex = 0; - while (chunkIndex < totalSize) { - const unsigned int chunkLen = std::min(totalSize - chunkIndex,(unsigned int)(ZT_PROTO_MAX_PACKET_LENGTH - (ZT_PACKET_IDX_PAYLOAD + 256))); - Packet outp(destination,RR->identity.address(),(requestPacketId) ? Packet::VERB_OK : Packet::VERB_NETWORK_CONFIG); - if (requestPacketId) { - outp.append((unsigned char)Packet::VERB_NETWORK_CONFIG_REQUEST); - outp.append(requestPacketId); - } + const unsigned int totalSize = dconf->sizeBytes(); + unsigned int chunkIndex = 0; + while (chunkIndex < totalSize) { + const unsigned int chunkLen = std::min(totalSize - chunkIndex, (unsigned int)(ZT_PROTO_MAX_PACKET_LENGTH - (ZT_PACKET_IDX_PAYLOAD + 256))); + Packet outp(destination, RR->identity.address(), (requestPacketId) ? Packet::VERB_OK : Packet::VERB_NETWORK_CONFIG); + if (requestPacketId) { + outp.append((unsigned char)Packet::VERB_NETWORK_CONFIG_REQUEST); + outp.append(requestPacketId); + } - const unsigned int sigStart = outp.size(); - outp.append(nwid); - outp.append((uint16_t)chunkLen); - outp.append((const void *)(dconf->data() + chunkIndex),chunkLen); + const unsigned int sigStart = outp.size(); + outp.append(nwid); + outp.append((uint16_t)chunkLen); + outp.append((const void*)(dconf->data() + chunkIndex), chunkLen); - outp.append((uint8_t)0); // no flags - outp.append((uint64_t)configUpdateId); - outp.append((uint32_t)totalSize); - outp.append((uint32_t)chunkIndex); + outp.append((uint8_t)0); // no flags + outp.append((uint64_t)configUpdateId); + outp.append((uint32_t)totalSize); + outp.append((uint32_t)chunkIndex); - C25519::Signature sig(RR->identity.sign(reinterpret_cast(outp.data()) + sigStart,outp.size() - sigStart)); - outp.append((uint8_t)1); - outp.append((uint16_t)ZT_C25519_SIGNATURE_LEN); - outp.append(sig.data,ZT_C25519_SIGNATURE_LEN); + ECC::Signature sig(RR->identity.sign(reinterpret_cast(outp.data()) + sigStart, outp.size() - sigStart)); + outp.append((uint8_t)1); + outp.append((uint16_t)ZT_ECC_SIGNATURE_LEN); + outp.append(sig.data, ZT_ECC_SIGNATURE_LEN); - outp.compress(); - RR->sw->send((void *)0,outp,true); - chunkIndex += chunkLen; - } - } - delete dconf; - } catch ( ... ) { - delete dconf; - throw; - } - } + outp.compress(); + RR->sw->send((void*)0, outp, true); + chunkIndex += chunkLen; + } + } + delete dconf; + } + catch (...) { + delete dconf; + throw; + } + } } -void Node::ncSendRevocation(const Address &destination,const Revocation &rev) +void Node::ncSendRevocation(const Address& destination, const Revocation& rev) { - if (destination == RR->identity.address()) { - SharedPtr n(network(rev.networkId())); - if (!n) { - return; - } - n->addCredential((void *)0,RR->identity.address(),rev); - } else { - Packet outp(destination,RR->identity.address(),Packet::VERB_NETWORK_CREDENTIALS); - outp.append((uint8_t)0x00); - outp.append((uint16_t)0); - outp.append((uint16_t)0); - outp.append((uint16_t)1); - rev.serialize(outp); - outp.append((uint16_t)0); - RR->sw->send((void *)0,outp,true); - } + if (destination == RR->identity.address()) { + SharedPtr n(network(rev.networkId())); + if (! n) { + return; + } + n->addCredential((void*)0, RR->identity.address(), rev); + } + else { + Packet outp(destination, RR->identity.address(), Packet::VERB_NETWORK_CREDENTIALS); + outp.append((uint8_t)0x00); + outp.append((uint16_t)0); + outp.append((uint16_t)0); + outp.append((uint16_t)1); + rev.serialize(outp); + outp.append((uint16_t)0); + RR->sw->send((void*)0, outp, true); + } } -void Node::ncSendError(uint64_t nwid,uint64_t requestPacketId,const Address &destination,NetworkController::ErrorCode errorCode, const void *errorData, unsigned int errorDataSize) +void Node::ncSendError(uint64_t nwid, uint64_t requestPacketId, const Address& destination, NetworkController::ErrorCode errorCode, const void* errorData, unsigned int errorDataSize) { - if (destination == RR->identity.address()) { - SharedPtr n(network(nwid)); - if (!n) { - return; - } - switch(errorCode) { - case NetworkController::NC_ERROR_OBJECT_NOT_FOUND: - case NetworkController::NC_ERROR_INTERNAL_SERVER_ERROR: - n->setNotFound(nullptr); - break; - case NetworkController::NC_ERROR_ACCESS_DENIED: - n->setAccessDenied(nullptr); - break; - case NetworkController::NC_ERROR_AUTHENTICATION_REQUIRED: { - //fprintf(stderr, "\n\nGot auth required\n\n"); - break; - } + if (destination == RR->identity.address()) { + SharedPtr n(network(nwid)); + if (! n) { + return; + } + switch (errorCode) { + case NetworkController::NC_ERROR_OBJECT_NOT_FOUND: + case NetworkController::NC_ERROR_INTERNAL_SERVER_ERROR: + n->setNotFound(nullptr); + break; + case NetworkController::NC_ERROR_ACCESS_DENIED: + n->setAccessDenied(nullptr); + break; + case NetworkController::NC_ERROR_AUTHENTICATION_REQUIRED: { + // fprintf(stderr, "\n\nGot auth required\n\n"); + break; + } - default: - break; - } - } else if (requestPacketId) { - Packet outp(destination,RR->identity.address(),Packet::VERB_ERROR); - outp.append((unsigned char)Packet::VERB_NETWORK_CONFIG_REQUEST); - outp.append(requestPacketId); - switch(errorCode) { - //case NetworkController::NC_ERROR_OBJECT_NOT_FOUND: - //case NetworkController::NC_ERROR_INTERNAL_SERVER_ERROR: - default: - outp.append((unsigned char)Packet::ERROR_OBJ_NOT_FOUND); - Metrics::pkt_error_obj_not_found_out++; - break; - case NetworkController::NC_ERROR_ACCESS_DENIED: - outp.append((unsigned char)Packet::ERROR_NETWORK_ACCESS_DENIED_); - Metrics::pkt_error_network_access_denied_out++; - break; - case NetworkController::NC_ERROR_AUTHENTICATION_REQUIRED: - outp.append((unsigned char)Packet::ERROR_NETWORK_AUTHENTICATION_REQUIRED); - Metrics::pkt_error_authentication_required_out++; - break; - } + default: + break; + } + } + else if (requestPacketId) { + Packet outp(destination, RR->identity.address(), Packet::VERB_ERROR); + outp.append((unsigned char)Packet::VERB_NETWORK_CONFIG_REQUEST); + outp.append(requestPacketId); + switch (errorCode) { + // case NetworkController::NC_ERROR_OBJECT_NOT_FOUND: + // case NetworkController::NC_ERROR_INTERNAL_SERVER_ERROR: + default: + outp.append((unsigned char)Packet::ERROR_OBJ_NOT_FOUND); + Metrics::pkt_error_obj_not_found_out++; + break; + case NetworkController::NC_ERROR_ACCESS_DENIED: + outp.append((unsigned char)Packet::ERROR_NETWORK_ACCESS_DENIED_); + Metrics::pkt_error_network_access_denied_out++; + break; + case NetworkController::NC_ERROR_AUTHENTICATION_REQUIRED: + outp.append((unsigned char)Packet::ERROR_NETWORK_AUTHENTICATION_REQUIRED); + Metrics::pkt_error_authentication_required_out++; + break; + } - outp.append(nwid); + outp.append(nwid); - if ((errorData)&&(errorDataSize > 0)&&(errorDataSize <= 0xffff)) { - outp.append((uint16_t)errorDataSize); - outp.append(errorData, errorDataSize); - } + if ((errorData) && (errorDataSize > 0) && (errorDataSize <= 0xffff)) { + outp.append((uint16_t)errorDataSize); + outp.append(errorData, errorDataSize); + } - RR->sw->send((void *)0,outp,true); - } // else we can't send an ERROR() in response to nothing, so discard + RR->sw->send((void*)0, outp, true); + } // else we can't send an ERROR() in response to nothing, so discard } -} // namespace ZeroTier +} // namespace ZeroTier /****************************************************************************/ /* CAPI bindings */ @@ -913,240 +923,268 @@ void Node::ncSendError(uint64_t nwid,uint64_t requestPacketId,const Address &des extern "C" { -enum ZT_ResultCode ZT_Node_new(ZT_Node **node,void *uptr,void *tptr,const struct ZT_Node_Callbacks *callbacks,int64_t now) +enum ZT_ResultCode ZT_Node_new(ZT_Node** node, void* uptr, void* tptr, const struct ZT_Node_Callbacks* callbacks, int64_t now) { - *node = (ZT_Node *)0; - try { - *node = reinterpret_cast(new ZeroTier::Node(uptr,tptr,callbacks,now)); - return ZT_RESULT_OK; - } catch (std::bad_alloc &exc) { - return ZT_RESULT_FATAL_ERROR_OUT_OF_MEMORY; - } catch (std::runtime_error &exc) { - return ZT_RESULT_FATAL_ERROR_DATA_STORE_FAILED; - } catch ( ... ) { - return ZT_RESULT_FATAL_ERROR_INTERNAL; - } + *node = (ZT_Node*)0; + try { + *node = reinterpret_cast(new ZeroTier::Node(uptr, tptr, callbacks, now)); + return ZT_RESULT_OK; + } + catch (std::bad_alloc& exc) { + return ZT_RESULT_FATAL_ERROR_OUT_OF_MEMORY; + } + catch (std::runtime_error& exc) { + return ZT_RESULT_FATAL_ERROR_DATA_STORE_FAILED; + } + catch (...) { + return ZT_RESULT_FATAL_ERROR_INTERNAL; + } } -void ZT_Node_delete(ZT_Node *node) +void ZT_Node_delete(ZT_Node* node) { - try { - delete (reinterpret_cast(node)); - } catch ( ... ) {} + try { + delete (reinterpret_cast(node)); + } + catch (...) { + } } -enum ZT_ResultCode ZT_Node_processWirePacket( - ZT_Node *node, - void *tptr, - int64_t now, - int64_t localSocket, - const struct sockaddr_storage *remoteAddress, - const void *packetData, - unsigned int packetLength, - volatile int64_t *nextBackgroundTaskDeadline) +enum ZT_ResultCode +ZT_Node_processWirePacket(ZT_Node* node, void* tptr, int64_t now, int64_t localSocket, const struct sockaddr_storage* remoteAddress, const void* packetData, unsigned int packetLength, volatile int64_t* nextBackgroundTaskDeadline) { - try { - return reinterpret_cast(node)->processWirePacket(tptr,now,localSocket,remoteAddress,packetData,packetLength,nextBackgroundTaskDeadline); - } catch (std::bad_alloc &exc) { - return ZT_RESULT_FATAL_ERROR_OUT_OF_MEMORY; - } catch ( ... ) { - return ZT_RESULT_OK; // "OK" since invalid packets are simply dropped, but the system is still up - } + try { + return reinterpret_cast(node)->processWirePacket(tptr, now, localSocket, remoteAddress, packetData, packetLength, nextBackgroundTaskDeadline); + } + catch (std::bad_alloc& exc) { + return ZT_RESULT_FATAL_ERROR_OUT_OF_MEMORY; + } + catch (...) { + return ZT_RESULT_OK; // "OK" since invalid packets are simply dropped, but the system is still up + } } enum ZT_ResultCode ZT_Node_processVirtualNetworkFrame( - ZT_Node *node, - void *tptr, - int64_t now, - uint64_t nwid, - uint64_t sourceMac, - uint64_t destMac, - unsigned int etherType, - unsigned int vlanId, - const void *frameData, - unsigned int frameLength, - volatile int64_t *nextBackgroundTaskDeadline) + ZT_Node* node, + void* tptr, + int64_t now, + uint64_t nwid, + uint64_t sourceMac, + uint64_t destMac, + unsigned int etherType, + unsigned int vlanId, + const void* frameData, + unsigned int frameLength, + volatile int64_t* nextBackgroundTaskDeadline) { - try { - return reinterpret_cast(node)->processVirtualNetworkFrame(tptr,now,nwid,sourceMac,destMac,etherType,vlanId,frameData,frameLength,nextBackgroundTaskDeadline); - } catch (std::bad_alloc &exc) { - return ZT_RESULT_FATAL_ERROR_OUT_OF_MEMORY; - } catch ( ... ) { - return ZT_RESULT_FATAL_ERROR_INTERNAL; - } + try { + return reinterpret_cast(node)->processVirtualNetworkFrame(tptr, now, nwid, sourceMac, destMac, etherType, vlanId, frameData, frameLength, nextBackgroundTaskDeadline); + } + catch (std::bad_alloc& exc) { + return ZT_RESULT_FATAL_ERROR_OUT_OF_MEMORY; + } + catch (...) { + return ZT_RESULT_FATAL_ERROR_INTERNAL; + } } -enum ZT_ResultCode ZT_Node_processBackgroundTasks(ZT_Node *node,void *tptr,int64_t now,volatile int64_t *nextBackgroundTaskDeadline) +enum ZT_ResultCode ZT_Node_processBackgroundTasks(ZT_Node* node, void* tptr, int64_t now, volatile int64_t* nextBackgroundTaskDeadline) { - try { - return reinterpret_cast(node)->processBackgroundTasks(tptr,now,nextBackgroundTaskDeadline); - } catch (std::bad_alloc &exc) { - return ZT_RESULT_FATAL_ERROR_OUT_OF_MEMORY; - } catch ( ... ) { - return ZT_RESULT_FATAL_ERROR_INTERNAL; - } + try { + return reinterpret_cast(node)->processBackgroundTasks(tptr, now, nextBackgroundTaskDeadline); + } + catch (std::bad_alloc& exc) { + return ZT_RESULT_FATAL_ERROR_OUT_OF_MEMORY; + } + catch (...) { + return ZT_RESULT_FATAL_ERROR_INTERNAL; + } } -enum ZT_ResultCode ZT_Node_join(ZT_Node *node,uint64_t nwid,void *uptr,void *tptr) +enum ZT_ResultCode ZT_Node_join(ZT_Node* node, uint64_t nwid, void* uptr, void* tptr) { - try { - return reinterpret_cast(node)->join(nwid,uptr,tptr); - } catch (std::bad_alloc &exc) { - return ZT_RESULT_FATAL_ERROR_OUT_OF_MEMORY; - } catch ( ... ) { - return ZT_RESULT_FATAL_ERROR_INTERNAL; - } + try { + return reinterpret_cast(node)->join(nwid, uptr, tptr); + } + catch (std::bad_alloc& exc) { + return ZT_RESULT_FATAL_ERROR_OUT_OF_MEMORY; + } + catch (...) { + return ZT_RESULT_FATAL_ERROR_INTERNAL; + } } -enum ZT_ResultCode ZT_Node_leave(ZT_Node *node,uint64_t nwid,void **uptr,void *tptr) +enum ZT_ResultCode ZT_Node_leave(ZT_Node* node, uint64_t nwid, void** uptr, void* tptr) { - try { - return reinterpret_cast(node)->leave(nwid,uptr,tptr); - } catch (std::bad_alloc &exc) { - return ZT_RESULT_FATAL_ERROR_OUT_OF_MEMORY; - } catch ( ... ) { - return ZT_RESULT_FATAL_ERROR_INTERNAL; - } + try { + return reinterpret_cast(node)->leave(nwid, uptr, tptr); + } + catch (std::bad_alloc& exc) { + return ZT_RESULT_FATAL_ERROR_OUT_OF_MEMORY; + } + catch (...) { + return ZT_RESULT_FATAL_ERROR_INTERNAL; + } } -enum ZT_ResultCode ZT_Node_multicastSubscribe(ZT_Node *node,void *tptr,uint64_t nwid,uint64_t multicastGroup,unsigned long multicastAdi) +enum ZT_ResultCode ZT_Node_multicastSubscribe(ZT_Node* node, void* tptr, uint64_t nwid, uint64_t multicastGroup, unsigned long multicastAdi) { - try { - return reinterpret_cast(node)->multicastSubscribe(tptr,nwid,multicastGroup,multicastAdi); - } catch (std::bad_alloc &exc) { - return ZT_RESULT_FATAL_ERROR_OUT_OF_MEMORY; - } catch ( ... ) { - return ZT_RESULT_FATAL_ERROR_INTERNAL; - } + try { + return reinterpret_cast(node)->multicastSubscribe(tptr, nwid, multicastGroup, multicastAdi); + } + catch (std::bad_alloc& exc) { + return ZT_RESULT_FATAL_ERROR_OUT_OF_MEMORY; + } + catch (...) { + return ZT_RESULT_FATAL_ERROR_INTERNAL; + } } -enum ZT_ResultCode ZT_Node_multicastUnsubscribe(ZT_Node *node,uint64_t nwid,uint64_t multicastGroup,unsigned long multicastAdi) +enum ZT_ResultCode ZT_Node_multicastUnsubscribe(ZT_Node* node, uint64_t nwid, uint64_t multicastGroup, unsigned long multicastAdi) { - try { - return reinterpret_cast(node)->multicastUnsubscribe(nwid,multicastGroup,multicastAdi); - } catch (std::bad_alloc &exc) { - return ZT_RESULT_FATAL_ERROR_OUT_OF_MEMORY; - } catch ( ... ) { - return ZT_RESULT_FATAL_ERROR_INTERNAL; - } + try { + return reinterpret_cast(node)->multicastUnsubscribe(nwid, multicastGroup, multicastAdi); + } + catch (std::bad_alloc& exc) { + return ZT_RESULT_FATAL_ERROR_OUT_OF_MEMORY; + } + catch (...) { + return ZT_RESULT_FATAL_ERROR_INTERNAL; + } } -enum ZT_ResultCode ZT_Node_orbit(ZT_Node *node,void *tptr,uint64_t moonWorldId,uint64_t moonSeed) +enum ZT_ResultCode ZT_Node_orbit(ZT_Node* node, void* tptr, uint64_t moonWorldId, uint64_t moonSeed) { - try { - return reinterpret_cast(node)->orbit(tptr,moonWorldId,moonSeed); - } catch ( ... ) { - return ZT_RESULT_FATAL_ERROR_INTERNAL; - } + try { + return reinterpret_cast(node)->orbit(tptr, moonWorldId, moonSeed); + } + catch (...) { + return ZT_RESULT_FATAL_ERROR_INTERNAL; + } } -enum ZT_ResultCode ZT_Node_deorbit(ZT_Node *node,void *tptr,uint64_t moonWorldId) +enum ZT_ResultCode ZT_Node_deorbit(ZT_Node* node, void* tptr, uint64_t moonWorldId) { - try { - return reinterpret_cast(node)->deorbit(tptr,moonWorldId); - } catch ( ... ) { - return ZT_RESULT_FATAL_ERROR_INTERNAL; - } + try { + return reinterpret_cast(node)->deorbit(tptr, moonWorldId); + } + catch (...) { + return ZT_RESULT_FATAL_ERROR_INTERNAL; + } } -uint64_t ZT_Node_address(ZT_Node *node) +uint64_t ZT_Node_address(ZT_Node* node) { - return reinterpret_cast(node)->address(); + return reinterpret_cast(node)->address(); } -void ZT_Node_status(ZT_Node *node,ZT_NodeStatus *status) +void ZT_Node_status(ZT_Node* node, ZT_NodeStatus* status) { - try { - reinterpret_cast(node)->status(status); - } catch ( ... ) {} + try { + reinterpret_cast(node)->status(status); + } + catch (...) { + } } -ZT_PeerList *ZT_Node_peers(ZT_Node *node) +ZT_PeerList* ZT_Node_peers(ZT_Node* node) { - try { - return reinterpret_cast(node)->peers(); - } catch ( ... ) { - return (ZT_PeerList *)0; - } + try { + return reinterpret_cast(node)->peers(); + } + catch (...) { + return (ZT_PeerList*)0; + } } -ZT_VirtualNetworkConfig *ZT_Node_networkConfig(ZT_Node *node,uint64_t nwid) +ZT_VirtualNetworkConfig* ZT_Node_networkConfig(ZT_Node* node, uint64_t nwid) { - try { - return reinterpret_cast(node)->networkConfig(nwid); - } catch ( ... ) { - return (ZT_VirtualNetworkConfig *)0; - } + try { + return reinterpret_cast(node)->networkConfig(nwid); + } + catch (...) { + return (ZT_VirtualNetworkConfig*)0; + } } -ZT_VirtualNetworkList *ZT_Node_networks(ZT_Node *node) +ZT_VirtualNetworkList* ZT_Node_networks(ZT_Node* node) { - try { - return reinterpret_cast(node)->networks(); - } catch ( ... ) { - return (ZT_VirtualNetworkList *)0; - } + try { + return reinterpret_cast(node)->networks(); + } + catch (...) { + return (ZT_VirtualNetworkList*)0; + } } -void ZT_Node_freeQueryResult(ZT_Node *node,void *qr) +void ZT_Node_freeQueryResult(ZT_Node* node, void* qr) { - try { - reinterpret_cast(node)->freeQueryResult(qr); - } catch ( ... ) {} + try { + reinterpret_cast(node)->freeQueryResult(qr); + } + catch (...) { + } } -int ZT_Node_addLocalInterfaceAddress(ZT_Node *node,const struct sockaddr_storage *addr) +int ZT_Node_addLocalInterfaceAddress(ZT_Node* node, const struct sockaddr_storage* addr) { - try { - return reinterpret_cast(node)->addLocalInterfaceAddress(addr); - } catch ( ... ) { - return 0; - } + try { + return reinterpret_cast(node)->addLocalInterfaceAddress(addr); + } + catch (...) { + return 0; + } } -void ZT_Node_clearLocalInterfaceAddresses(ZT_Node *node) +void ZT_Node_clearLocalInterfaceAddresses(ZT_Node* node) { - try { - reinterpret_cast(node)->clearLocalInterfaceAddresses(); - } catch ( ... ) {} + try { + reinterpret_cast(node)->clearLocalInterfaceAddresses(); + } + catch (...) { + } } -int ZT_Node_sendUserMessage(ZT_Node *node,void *tptr,uint64_t dest,uint64_t typeId,const void *data,unsigned int len) +int ZT_Node_sendUserMessage(ZT_Node* node, void* tptr, uint64_t dest, uint64_t typeId, const void* data, unsigned int len) { - try { - return reinterpret_cast(node)->sendUserMessage(tptr,dest,typeId,data,len); - } catch ( ... ) { - return 0; - } + try { + return reinterpret_cast(node)->sendUserMessage(tptr, dest, typeId, data, len); + } + catch (...) { + return 0; + } } -void ZT_Node_setNetconfMaster(ZT_Node *node,void *networkControllerInstance) +void ZT_Node_setNetconfMaster(ZT_Node* node, void* networkControllerInstance) { - try { - reinterpret_cast(node)->setNetconfMaster(networkControllerInstance); - } catch ( ... ) {} + try { + reinterpret_cast(node)->setNetconfMaster(networkControllerInstance); + } + catch (...) { + } } -enum ZT_ResultCode ZT_Node_setPhysicalPathConfiguration(ZT_Node *node,const struct sockaddr_storage *pathNetwork,const ZT_PhysicalPathConfiguration *pathConfig) +enum ZT_ResultCode ZT_Node_setPhysicalPathConfiguration(ZT_Node* node, const struct sockaddr_storage* pathNetwork, const ZT_PhysicalPathConfiguration* pathConfig) { - try { - return reinterpret_cast(node)->setPhysicalPathConfiguration(pathNetwork,pathConfig); - } catch ( ... ) { - return ZT_RESULT_FATAL_ERROR_INTERNAL; - } + try { + return reinterpret_cast(node)->setPhysicalPathConfiguration(pathNetwork, pathConfig); + } + catch (...) { + return ZT_RESULT_FATAL_ERROR_INTERNAL; + } } -void ZT_version(int *major,int *minor,int *revision) +void ZT_version(int* major, int* minor, int* revision) { - if (major) { - *major = ZEROTIER_ONE_VERSION_MAJOR; - } - if (minor) { - *minor = ZEROTIER_ONE_VERSION_MINOR; - } - if (revision) { - *revision = ZEROTIER_ONE_VERSION_REVISION; - } + if (major) { + *major = ZEROTIER_ONE_VERSION_MAJOR; + } + if (minor) { + *minor = ZEROTIER_ONE_VERSION_MINOR; + } + if (revision) { + *revision = ZEROTIER_ONE_VERSION_REVISION; + } } -} // extern "C" +} // extern "C" diff --git a/node/Node.hpp b/node/Node.hpp index f9d05483..49d8b31a 100644 --- a/node/Node.hpp +++ b/node/Node.hpp @@ -14,29 +14,26 @@ #ifndef ZT_NODE_HPP #define ZT_NODE_HPP +#include "../include/ZeroTierOne.h" +#include "Bond.hpp" +#include "Constants.hpp" +#include "Hashtable.hpp" +#include "InetAddress.hpp" +#include "MAC.hpp" +#include "Mutex.hpp" +#include "Network.hpp" +#include "NetworkController.hpp" +#include "Path.hpp" +#include "RuntimeEnvironment.hpp" +#include "Salsa20.hpp" +#include "SelfAwareness.hpp" + +#include #include #include #include - -#include #include -#include "Constants.hpp" - -#include "../include/ZeroTierOne.h" - -#include "RuntimeEnvironment.hpp" -#include "InetAddress.hpp" -#include "Mutex.hpp" -#include "MAC.hpp" -#include "Network.hpp" -#include "Path.hpp" -#include "Salsa20.hpp" -#include "NetworkController.hpp" -#include "Hashtable.hpp" -#include "Bond.hpp" -#include "SelfAwareness.hpp" - // Bit mask for "expecting reply" hash #define ZT_EXPECTING_REPLIES_BUCKET_MASK1 255 #define ZT_EXPECTING_REPLIES_BUCKET_MASK2 31 @@ -50,292 +47,319 @@ class World; * * The pointer returned by ZT_Node_new() is an instance of this class. */ -class Node : public NetworkController::Sender -{ -public: - Node(void *uptr,void *tptr,const struct ZT_Node_Callbacks *callbacks,int64_t now); - virtual ~Node(); +class Node : public NetworkController::Sender { + public: + Node(void* uptr, void* tptr, const struct ZT_Node_Callbacks* callbacks, int64_t now); + virtual ~Node(); - // Get rid of alignment warnings on 32-bit Windows and possibly improve performance + // Get rid of alignment warnings on 32-bit Windows and possibly improve performance #ifdef __WINDOWS__ - void * operator new(size_t i) { return _mm_malloc(i,16); } - void operator delete(void* p) { _mm_free(p); } + void* operator new(size_t i) + { + return _mm_malloc(i, 16); + } + void operator delete(void* p) + { + _mm_free(p); + } #endif - // Public API Functions ---------------------------------------------------- + // Public API Functions ---------------------------------------------------- - ZT_ResultCode processWirePacket( - void *tptr, - int64_t now, - int64_t localSocket, - const struct sockaddr_storage *remoteAddress, - const void *packetData, - unsigned int packetLength, - volatile int64_t *nextBackgroundTaskDeadline); - ZT_ResultCode processVirtualNetworkFrame( - void *tptr, - int64_t now, - uint64_t nwid, - uint64_t sourceMac, - uint64_t destMac, - unsigned int etherType, - unsigned int vlanId, - const void *frameData, - unsigned int frameLength, - volatile int64_t *nextBackgroundTaskDeadline); - ZT_ResultCode processBackgroundTasks(void *tptr,int64_t now,volatile int64_t *nextBackgroundTaskDeadline); - ZT_ResultCode join(uint64_t nwid,void *uptr,void *tptr); - ZT_ResultCode leave(uint64_t nwid,void **uptr,void *tptr); - ZT_ResultCode multicastSubscribe(void *tptr,uint64_t nwid,uint64_t multicastGroup,unsigned long multicastAdi); - ZT_ResultCode multicastUnsubscribe(uint64_t nwid,uint64_t multicastGroup,unsigned long multicastAdi); - ZT_ResultCode orbit(void *tptr,uint64_t moonWorldId,uint64_t moonSeed); - ZT_ResultCode deorbit(void *tptr,uint64_t moonWorldId); - uint64_t address() const; - void status(ZT_NodeStatus *status) const; - ZT_PeerList *peers() const; - ZT_VirtualNetworkConfig *networkConfig(uint64_t nwid) const; - ZT_VirtualNetworkList *networks() const; - void freeQueryResult(void *qr); - int addLocalInterfaceAddress(const struct sockaddr_storage *addr); - void clearLocalInterfaceAddresses(); - int sendUserMessage(void *tptr,uint64_t dest,uint64_t typeId,const void *data,unsigned int len); - void setNetconfMaster(void *networkControllerInstance); + ZT_ResultCode processWirePacket(void* tptr, int64_t now, int64_t localSocket, const struct sockaddr_storage* remoteAddress, const void* packetData, unsigned int packetLength, volatile int64_t* nextBackgroundTaskDeadline); + ZT_ResultCode processVirtualNetworkFrame( + void* tptr, + int64_t now, + uint64_t nwid, + uint64_t sourceMac, + uint64_t destMac, + unsigned int etherType, + unsigned int vlanId, + const void* frameData, + unsigned int frameLength, + volatile int64_t* nextBackgroundTaskDeadline); + ZT_ResultCode processBackgroundTasks(void* tptr, int64_t now, volatile int64_t* nextBackgroundTaskDeadline); + ZT_ResultCode join(uint64_t nwid, void* uptr, void* tptr); + ZT_ResultCode leave(uint64_t nwid, void** uptr, void* tptr); + ZT_ResultCode multicastSubscribe(void* tptr, uint64_t nwid, uint64_t multicastGroup, unsigned long multicastAdi); + ZT_ResultCode multicastUnsubscribe(uint64_t nwid, uint64_t multicastGroup, unsigned long multicastAdi); + ZT_ResultCode orbit(void* tptr, uint64_t moonWorldId, uint64_t moonSeed); + ZT_ResultCode deorbit(void* tptr, uint64_t moonWorldId); + uint64_t address() const; + void status(ZT_NodeStatus* status) const; + ZT_PeerList* peers() const; + ZT_VirtualNetworkConfig* networkConfig(uint64_t nwid) const; + ZT_VirtualNetworkList* networks() const; + void freeQueryResult(void* qr); + int addLocalInterfaceAddress(const struct sockaddr_storage* addr); + void clearLocalInterfaceAddresses(); + int sendUserMessage(void* tptr, uint64_t dest, uint64_t typeId, const void* data, unsigned int len); + void setNetconfMaster(void* networkControllerInstance); - // Internal functions ------------------------------------------------------ + // Internal functions ------------------------------------------------------ - inline int64_t now() const { return _now; } + inline int64_t now() const + { + return _now; + } - inline bool putPacket(void *tPtr,const int64_t localSocket,const InetAddress &addr,const void *data,unsigned int len,unsigned int ttl = 0) - { - return (_cb.wirePacketSendFunction( - reinterpret_cast(this), - _uPtr, - tPtr, - localSocket, - reinterpret_cast(&addr), - data, - len, - ttl) == 0); - } + inline bool putPacket(void* tPtr, const int64_t localSocket, const InetAddress& addr, const void* data, unsigned int len, unsigned int ttl = 0) + { + return (_cb.wirePacketSendFunction(reinterpret_cast(this), _uPtr, tPtr, localSocket, reinterpret_cast(&addr), data, len, ttl) == 0); + } - inline void putFrame(void *tPtr,uint64_t nwid,void **nuptr,const MAC &source,const MAC &dest,unsigned int etherType,unsigned int vlanId,const void *data,unsigned int len) - { - _cb.virtualNetworkFrameFunction( - reinterpret_cast(this), - _uPtr, - tPtr, - nwid, - nuptr, - source.toInt(), - dest.toInt(), - etherType, - vlanId, - data, - len); - } + inline void putFrame(void* tPtr, uint64_t nwid, void** nuptr, const MAC& source, const MAC& dest, unsigned int etherType, unsigned int vlanId, const void* data, unsigned int len) + { + _cb.virtualNetworkFrameFunction(reinterpret_cast(this), _uPtr, tPtr, nwid, nuptr, source.toInt(), dest.toInt(), etherType, vlanId, data, len); + } - inline SharedPtr network(uint64_t nwid) const - { - Mutex::Lock _l(_networks_m); - const SharedPtr *n = _networks.get(nwid); - if (n) { - return *n; - } - return SharedPtr(); - } + inline SharedPtr network(uint64_t nwid) const + { + Mutex::Lock _l(_networks_m); + const SharedPtr* n = _networks.get(nwid); + if (n) { + return *n; + } + return SharedPtr(); + } - inline bool belongsToNetwork(uint64_t nwid) const - { - Mutex::Lock _l(_networks_m); - return _networks.contains(nwid); - } + inline bool belongsToNetwork(uint64_t nwid) const + { + Mutex::Lock _l(_networks_m); + return _networks.contains(nwid); + } - inline std::vector< SharedPtr > allNetworks() const - { - std::vector< SharedPtr > nw; - Mutex::Lock _l(_networks_m); - Hashtable< uint64_t,SharedPtr >::Iterator i(*const_cast< Hashtable< uint64_t,SharedPtr > * >(&_networks)); - uint64_t *k = (uint64_t *)0; - SharedPtr *v = (SharedPtr *)0; - while (i.next(k,v)) { - nw.push_back(*v); - } - return nw; - } + inline std::vector > allNetworks() const + { + std::vector > nw; + Mutex::Lock _l(_networks_m); + Hashtable >::Iterator i(*const_cast >*>(&_networks)); + uint64_t* k = (uint64_t*)0; + SharedPtr* v = (SharedPtr*)0; + while (i.next(k, v)) { + nw.push_back(*v); + } + return nw; + } - inline std::vector directPaths() const - { - Mutex::Lock _l(_directPaths_m); - return _directPaths; - } + inline std::vector directPaths() const + { + Mutex::Lock _l(_directPaths_m); + return _directPaths; + } - inline void postEvent(void *tPtr,ZT_Event ev,const void *md = (const void *)0) { _cb.eventCallback(reinterpret_cast(this),_uPtr,tPtr,ev,md); } + inline void postEvent(void* tPtr, ZT_Event ev, const void* md = (const void*)0) + { + _cb.eventCallback(reinterpret_cast(this), _uPtr, tPtr, ev, md); + } - inline int configureVirtualNetworkPort(void *tPtr,uint64_t nwid,void **nuptr,ZT_VirtualNetworkConfigOperation op,const ZT_VirtualNetworkConfig *nc) { return _cb.virtualNetworkConfigFunction(reinterpret_cast(this),_uPtr,tPtr,nwid,nuptr,op,nc); } + inline int configureVirtualNetworkPort(void* tPtr, uint64_t nwid, void** nuptr, ZT_VirtualNetworkConfigOperation op, const ZT_VirtualNetworkConfig* nc) + { + return _cb.virtualNetworkConfigFunction(reinterpret_cast(this), _uPtr, tPtr, nwid, nuptr, op, nc); + } - inline bool online() const { return _online; } + inline bool online() const + { + return _online; + } - inline int stateObjectGet(void *const tPtr,ZT_StateObjectType type,const uint64_t id[2],void *const data,const unsigned int maxlen) { return _cb.stateGetFunction(reinterpret_cast(this),_uPtr,tPtr,type,id,data,maxlen); } - inline void stateObjectPut(void *const tPtr,ZT_StateObjectType type,const uint64_t id[2],const void *const data,const unsigned int len) { _cb.statePutFunction(reinterpret_cast(this),_uPtr,tPtr,type,id,data,(int)len); } - inline void stateObjectDelete(void *const tPtr,ZT_StateObjectType type,const uint64_t id[2]) { _cb.statePutFunction(reinterpret_cast(this),_uPtr,tPtr,type,id,(const void *)0,-1); } + inline int stateObjectGet(void* const tPtr, ZT_StateObjectType type, const uint64_t id[2], void* const data, const unsigned int maxlen) + { + return _cb.stateGetFunction(reinterpret_cast(this), _uPtr, tPtr, type, id, data, maxlen); + } + inline void stateObjectPut(void* const tPtr, ZT_StateObjectType type, const uint64_t id[2], const void* const data, const unsigned int len) + { + _cb.statePutFunction(reinterpret_cast(this), _uPtr, tPtr, type, id, data, (int)len); + } + inline void stateObjectDelete(void* const tPtr, ZT_StateObjectType type, const uint64_t id[2]) + { + _cb.statePutFunction(reinterpret_cast(this), _uPtr, tPtr, type, id, (const void*)0, -1); + } - bool shouldUsePathForZeroTierTraffic(void *tPtr,const Address &ztaddr,const int64_t localSocket,const InetAddress &remoteAddress); - inline bool externalPathLookup(void *tPtr,const Address &ztaddr,int family,InetAddress &addr) { return ( (_cb.pathLookupFunction) ? (_cb.pathLookupFunction(reinterpret_cast(this),_uPtr,tPtr,ztaddr.toInt(),family,reinterpret_cast(&addr)) != 0) : false ); } + bool shouldUsePathForZeroTierTraffic(void* tPtr, const Address& ztaddr, const int64_t localSocket, const InetAddress& remoteAddress); + inline bool externalPathLookup(void* tPtr, const Address& ztaddr, int family, InetAddress& addr) + { + return ((_cb.pathLookupFunction) ? (_cb.pathLookupFunction(reinterpret_cast(this), _uPtr, tPtr, ztaddr.toInt(), family, reinterpret_cast(&addr)) != 0) : false); + } - uint64_t prng(); - ZT_ResultCode setPhysicalPathConfiguration(const struct sockaddr_storage *pathNetwork,const ZT_PhysicalPathConfiguration *pathConfig); + uint64_t prng(); + ZT_ResultCode setPhysicalPathConfiguration(const struct sockaddr_storage* pathNetwork, const ZT_PhysicalPathConfiguration* pathConfig); - World planet() const; - std::vector moons() const; + World planet() const; + std::vector moons() const; - inline const Identity &identity() const { return _RR.identity; } + inline const Identity& identity() const + { + return _RR.identity; + } - inline const std::vector SurfaceAddresses() const { return _RR.sa->whoami(); } + inline const std::vector SurfaceAddresses() const + { + return _RR.sa->whoami(); + } - inline Bond *bondController() const { return _RR.bc; } + inline Bond* bondController() const + { + return _RR.bc; + } - /** - * Register that we are expecting a reply to a packet ID - * - * This only uses the most significant bits of the packet ID, both to save space - * and to avoid using the higher bits that can be modified during armor() to - * mask against the packet send counter used for QoS detection. - * - * @param packetId Packet ID to expect reply to - */ - inline void expectReplyTo(const uint64_t packetId) - { - const unsigned long pid2 = (unsigned long)(packetId >> 32); - const unsigned long bucket = (unsigned long)(pid2 & ZT_EXPECTING_REPLIES_BUCKET_MASK1); - _expectingRepliesTo[bucket][_expectingRepliesToBucketPtr[bucket]++ & ZT_EXPECTING_REPLIES_BUCKET_MASK2] = (uint32_t)pid2; - } + /** + * Register that we are expecting a reply to a packet ID + * + * This only uses the most significant bits of the packet ID, both to save space + * and to avoid using the higher bits that can be modified during armor() to + * mask against the packet send counter used for QoS detection. + * + * @param packetId Packet ID to expect reply to + */ + inline void expectReplyTo(const uint64_t packetId) + { + const unsigned long pid2 = (unsigned long)(packetId >> 32); + const unsigned long bucket = (unsigned long)(pid2 & ZT_EXPECTING_REPLIES_BUCKET_MASK1); + _expectingRepliesTo[bucket][_expectingRepliesToBucketPtr[bucket]++ & ZT_EXPECTING_REPLIES_BUCKET_MASK2] = (uint32_t)pid2; + } - /** - * Check whether a given packet ID is something we are expecting a reply to - * - * This only uses the most significant bits of the packet ID, both to save space - * and to avoid using the higher bits that can be modified during armor() to - * mask against the packet send counter used for QoS detection. - * - * @param packetId Packet ID to check - * @return True if we're expecting a reply - */ - inline bool expectingReplyTo(const uint64_t packetId) const - { - const uint32_t pid2 = (uint32_t)(packetId >> 32); - const unsigned long bucket = (unsigned long)(pid2 & ZT_EXPECTING_REPLIES_BUCKET_MASK1); - for(unsigned long i=0;i<=ZT_EXPECTING_REPLIES_BUCKET_MASK2;++i) { - if (_expectingRepliesTo[bucket][i] == pid2) { - return true; - } - } - return false; - } + /** + * Check whether a given packet ID is something we are expecting a reply to + * + * This only uses the most significant bits of the packet ID, both to save space + * and to avoid using the higher bits that can be modified during armor() to + * mask against the packet send counter used for QoS detection. + * + * @param packetId Packet ID to check + * @return True if we're expecting a reply + */ + inline bool expectingReplyTo(const uint64_t packetId) const + { + const uint32_t pid2 = (uint32_t)(packetId >> 32); + const unsigned long bucket = (unsigned long)(pid2 & ZT_EXPECTING_REPLIES_BUCKET_MASK1); + for (unsigned long i = 0; i <= ZT_EXPECTING_REPLIES_BUCKET_MASK2; ++i) { + if (_expectingRepliesTo[bucket][i] == pid2) { + return true; + } + } + return false; + } - /** - * Check whether we should do potentially expensive identity verification (rate limit) - * - * @param now Current time - * @param from Source address of packet - * @return True if within rate limits - */ - inline bool rateGateIdentityVerification(const int64_t now,const InetAddress &from) - { - unsigned long iph = from.rateGateHash(); - if ((now - _lastIdentityVerification[iph]) >= ZT_IDENTITY_VALIDATION_SOURCE_RATE_LIMIT) { - _lastIdentityVerification[iph] = now; - return true; - } - return false; - } + /** + * Check whether we should do potentially expensive identity verification (rate limit) + * + * @param now Current time + * @param from Source address of packet + * @return True if within rate limits + */ + inline bool rateGateIdentityVerification(const int64_t now, const InetAddress& from) + { + unsigned long iph = from.rateGateHash(); + if ((now - _lastIdentityVerification[iph]) >= ZT_IDENTITY_VALIDATION_SOURCE_RATE_LIMIT) { + _lastIdentityVerification[iph] = now; + return true; + } + return false; + } - virtual void ncSendConfig(uint64_t nwid,uint64_t requestPacketId,const Address &destination,const NetworkConfig &nc,bool sendLegacyFormatConfig); - virtual void ncSendRevocation(const Address &destination,const Revocation &rev); - virtual void ncSendError(uint64_t nwid,uint64_t requestPacketId,const Address &destination,NetworkController::ErrorCode errorCode, const void *errorData, unsigned int errorDataSize); + virtual void ncSendConfig(uint64_t nwid, uint64_t requestPacketId, const Address& destination, const NetworkConfig& nc, bool sendLegacyFormatConfig); + virtual void ncSendRevocation(const Address& destination, const Revocation& rev); + virtual void ncSendError(uint64_t nwid, uint64_t requestPacketId, const Address& destination, NetworkController::ErrorCode errorCode, const void* errorData, unsigned int errorDataSize); - inline const Address &remoteTraceTarget() const { return _remoteTraceTarget; } - inline Trace::Level remoteTraceLevel() const { return _remoteTraceLevel; } + inline const Address& remoteTraceTarget() const + { + return _remoteTraceTarget; + } + inline Trace::Level remoteTraceLevel() const + { + return _remoteTraceLevel; + } - inline bool localControllerHasAuthorized(const int64_t now,const uint64_t nwid,const Address &addr) const - { - _localControllerAuthorizations_m.lock(); - const int64_t *const at = _localControllerAuthorizations.get(_LocalControllerAuth(nwid,addr)); - _localControllerAuthorizations_m.unlock(); - if (at) { - return ((now - *at) < (ZT_NETWORK_AUTOCONF_DELAY * 3)); - } - return false; - } + inline bool localControllerHasAuthorized(const int64_t now, const uint64_t nwid, const Address& addr) const + { + _localControllerAuthorizations_m.lock(); + const int64_t* const at = _localControllerAuthorizations.get(_LocalControllerAuth(nwid, addr)); + _localControllerAuthorizations_m.unlock(); + if (at) { + return ((now - *at) < (ZT_NETWORK_AUTOCONF_DELAY * 3)); + } + return false; + } - inline void statsLogVerb(const unsigned int v,const unsigned int bytes) - { - ++_stats.inVerbCounts[v]; - _stats.inVerbBytes[v] += (uint64_t)bytes; - } + inline void statsLogVerb(const unsigned int v, const unsigned int bytes) + { + ++_stats.inVerbCounts[v]; + _stats.inVerbBytes[v] += (uint64_t)bytes; + } - inline void setLowBandwidthMode(bool isEnabled) - { - _lowBandwidthMode = isEnabled; - } + inline void setLowBandwidthMode(bool isEnabled) + { + _lowBandwidthMode = isEnabled; + } - inline bool lowBandwidthModeEnabled() - { - return _lowBandwidthMode; - } + inline bool lowBandwidthModeEnabled() + { + return _lowBandwidthMode; + } - void initMultithreading(unsigned int concurrency, bool cpuPinningEnabled); + void initMultithreading(unsigned int concurrency, bool cpuPinningEnabled); + public: + RuntimeEnvironment _RR; + RuntimeEnvironment* RR; + void* _uPtr; // _uptr (lower case) is reserved in Visual Studio :P + ZT_Node_Callbacks _cb; -public: - RuntimeEnvironment _RR; - RuntimeEnvironment *RR; - void *_uPtr; // _uptr (lower case) is reserved in Visual Studio :P - ZT_Node_Callbacks _cb; + // For tracking packet IDs to filter out OK/ERROR replies to packets we did not send + uint8_t _expectingRepliesToBucketPtr[ZT_EXPECTING_REPLIES_BUCKET_MASK1 + 1]; + uint32_t _expectingRepliesTo[ZT_EXPECTING_REPLIES_BUCKET_MASK1 + 1][ZT_EXPECTING_REPLIES_BUCKET_MASK2 + 1]; - // For tracking packet IDs to filter out OK/ERROR replies to packets we did not send - uint8_t _expectingRepliesToBucketPtr[ZT_EXPECTING_REPLIES_BUCKET_MASK1 + 1]; - uint32_t _expectingRepliesTo[ZT_EXPECTING_REPLIES_BUCKET_MASK1 + 1][ZT_EXPECTING_REPLIES_BUCKET_MASK2 + 1]; + // Time of last identity verification indexed by InetAddress.rateGateHash() -- used in IncomingPacket::_doHELLO() via rateGateIdentityVerification() + int64_t _lastIdentityVerification[16384]; - // Time of last identity verification indexed by InetAddress.rateGateHash() -- used in IncomingPacket::_doHELLO() via rateGateIdentityVerification() - int64_t _lastIdentityVerification[16384]; + // Statistics about stuff happening + volatile ZT_NodeStatistics _stats; - // Statistics about stuff happening - volatile ZT_NodeStatistics _stats; + // Map that remembers if we have recently sent a network config to someone + // querying us as a controller. + struct _LocalControllerAuth { + uint64_t nwid, address; + _LocalControllerAuth(const uint64_t nwid_, const Address& address_) : nwid(nwid_), address(address_.toInt()) + { + } + inline unsigned long hashCode() const + { + return (unsigned long)(nwid ^ address); + } + inline bool operator==(const _LocalControllerAuth& a) const + { + return ((a.nwid == nwid) && (a.address == address)); + } + inline bool operator!=(const _LocalControllerAuth& a) const + { + return ((a.nwid != nwid) || (a.address != address)); + } + }; + Hashtable<_LocalControllerAuth, int64_t> _localControllerAuthorizations; + Mutex _localControllerAuthorizations_m; - // Map that remembers if we have recently sent a network config to someone - // querying us as a controller. - struct _LocalControllerAuth - { - uint64_t nwid,address; - _LocalControllerAuth(const uint64_t nwid_,const Address &address_) : nwid(nwid_),address(address_.toInt()) {} - inline unsigned long hashCode() const { return (unsigned long)(nwid ^ address); } - inline bool operator==(const _LocalControllerAuth &a) const { return ((a.nwid == nwid)&&(a.address == address)); } - inline bool operator!=(const _LocalControllerAuth &a) const { return ((a.nwid != nwid)||(a.address != address)); } - }; - Hashtable< _LocalControllerAuth,int64_t > _localControllerAuthorizations; - Mutex _localControllerAuthorizations_m; + Hashtable > _networks; + Mutex _networks_m; - Hashtable< uint64_t,SharedPtr > _networks; - Mutex _networks_m; + std::vector _directPaths; + Mutex _directPaths_m; - std::vector _directPaths; - Mutex _directPaths_m; + Mutex _backgroundTasksLock; - Mutex _backgroundTasksLock; + Address _remoteTraceTarget; + enum Trace::Level _remoteTraceLevel; - Address _remoteTraceTarget; - enum Trace::Level _remoteTraceLevel; - - volatile int64_t _now; - int64_t _lastPingCheck; - int64_t _lastGratuitousPingCheck; - int64_t _lastHousekeepingRun; - int64_t _lastMemoizedTraceSettings; - volatile int64_t _prngState[2]; - bool _online; - bool _lowBandwidthMode; + volatile int64_t _now; + int64_t _lastPingCheck; + int64_t _lastGratuitousPingCheck; + int64_t _lastHousekeepingRun; + int64_t _lastMemoizedTraceSettings; + volatile int64_t _prngState[2]; + bool _online; + bool _lowBandwidthMode; }; -} // namespace ZeroTier +} // namespace ZeroTier #endif diff --git a/node/OutboundMulticast.cpp b/node/OutboundMulticast.cpp index 754c4853..62cf6e02 100644 --- a/node/OutboundMulticast.cpp +++ b/node/OutboundMulticast.cpp @@ -11,82 +11,84 @@ */ /****/ -#include "Constants.hpp" -#include "RuntimeEnvironment.hpp" #include "OutboundMulticast.hpp" -#include "Switch.hpp" + +#include "Constants.hpp" #include "Network.hpp" #include "Node.hpp" #include "Peer.hpp" +#include "RuntimeEnvironment.hpp" +#include "Switch.hpp" #include "Topology.hpp" namespace ZeroTier { void OutboundMulticast::init( - const RuntimeEnvironment *RR, - uint64_t timestamp, - uint64_t nwid, - bool disableCompression, - unsigned int limit, - unsigned int gatherLimit, - const MAC &src, - const MulticastGroup &dest, - unsigned int etherType, - const void *payload, - unsigned int len) + const RuntimeEnvironment* RR, + uint64_t timestamp, + uint64_t nwid, + bool disableCompression, + unsigned int limit, + unsigned int gatherLimit, + const MAC& src, + const MulticastGroup& dest, + unsigned int etherType, + const void* payload, + unsigned int len) { - uint8_t flags = 0; + uint8_t flags = 0; - _timestamp = timestamp; - _nwid = nwid; - if (src) { - _macSrc = src; - flags |= 0x04; - } else { - _macSrc.fromAddress(RR->identity.address(),nwid); - } - _macDest = dest.mac(); - _limit = limit; - _frameLen = (len < ZT_MAX_MTU) ? len : ZT_MAX_MTU; - _etherType = etherType; + _timestamp = timestamp; + _nwid = nwid; + if (src) { + _macSrc = src; + flags |= 0x04; + } + else { + _macSrc.fromAddress(RR->identity.address(), nwid); + } + _macDest = dest.mac(); + _limit = limit; + _frameLen = (len < ZT_MAX_MTU) ? len : ZT_MAX_MTU; + _etherType = etherType; - if (gatherLimit) { - flags |= 0x02; - } + if (gatherLimit) { + flags |= 0x02; + } - _packet.setSource(RR->identity.address()); - _packet.setVerb(Packet::VERB_MULTICAST_FRAME); - _packet.append((uint64_t)nwid); - _packet.append(flags); - if (gatherLimit) { - _packet.append((uint32_t)gatherLimit); - } - if (src) { - src.appendTo(_packet); - } - dest.mac().appendTo(_packet); - _packet.append((uint32_t)dest.adi()); - _packet.append((uint16_t)etherType); - _packet.append(payload,_frameLen); - if (!disableCompression) { - _packet.compress(); - } + _packet.setSource(RR->identity.address()); + _packet.setVerb(Packet::VERB_MULTICAST_FRAME); + _packet.append((uint64_t)nwid); + _packet.append(flags); + if (gatherLimit) { + _packet.append((uint32_t)gatherLimit); + } + if (src) { + src.appendTo(_packet); + } + dest.mac().appendTo(_packet); + _packet.append((uint32_t)dest.adi()); + _packet.append((uint16_t)etherType); + _packet.append(payload, _frameLen); + if (! disableCompression) { + _packet.compress(); + } - memcpy(_frameData,payload,_frameLen); + memcpy(_frameData, payload, _frameLen); } -void OutboundMulticast::sendOnly(const RuntimeEnvironment *RR,void *tPtr,const Address &toAddr) +void OutboundMulticast::sendOnly(const RuntimeEnvironment* RR, void* tPtr, const Address& toAddr) { - const SharedPtr nw(RR->node->network(_nwid)); - uint8_t QoSBucket = 255; // Dummy value - if ((nw)&&(nw->filterOutgoingPacket(tPtr,true,RR->identity.address(),toAddr,_macSrc,_macDest,_frameData,_frameLen,_etherType,0,QoSBucket))) { - nw->pushCredentialsIfNeeded(tPtr,toAddr,RR->node->now()); - _packet.newInitializationVector(); - _packet.setDestination(toAddr); - RR->node->expectReplyTo(_packet.packetId()); - _tmp = _packet; - RR->sw->send(tPtr,_tmp,true); - } + const SharedPtr nw(RR->node->network(_nwid)); + uint8_t QoSBucket = 255; // Dummy value + if ((nw) && (nw->filterOutgoingPacket(tPtr, true, RR->identity.address(), toAddr, _macSrc, _macDest, _frameData, _frameLen, _etherType, 0, QoSBucket))) { + nw->pushCredentialsIfNeeded(tPtr, toAddr, RR->node->now()); + _packet.newInitializationVector(); + _packet.setDestination(toAddr); + RR->node->expectReplyTo(_packet.packetId()); + _tmp = _packet; + RR->sw->send(tPtr, _tmp, true); + } } -} // namespace ZeroTier +} // namespace ZeroTier diff --git a/node/OutboundMulticast.hpp b/node/OutboundMulticast.hpp index 38c8043e..7f04446a 100644 --- a/node/OutboundMulticast.hpp +++ b/node/OutboundMulticast.hpp @@ -14,17 +14,16 @@ #ifndef ZT_OUTBOUNDMULTICAST_HPP #define ZT_OUTBOUNDMULTICAST_HPP -#include - -#include -#include - +#include "Address.hpp" #include "Constants.hpp" #include "MAC.hpp" #include "MulticastGroup.hpp" -#include "Address.hpp" #include "Packet.hpp" +#include +#include +#include + namespace ZeroTier { class CertificateOfMembership; @@ -35,124 +34,135 @@ class RuntimeEnvironment; * * This object isn't guarded by a mutex; caller must synchronize access. */ -class OutboundMulticast -{ -public: - /** - * Create an uninitialized outbound multicast - * - * It must be initialized with init(). - */ - OutboundMulticast() {} +class OutboundMulticast { + public: + /** + * Create an uninitialized outbound multicast + * + * It must be initialized with init(). + */ + OutboundMulticast() + { + } - /** - * Initialize outbound multicast - * - * @param RR Runtime environment - * @param timestamp Creation time - * @param nwid Network ID - * @param disableCompression Disable compression of frame payload - * @param limit Multicast limit for desired number of packets to send - * @param gatherLimit Number to lazily/implicitly gather with this frame or 0 for none - * @param src Source MAC address of frame or NULL to imply compute from sender ZT address - * @param dest Destination multicast group (MAC + ADI) - * @param etherType 16-bit Ethernet type ID - * @param payload Data - * @param len Length of data - * @throws std::out_of_range Data too large to fit in a MULTICAST_FRAME - */ - void init( - const RuntimeEnvironment *RR, - uint64_t timestamp, - uint64_t nwid, - bool disableCompression, - unsigned int limit, - unsigned int gatherLimit, - const MAC &src, - const MulticastGroup &dest, - unsigned int etherType, - const void *payload, - unsigned int len); + /** + * Initialize outbound multicast + * + * @param RR Runtime environment + * @param timestamp Creation time + * @param nwid Network ID + * @param disableCompression Disable compression of frame payload + * @param limit Multicast limit for desired number of packets to send + * @param gatherLimit Number to lazily/implicitly gather with this frame or 0 for none + * @param src Source MAC address of frame or NULL to imply compute from sender ZT address + * @param dest Destination multicast group (MAC + ADI) + * @param etherType 16-bit Ethernet type ID + * @param payload Data + * @param len Length of data + * @throws std::out_of_range Data too large to fit in a MULTICAST_FRAME + */ + void init( + const RuntimeEnvironment* RR, + uint64_t timestamp, + uint64_t nwid, + bool disableCompression, + unsigned int limit, + unsigned int gatherLimit, + const MAC& src, + const MulticastGroup& dest, + unsigned int etherType, + const void* payload, + unsigned int len); - /** - * @return Multicast creation time - */ - inline uint64_t timestamp() const { return _timestamp; } + /** + * @return Multicast creation time + */ + inline uint64_t timestamp() const + { + return _timestamp; + } - /** - * @param now Current time - * @return True if this multicast is expired (has exceeded transmit timeout) - */ - inline bool expired(int64_t now) const { return ((now - _timestamp) >= ZT_MULTICAST_TRANSMIT_TIMEOUT); } + /** + * @param now Current time + * @return True if this multicast is expired (has exceeded transmit timeout) + */ + inline bool expired(int64_t now) const + { + return ((now - _timestamp) >= ZT_MULTICAST_TRANSMIT_TIMEOUT); + } - /** - * @return True if this outbound multicast has been sent to enough peers - */ - inline bool atLimit() const { return (_alreadySentTo.size() >= _limit); } + /** + * @return True if this outbound multicast has been sent to enough peers + */ + inline bool atLimit() const + { + return (_alreadySentTo.size() >= _limit); + } - /** - * Just send without checking log - * - * @param RR Runtime environment - * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call - * @param toAddr Destination address - */ - void sendOnly(const RuntimeEnvironment *RR,void *tPtr,const Address &toAddr); + /** + * Just send without checking log + * + * @param RR Runtime environment + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call + * @param toAddr Destination address + */ + void sendOnly(const RuntimeEnvironment* RR, void* tPtr, const Address& toAddr); - /** - * Just send and log but do not check sent log - * - * @param RR Runtime environment - * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call - * @param toAddr Destination address - */ - inline void sendAndLog(const RuntimeEnvironment *RR,void *tPtr,const Address &toAddr) - { - _alreadySentTo.push_back(toAddr); - sendOnly(RR,tPtr,toAddr); - } + /** + * Just send and log but do not check sent log + * + * @param RR Runtime environment + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call + * @param toAddr Destination address + */ + inline void sendAndLog(const RuntimeEnvironment* RR, void* tPtr, const Address& toAddr) + { + _alreadySentTo.push_back(toAddr); + sendOnly(RR, tPtr, toAddr); + } - /** - * Log an address as having been used so we will not send there in the future - * - * @param toAddr Address to log as sent - */ - inline void logAsSent(const Address &toAddr) - { - _alreadySentTo.push_back(toAddr); - } + /** + * Log an address as having been used so we will not send there in the future + * + * @param toAddr Address to log as sent + */ + inline void logAsSent(const Address& toAddr) + { + _alreadySentTo.push_back(toAddr); + } - /** - * Try to send this to a given peer if it hasn't been sent to them already - * - * @param RR Runtime environment - * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call - * @param toAddr Destination address - * @return True if address is new and packet was sent to switch, false if duplicate - */ - inline bool sendIfNew(const RuntimeEnvironment *RR,void *tPtr,const Address &toAddr) - { - if (std::find(_alreadySentTo.begin(),_alreadySentTo.end(),toAddr) == _alreadySentTo.end()) { - sendAndLog(RR,tPtr,toAddr); - return true; - } else { - return false; - } - } + /** + * Try to send this to a given peer if it hasn't been sent to them already + * + * @param RR Runtime environment + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call + * @param toAddr Destination address + * @return True if address is new and packet was sent to switch, false if duplicate + */ + inline bool sendIfNew(const RuntimeEnvironment* RR, void* tPtr, const Address& toAddr) + { + if (std::find(_alreadySentTo.begin(), _alreadySentTo.end(), toAddr) == _alreadySentTo.end()) { + sendAndLog(RR, tPtr, toAddr); + return true; + } + else { + return false; + } + } -private: - uint64_t _timestamp; - uint64_t _nwid; - MAC _macSrc; - MAC _macDest; - unsigned int _limit; - unsigned int _frameLen; - unsigned int _etherType; - Packet _packet,_tmp; - std::vector
_alreadySentTo; - uint8_t _frameData[ZT_MAX_MTU]; + private: + uint64_t _timestamp; + uint64_t _nwid; + MAC _macSrc; + MAC _macDest; + unsigned int _limit; + unsigned int _frameLen; + unsigned int _etherType; + Packet _packet, _tmp; + std::vector
_alreadySentTo; + uint8_t _frameData[ZT_MAX_MTU]; }; -} // namespace ZeroTier +} // namespace ZeroTier #endif diff --git a/node/Packet.cpp b/node/Packet.cpp index f0430c29..35b29ea1 100644 --- a/node/Packet.cpp +++ b/node/Packet.cpp @@ -11,14 +11,16 @@ */ /****/ -#include -#include -#include -#include -#include - #include "Packet.hpp" +#include "ECC.hpp" + +#include +#include +#include +#include +#include + #if defined(ZT_USE_X64_ASM_SALSA2012) && defined(ZT_ARCH_X64) #include "../ext/x64-salsa2012-asm/salsa2012.h" #endif @@ -29,8 +31,8 @@ #ifdef _MSC_VER #define FORCE_INLINE static __forceinline #include -#pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */ -#pragma warning(disable : 4293) /* disable: C4293: too large shift (32-bits) */ +#pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */ +#pragma warning(disable : 4293) /* disable: C4293: too large shift (32-bits) */ #else #define FORCE_INLINE static inline #endif @@ -43,27 +45,30 @@ namespace ZeroTier { // x64 SSE crypto #if defined(ZT_USE_X64_ASM_SALSA2012) && defined(ZT_ARCH_X64) -#define ZT_HAS_FAST_CRYPTO() (true) -#define ZT_FAST_SINGLE_PASS_SALSA2012(b,l,n,k) zt_salsa2012_amd64_xmm6(reinterpret_cast(b),(l),reinterpret_cast(n),reinterpret_cast(k)) +#define ZT_HAS_FAST_CRYPTO() (true) +#define ZT_FAST_SINGLE_PASS_SALSA2012(b, l, n, k) zt_salsa2012_amd64_xmm6(reinterpret_cast(b), (l), reinterpret_cast(n), reinterpret_cast(k)) #endif // ARM (32-bit) NEON crypto (must be detected) #ifdef ZT_USE_ARM32_NEON_ASM_SALSA2012 -class _FastCryptoChecker -{ -public: - _FastCryptoChecker() : canHas(zt_arm_has_neon()) {} - bool canHas; +class _FastCryptoChecker { + public: + _FastCryptoChecker() : canHas(zt_arm_has_neon()) + { + } + bool canHas; }; static const _FastCryptoChecker _ZT_FAST_CRYPTO_CHECK; -#define ZT_HAS_FAST_CRYPTO() (_ZT_FAST_CRYPTO_CHECK.canHas) -#define ZT_FAST_SINGLE_PASS_SALSA2012(b,l,n,k) zt_salsa2012_armneon3_xor(reinterpret_cast(b),(const unsigned char *)0,(l),reinterpret_cast(n),reinterpret_cast(k)) +#define ZT_HAS_FAST_CRYPTO() (_ZT_FAST_CRYPTO_CHECK.canHas) +#define ZT_FAST_SINGLE_PASS_SALSA2012(b, l, n, k) zt_salsa2012_armneon3_xor(reinterpret_cast(b), (const unsigned char*)0, (l), reinterpret_cast(n), reinterpret_cast(k)) #endif // No fast crypto available #ifndef ZT_HAS_FAST_CRYPTO #define ZT_HAS_FAST_CRYPTO() (false) -#define ZT_FAST_SINGLE_PASS_SALSA2012(b,l,n,k) {} +#define ZT_FAST_SINGLE_PASS_SALSA2012(b, l, n, k) \ + { \ + } #endif /************************************************************************** */ @@ -95,9 +100,9 @@ namespace { modification, are permitted provided that the following conditions are met: - * Redistributions of source code must retain the above copyright + * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above + * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. @@ -115,8 +120,8 @@ namespace { OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. You can contact the author at : - - LZ4 homepage : http://www.lz4.org - - LZ4 source repository : https://github.com/lz4/lz4 + - LZ4 homepage : http://www.lz4.org + - LZ4 source repository : https://github.com/lz4/lz4 */ /** @@ -128,9 +133,9 @@ namespace { The LZ4 compression library provides in-memory compression and decompression functions. Compression can be done in: - - a single step (described as Simple Functions) - - a single step, reusing a context (described in Advanced Functions) - - unbounded multiple steps (described as Streaming compression) + - a single step (described as Simple Functions) + - a single step, reusing a context (described in Advanced Functions) + - unbounded multiple steps (described as Streaming compression) lz4.h provides block compression functions. It gives full buffer control to user. Decompressing an lz4-compressed block also requires metadata (such as compressed size). @@ -142,55 +147,55 @@ namespace { A library is provided to take care of it, see lz4frame.h. */ -#define LZ4_VERSION_MAJOR 1 /* for breaking interface changes */ -#define LZ4_VERSION_MINOR 7 /* for new (non-breaking) interface capabilities */ -#define LZ4_VERSION_RELEASE 5 /* for tweaks, bug-fixes, or development */ -#define LZ4_VERSION_NUMBER (LZ4_VERSION_MAJOR *100*100 + LZ4_VERSION_MINOR *100 + LZ4_VERSION_RELEASE) -#define LZ4_LIB_VERSION LZ4_VERSION_MAJOR.LZ4_VERSION_MINOR.LZ4_VERSION_RELEASE -#define LZ4_QUOTE(str) #str +#define LZ4_VERSION_MAJOR 1 /* for breaking interface changes */ +#define LZ4_VERSION_MINOR 7 /* for new (non-breaking) interface capabilities */ +#define LZ4_VERSION_RELEASE 5 /* for tweaks, bug-fixes, or development */ +#define LZ4_VERSION_NUMBER (LZ4_VERSION_MAJOR * 100 * 100 + LZ4_VERSION_MINOR * 100 + LZ4_VERSION_RELEASE) +#define LZ4_LIB_VERSION LZ4_VERSION_MAJOR.LZ4_VERSION_MINOR.LZ4_VERSION_RELEASE +#define LZ4_QUOTE(str) #str #define LZ4_EXPAND_AND_QUOTE(str) LZ4_QUOTE(str) -#define LZ4_VERSION_STRING LZ4_EXPAND_AND_QUOTE(LZ4_LIB_VERSION) -#define LZ4_MEMORY_USAGE 14 -#define LZ4_MAX_INPUT_SIZE 0x7E000000 /* 2 113 929 216 bytes */ -#define LZ4_COMPRESSBOUND(isize) ((unsigned)(isize) > (unsigned)LZ4_MAX_INPUT_SIZE ? 0 : (isize) + ((isize)/255) + 16) +#define LZ4_VERSION_STRING LZ4_EXPAND_AND_QUOTE(LZ4_LIB_VERSION) +#define LZ4_MEMORY_USAGE 14 +#define LZ4_MAX_INPUT_SIZE 0x7E000000 /* 2 113 929 216 bytes */ +#define LZ4_COMPRESSBOUND(isize) ((unsigned)(isize) > (unsigned)LZ4_MAX_INPUT_SIZE ? 0 : (isize) + ((isize) / 255) + 16) -typedef union LZ4_stream_u LZ4_stream_t; /* incomplete type (defined later) */ +typedef union LZ4_stream_u LZ4_stream_t; /* incomplete type (defined later) */ -static inline void LZ4_resetStream (LZ4_stream_t* streamPtr); +static inline void LZ4_resetStream(LZ4_stream_t* streamPtr); -#define LZ4_HASHLOG (LZ4_MEMORY_USAGE-2) +#define LZ4_HASHLOG (LZ4_MEMORY_USAGE - 2) #define LZ4_HASHTABLESIZE (1 << LZ4_MEMORY_USAGE) -#define LZ4_HASH_SIZE_U32 (1 << LZ4_HASHLOG) /* required as macro for static allocation */ +#define LZ4_HASH_SIZE_U32 (1 << LZ4_HASHLOG) /* required as macro for static allocation */ typedef struct { - uint32_t hashTable[LZ4_HASH_SIZE_U32]; - uint32_t currentOffset; - uint32_t initCheck; - const uint8_t* dictionary; - uint8_t* bufferStart; /* obsolete, used for slideInputBuffer */ - uint32_t dictSize; + uint32_t hashTable[LZ4_HASH_SIZE_U32]; + uint32_t currentOffset; + uint32_t initCheck; + const uint8_t* dictionary; + uint8_t* bufferStart; /* obsolete, used for slideInputBuffer */ + uint32_t dictSize; } LZ4_stream_t_internal; typedef struct { - const uint8_t* externalDict; - size_t extDictSize; - const uint8_t* prefixEnd; - size_t prefixSize; + const uint8_t* externalDict; + size_t extDictSize; + const uint8_t* prefixEnd; + size_t prefixSize; } LZ4_streamDecode_t_internal; -#define LZ4_STREAMSIZE_U64 ((1 << (LZ4_MEMORY_USAGE-3)) + 4) -#define LZ4_STREAMSIZE (LZ4_STREAMSIZE_U64 * sizeof(unsigned long long)) +#define LZ4_STREAMSIZE_U64 ((1 << (LZ4_MEMORY_USAGE - 3)) + 4) +#define LZ4_STREAMSIZE (LZ4_STREAMSIZE_U64 * sizeof(unsigned long long)) union LZ4_stream_u { - unsigned long long table[LZ4_STREAMSIZE_U64]; - LZ4_stream_t_internal internal_donotuse; -} ; /* previously typedef'd to LZ4_stream_t */ + unsigned long long table[LZ4_STREAMSIZE_U64]; + LZ4_stream_t_internal internal_donotuse; +}; /* previously typedef'd to LZ4_stream_t */ -#define LZ4_STREAMDECODESIZE_U64 4 -#define LZ4_STREAMDECODESIZE (LZ4_STREAMDECODESIZE_U64 * sizeof(unsigned long long)) +#define LZ4_STREAMDECODESIZE_U64 4 +#define LZ4_STREAMDECODESIZE (LZ4_STREAMDECODESIZE_U64 * sizeof(unsigned long long)) union LZ4_streamDecode_u { - unsigned long long table[LZ4_STREAMDECODESIZE_U64]; - LZ4_streamDecode_t_internal internal_donotuse; -} ; /* previously typedef'd to LZ4_streamDecode_t */ + unsigned long long table[LZ4_STREAMDECODESIZE_U64]; + LZ4_streamDecode_t_internal internal_donotuse; +}; /* previously typedef'd to LZ4_streamDecode_t */ #ifndef HEAPMODE #define HEAPMODE 0 @@ -202,7 +207,7 @@ union LZ4_streamDecode_u { #define LZ4_FORCE_MEMORY_ACCESS 2 #endif -#if defined(_MSC_VER) && defined(_WIN32_WCE) /* Visual Studio for Windows CE does not support Hardware bit count */ +#if defined(_MSC_VER) && defined(_WIN32_WCE) /* Visual Studio for Windows CE does not support Hardware bit count */ #define LZ4_FORCE_SW_BITCOUNT #endif @@ -210,222 +215,280 @@ union LZ4_streamDecode_u { #define FORCE_INLINE static inline #endif -#define ALLOCATOR(n,s) calloc(n,s) -#define FREEMEM free -#define MEM_INIT memset +#define ALLOCATOR(n, s) calloc(n, s) +#define FREEMEM free +#define MEM_INIT memset -typedef uint8_t BYTE; +typedef uint8_t BYTE; typedef uint16_t U16; typedef uint32_t U32; -typedef int32_t S32; +typedef int32_t S32; typedef uint64_t U64; typedef uintptr_t uptrval; typedef uintptr_t reg_t; static inline unsigned LZ4_isLittleEndian(void) { - const union { U32 u; BYTE c[4]; } one = { 1 }; /* don't use static : performance detrimental */ - return one.c[0]; + const union { + U32 u; + BYTE c[4]; + } one = { 1 }; /* don't use static : performance detrimental */ + return one.c[0]; } -#if defined(LZ4_FORCE_MEMORY_ACCESS) && (LZ4_FORCE_MEMORY_ACCESS==2) -static U16 LZ4_read16(const void* memPtr) { return *(const U16*) memPtr; } -static U32 LZ4_read32(const void* memPtr) { return *(const U32*) memPtr; } -static reg_t LZ4_read_ARCH(const void* memPtr) { return *(const reg_t*) memPtr; } -static void LZ4_write16(void* memPtr, U16 value) { *(U16*)memPtr = value; } -static void LZ4_write32(void* memPtr, U32 value) { *(U32*)memPtr = value; } -#elif defined(LZ4_FORCE_MEMORY_ACCESS) && (LZ4_FORCE_MEMORY_ACCESS==1) -typedef union { U16 u16; U32 u32; reg_t uArch; } __attribute__((packed)) unalign; -static U16 LZ4_read16(const void* ptr) { return ((const unalign*)ptr)->u16; } -static U32 LZ4_read32(const void* ptr) { return ((const unalign*)ptr)->u32; } -static reg_t LZ4_read_ARCH(const void* ptr) { return ((const unalign*)ptr)->uArch; } -static void LZ4_write16(void* memPtr, U16 value) { ((unalign*)memPtr)->u16 = value; } -static void LZ4_write32(void* memPtr, U32 value) { ((unalign*)memPtr)->u32 = value; } +#if defined(LZ4_FORCE_MEMORY_ACCESS) && (LZ4_FORCE_MEMORY_ACCESS == 2) +static U16 LZ4_read16(const void* memPtr) +{ + return *(const U16*)memPtr; +} +static U32 LZ4_read32(const void* memPtr) +{ + return *(const U32*)memPtr; +} +static reg_t LZ4_read_ARCH(const void* memPtr) +{ + return *(const reg_t*)memPtr; +} +static void LZ4_write16(void* memPtr, U16 value) +{ + *(U16*)memPtr = value; +} +static void LZ4_write32(void* memPtr, U32 value) +{ + *(U32*)memPtr = value; +} +#elif defined(LZ4_FORCE_MEMORY_ACCESS) && (LZ4_FORCE_MEMORY_ACCESS == 1) +typedef union { + U16 u16; + U32 u32; + reg_t uArch; +} __attribute__((packed)) unalign; +static U16 LZ4_read16(const void* ptr) +{ + return ((const unalign*)ptr)->u16; +} +static U32 LZ4_read32(const void* ptr) +{ + return ((const unalign*)ptr)->u32; +} +static reg_t LZ4_read_ARCH(const void* ptr) +{ + return ((const unalign*)ptr)->uArch; +} +static void LZ4_write16(void* memPtr, U16 value) +{ + ((unalign*)memPtr)->u16 = value; +} +static void LZ4_write32(void* memPtr, U32 value) +{ + ((unalign*)memPtr)->u32 = value; +} #else /* safe and portable access through memcpy() */ static inline U16 LZ4_read16(const void* memPtr) { - U16 val; memcpy(&val, memPtr, sizeof(val)); return val; + U16 val; + memcpy(&val, memPtr, sizeof(val)); + return val; } static inline U32 LZ4_read32(const void* memPtr) { - U32 val; memcpy(&val, memPtr, sizeof(val)); return val; + U32 val; + memcpy(&val, memPtr, sizeof(val)); + return val; } static inline reg_t LZ4_read_ARCH(const void* memPtr) { - reg_t val; memcpy(&val, memPtr, sizeof(val)); return val; + reg_t val; + memcpy(&val, memPtr, sizeof(val)); + return val; } static inline void LZ4_write16(void* memPtr, U16 value) { - memcpy(memPtr, &value, sizeof(value)); + memcpy(memPtr, &value, sizeof(value)); } static inline void LZ4_write32(void* memPtr, U32 value) { - memcpy(memPtr, &value, sizeof(value)); + memcpy(memPtr, &value, sizeof(value)); } #endif /* LZ4_FORCE_MEMORY_ACCESS */ static inline U16 LZ4_readLE16(const void* memPtr) { - if (LZ4_isLittleEndian()) { - return LZ4_read16(memPtr); - } else { - const BYTE* p = (const BYTE*)memPtr; - return (U16)((U16)p[0] + (p[1]<<8)); - } + if (LZ4_isLittleEndian()) { + return LZ4_read16(memPtr); + } + else { + const BYTE* p = (const BYTE*)memPtr; + return (U16)((U16)p[0] + (p[1] << 8)); + } } static inline void LZ4_writeLE16(void* memPtr, U16 value) { - if (LZ4_isLittleEndian()) { - LZ4_write16(memPtr, value); - } else { - BYTE* p = (BYTE*)memPtr; - p[0] = (BYTE) value; - p[1] = (BYTE)(value>>8); - } + if (LZ4_isLittleEndian()) { + LZ4_write16(memPtr, value); + } + else { + BYTE* p = (BYTE*)memPtr; + p[0] = (BYTE)value; + p[1] = (BYTE)(value >> 8); + } } static inline void LZ4_copy8(void* dst, const void* src) { - memcpy(dst,src,8); + memcpy(dst, src, 8); } static inline void LZ4_wildCopy(void* dstPtr, const void* srcPtr, void* dstEnd) { - BYTE* d = (BYTE*)dstPtr; - const BYTE* s = (const BYTE*)srcPtr; - BYTE* const e = (BYTE*)dstEnd; - do { - LZ4_copy8(d,s); - d+=8; - s+=8; - } while (d>3); -# elif (defined(__clang__) || (defined(__GNUC__) && (__GNUC__>=3))) && !defined(LZ4_FORCE_SW_BITCOUNT) - return (__builtin_ctzll((U64)val) >> 3); -# else - static const int DeBruijnBytePos[64] = { 0, 0, 0, 0, 0, 1, 1, 2, 0, 3, 1, 3, 1, 4, 2, 7, 0, 2, 3, 6, 1, 5, 3, 5, 1, 3, 4, 4, 2, 5, 6, 7, 7, 0, 1, 2, 3, 3, 4, 6, 2, 6, 5, 5, 3, 4, 5, 6, 7, 1, 2, 4, 6, 4, 4, 5, 7, 2, 6, 5, 7, 6, 7, 7 }; - return DeBruijnBytePos[((U64)((val & -(long long)val) * 0x0218A392CDABBD3FULL)) >> 58]; -# endif - } else /* 32 bits */ { -# if defined(_MSC_VER) && !defined(LZ4_FORCE_SW_BITCOUNT) - unsigned long r; - _BitScanForward( &r, (U32)val ); - return (int)(r>>3); -# elif (defined(__clang__) || (defined(__GNUC__) && (__GNUC__>=3))) && !defined(LZ4_FORCE_SW_BITCOUNT) - return (__builtin_ctz((U32)val) >> 3); -# else - static const int DeBruijnBytePos[32] = { 0, 0, 3, 0, 3, 1, 3, 0, 3, 2, 2, 1, 3, 2, 0, 1, 3, 3, 1, 2, 2, 2, 2, 0, 3, 1, 2, 0, 1, 0, 1, 1 }; - return DeBruijnBytePos[((U32)((val & -(S32)val) * 0x077CB531U)) >> 27]; -# endif - } - } else /* Big Endian CPU */ { - if (sizeof(val)==8) { -# if defined(_MSC_VER) && defined(_WIN64) && !defined(LZ4_FORCE_SW_BITCOUNT) - unsigned long r = 0; - _BitScanReverse64( &r, val ); - return (unsigned)(r>>3); -# elif (defined(__clang__) || (defined(__GNUC__) && (__GNUC__>=3))) && !defined(LZ4_FORCE_SW_BITCOUNT) - return (__builtin_clzll((U64)val) >> 3); -# else - unsigned r; - if (!(val>>32)) { - r=4; - } else { - r=0; - val>>=32; - } - if (!(val>>16)) { - r+=2; - val>>=8; - } else { - val>>=24; - } - r += (!val); - return r; -# endif - } else /* 32 bits */ { -# if defined(_MSC_VER) && !defined(LZ4_FORCE_SW_BITCOUNT) - unsigned long r = 0; - _BitScanReverse( &r, (unsigned long)val ); - return (unsigned)(r>>3); -# elif (defined(__clang__) || (defined(__GNUC__) && (__GNUC__>=3))) && !defined(LZ4_FORCE_SW_BITCOUNT) - return (__builtin_clz((U32)val) >> 3); -# else - unsigned r; - if (!(val>>16)) { - r=2; - val>>=8; - } else { - r=0; - val>>=24; - } - r += (!val); - return r; -# endif - } - } + if (LZ4_isLittleEndian()) { + if (sizeof(val) == 8) { +#if defined(_MSC_VER) && defined(_WIN64) && ! defined(LZ4_FORCE_SW_BITCOUNT) + unsigned long r = 0; + _BitScanForward64(&r, (U64)val); + return (int)(r >> 3); +#elif (defined(__clang__) || (defined(__GNUC__) && (__GNUC__ >= 3))) && ! defined(LZ4_FORCE_SW_BITCOUNT) + return (__builtin_ctzll((U64)val) >> 3); +#else + static const int DeBruijnBytePos[64] = { 0, 0, 0, 0, 0, 1, 1, 2, 0, 3, 1, 3, 1, 4, 2, 7, 0, 2, 3, 6, 1, 5, 3, 5, 1, 3, 4, 4, 2, 5, 6, 7, + 7, 0, 1, 2, 3, 3, 4, 6, 2, 6, 5, 5, 3, 4, 5, 6, 7, 1, 2, 4, 6, 4, 4, 5, 7, 2, 6, 5, 7, 6, 7, 7 }; + return DeBruijnBytePos[((U64)((val & -(long long)val) * 0x0218A392CDABBD3FULL)) >> 58]; +#endif + } + else /* 32 bits */ { +#if defined(_MSC_VER) && ! defined(LZ4_FORCE_SW_BITCOUNT) + unsigned long r; + _BitScanForward(&r, (U32)val); + return (int)(r >> 3); +#elif (defined(__clang__) || (defined(__GNUC__) && (__GNUC__ >= 3))) && ! defined(LZ4_FORCE_SW_BITCOUNT) + return (__builtin_ctz((U32)val) >> 3); +#else + static const int DeBruijnBytePos[32] = { 0, 0, 3, 0, 3, 1, 3, 0, 3, 2, 2, 1, 3, 2, 0, 1, 3, 3, 1, 2, 2, 2, 2, 0, 3, 1, 2, 0, 1, 0, 1, 1 }; + return DeBruijnBytePos[((U32)((val & -(S32)val) * 0x077CB531U)) >> 27]; +#endif + } + } + else /* Big Endian CPU */ { + if (sizeof(val) == 8) { +#if defined(_MSC_VER) && defined(_WIN64) && ! defined(LZ4_FORCE_SW_BITCOUNT) + unsigned long r = 0; + _BitScanReverse64(&r, val); + return (unsigned)(r >> 3); +#elif (defined(__clang__) || (defined(__GNUC__) && (__GNUC__ >= 3))) && ! defined(LZ4_FORCE_SW_BITCOUNT) + return (__builtin_clzll((U64)val) >> 3); +#else + unsigned r; + if (! (val >> 32)) { + r = 4; + } + else { + r = 0; + val >>= 32; + } + if (! (val >> 16)) { + r += 2; + val >>= 8; + } + else { + val >>= 24; + } + r += (! val); + return r; +#endif + } + else /* 32 bits */ { +#if defined(_MSC_VER) && ! defined(LZ4_FORCE_SW_BITCOUNT) + unsigned long r = 0; + _BitScanReverse(&r, (unsigned long)val); + return (unsigned)(r >> 3); +#elif (defined(__clang__) || (defined(__GNUC__) && (__GNUC__ >= 3))) && ! defined(LZ4_FORCE_SW_BITCOUNT) + return (__builtin_clz((U32)val) >> 3); +#else + unsigned r; + if (! (val >> 16)) { + r = 2; + val >>= 8; + } + else { + r = 0; + val >>= 24; + } + r += (! val); + return r; +#endif + } + } } #define STEPSIZE sizeof(reg_t) static inline unsigned LZ4_count(const BYTE* pIn, const BYTE* pMatch, const BYTE* pInLimit) { - const BYTE* const pStart = pIn; + const BYTE* const pStart = pIn; - while (likely(pIn compression run slower on incompressible data */ +static const int LZ4_64Klimit = ((64 KB) + (MFLIMIT - 1)); +static const U32 LZ4_skipTrigger = 6; /* Increase this value ==> compression run slower on incompressible data */ typedef enum { notLimited = 0, limitedOutput = 1 } limitedOutput_directive; typedef enum { byPtr, byU32, byU16 } tableType_t; @@ -436,761 +499,826 @@ typedef enum { noDictIssue = 0, dictSmall } dictIssue_directive; typedef enum { endOnOutputSize = 0, endOnInputSize = 1 } endCondition_directive; typedef enum { full = 0, partial = 1 } earlyEnd_directive; -static inline int LZ4_compressBound(int isize) { return LZ4_COMPRESSBOUND(isize); } +static inline int LZ4_compressBound(int isize) +{ + return LZ4_COMPRESSBOUND(isize); +} static inline U32 LZ4_hash4(U32 sequence, tableType_t const tableType) { - if (tableType == byU16) { - return ((sequence * 2654435761U) >> ((MINMATCH*8)-(LZ4_HASHLOG+1))); - } else { - return ((sequence * 2654435761U) >> ((MINMATCH*8)-LZ4_HASHLOG)); - } + if (tableType == byU16) { + return ((sequence * 2654435761U) >> ((MINMATCH * 8) - (LZ4_HASHLOG + 1))); + } + else { + return ((sequence * 2654435761U) >> ((MINMATCH * 8) - LZ4_HASHLOG)); + } } static inline U32 LZ4_hash5(U64 sequence, tableType_t const tableType) { - static const U64 prime5bytes = 889523592379ULL; - static const U64 prime8bytes = 11400714785074694791ULL; - const U32 hashLog = (tableType == byU16) ? LZ4_HASHLOG+1 : LZ4_HASHLOG; - if (LZ4_isLittleEndian()) { - return (U32)(((sequence << 24) * prime5bytes) >> (64 - hashLog)); - } else { - return (U32)(((sequence >> 24) * prime8bytes) >> (64 - hashLog)); - } + static const U64 prime5bytes = 889523592379ULL; + static const U64 prime8bytes = 11400714785074694791ULL; + const U32 hashLog = (tableType == byU16) ? LZ4_HASHLOG + 1 : LZ4_HASHLOG; + if (LZ4_isLittleEndian()) { + return (U32)(((sequence << 24) * prime5bytes) >> (64 - hashLog)); + } + else { + return (U32)(((sequence >> 24) * prime8bytes) >> (64 - hashLog)); + } } FORCE_INLINE U32 LZ4_hashPosition(const void* const p, tableType_t const tableType) { - if ((sizeof(reg_t)==8) && (tableType != byU16)) { - return LZ4_hash5(LZ4_read_ARCH(p), tableType); - } - return LZ4_hash4(LZ4_read32(p), tableType); + if ((sizeof(reg_t) == 8) && (tableType != byU16)) { + return LZ4_hash5(LZ4_read_ARCH(p), tableType); + } + return LZ4_hash4(LZ4_read32(p), tableType); } static inline void LZ4_putPositionOnHash(const BYTE* p, U32 h, void* tableBase, tableType_t const tableType, const BYTE* srcBase) { - switch (tableType) { - case byPtr: { - const BYTE** hashTable = (const BYTE**)tableBase; hashTable[h] = p; - return; - } - case byU32: { - U32* hashTable = (U32*) tableBase; hashTable[h] = (U32)(p-srcBase); - return; - } - case byU16: { - U16* hashTable = (U16*) tableBase; hashTable[h] = (U16)(p-srcBase); - return; - } - } + switch (tableType) { + case byPtr: { + const BYTE** hashTable = (const BYTE**)tableBase; + hashTable[h] = p; + return; + } + case byU32: { + U32* hashTable = (U32*)tableBase; + hashTable[h] = (U32)(p - srcBase); + return; + } + case byU16: { + U16* hashTable = (U16*)tableBase; + hashTable[h] = (U16)(p - srcBase); + return; + } + } } FORCE_INLINE void LZ4_putPosition(const BYTE* p, void* tableBase, tableType_t tableType, const BYTE* srcBase) { - U32 const h = LZ4_hashPosition(p, tableType); - LZ4_putPositionOnHash(p, h, tableBase, tableType, srcBase); + U32 const h = LZ4_hashPosition(p, tableType); + LZ4_putPositionOnHash(p, h, tableBase, tableType, srcBase); } static inline const BYTE* LZ4_getPositionOnHash(U32 h, void* tableBase, tableType_t tableType, const BYTE* srcBase) { - if (tableType == byPtr) { - const BYTE** hashTable = (const BYTE**) tableBase; - return hashTable[h]; - } - if (tableType == byU32) { - const U32* const hashTable = (U32*) tableBase; - return hashTable[h] + srcBase; - } - { /* default, to ensure a return */ - const U16* const hashTable = (U16*) tableBase; - return hashTable[h] + srcBase; - } + if (tableType == byPtr) { + const BYTE** hashTable = (const BYTE**)tableBase; + return hashTable[h]; + } + if (tableType == byU32) { + const U32* const hashTable = (U32*)tableBase; + return hashTable[h] + srcBase; + } + { /* default, to ensure a return */ + const U16* const hashTable = (U16*)tableBase; + return hashTable[h] + srcBase; + } } FORCE_INLINE const BYTE* LZ4_getPosition(const BYTE* p, void* tableBase, tableType_t tableType, const BYTE* srcBase) { - U32 const h = LZ4_hashPosition(p, tableType); - return LZ4_getPositionOnHash(h, tableBase, tableType, srcBase); + U32 const h = LZ4_hashPosition(p, tableType); + return LZ4_getPositionOnHash(h, tableBase, tableType, srcBase); } FORCE_INLINE int LZ4_compress_generic( - LZ4_stream_t_internal* const cctx, - const char* const source, - char* const dest, - const int inputSize, - const int maxOutputSize, - const limitedOutput_directive outputLimited, - const tableType_t tableType, - const dict_directive dict, - const dictIssue_directive dictIssue, - const U32 acceleration) + LZ4_stream_t_internal* const cctx, + const char* const source, + char* const dest, + const int inputSize, + const int maxOutputSize, + const limitedOutput_directive outputLimited, + const tableType_t tableType, + const dict_directive dict, + const dictIssue_directive dictIssue, + const U32 acceleration) { - const BYTE* ip = (const BYTE*) source; - const BYTE* base; - const BYTE* lowLimit; - const BYTE* const lowRefLimit = ip - cctx->dictSize; - const BYTE* const dictionary = cctx->dictionary; - const BYTE* const dictEnd = dictionary + cctx->dictSize; - const ptrdiff_t dictDelta = dictEnd - (const BYTE*)source; - const BYTE* anchor = (const BYTE*) source; - const BYTE* const iend = ip + inputSize; - const BYTE* const mflimit = iend - MFLIMIT; - const BYTE* const matchlimit = iend - LASTLITERALS; + const BYTE* ip = (const BYTE*)source; + const BYTE* base; + const BYTE* lowLimit; + const BYTE* const lowRefLimit = ip - cctx->dictSize; + const BYTE* const dictionary = cctx->dictionary; + const BYTE* const dictEnd = dictionary + cctx->dictSize; + const ptrdiff_t dictDelta = dictEnd - (const BYTE*)source; + const BYTE* anchor = (const BYTE*)source; + const BYTE* const iend = ip + inputSize; + const BYTE* const mflimit = iend - MFLIMIT; + const BYTE* const matchlimit = iend - LASTLITERALS; - BYTE* op = (BYTE*) dest; - BYTE* const olimit = op + maxOutputSize; + BYTE* op = (BYTE*)dest; + BYTE* const olimit = op + maxOutputSize; - U32 forwardH; + U32 forwardH; - /* Init conditions */ - if ((U32)inputSize > (U32)LZ4_MAX_INPUT_SIZE) { - return 0; /* Unsupported inputSize, too large (or negative) */ - } - switch(dict) { - case noDict: - default: - base = (const BYTE*)source; - lowLimit = (const BYTE*)source; - break; - case withPrefix64k: - base = (const BYTE*)source - cctx->currentOffset; - lowLimit = (const BYTE*)source - cctx->dictSize; - break; - case usingExtDict: - base = (const BYTE*)source - cctx->currentOffset; - lowLimit = (const BYTE*)source; - break; - } - if ((tableType == byU16) && (inputSize>=LZ4_64Klimit)) { - return 0; /* Size too large (not within 64K limit) */ - } - if (inputSize (U32)LZ4_MAX_INPUT_SIZE) { + return 0; /* Unsupported inputSize, too large (or negative) */ + } + switch (dict) { + case noDict: + default: + base = (const BYTE*)source; + lowLimit = (const BYTE*)source; + break; + case withPrefix64k: + base = (const BYTE*)source - cctx->currentOffset; + lowLimit = (const BYTE*)source - cctx->dictSize; + break; + case usingExtDict: + base = (const BYTE*)source - cctx->currentOffset; + lowLimit = (const BYTE*)source; + break; + } + if ((tableType == byU16) && (inputSize >= LZ4_64Klimit)) { + return 0; /* Size too large (not within 64K limit) */ + } + if (inputSize < LZ4_minLength) { + goto _last_literals; /* Input too small, no compression (all literals) */ + } - /* First Byte */ - LZ4_putPosition(ip, cctx->hashTable, tableType, base); - ip++; - forwardH = LZ4_hashPosition(ip, tableType); + /* First Byte */ + LZ4_putPosition(ip, cctx->hashTable, tableType, base); + ip++; + forwardH = LZ4_hashPosition(ip, tableType); - /* Main Loop */ - for ( ; ; ) { - ptrdiff_t refDelta = 0; - const BYTE* match; - BYTE* token; + /* Main Loop */ + for (;;) { + ptrdiff_t refDelta = 0; + const BYTE* match; + BYTE* token; - /* Find a match */ - { - const BYTE* forwardIp = ip; - unsigned step = 1; - unsigned searchMatchNb = acceleration << LZ4_skipTrigger; - do { - U32 const h = forwardH; - ip = forwardIp; - forwardIp += step; - step = (searchMatchNb++ >> LZ4_skipTrigger); + /* Find a match */ + { + const BYTE* forwardIp = ip; + unsigned step = 1; + unsigned searchMatchNb = acceleration << LZ4_skipTrigger; + do { + U32 const h = forwardH; + ip = forwardIp; + forwardIp += step; + step = (searchMatchNb++ >> LZ4_skipTrigger); - if (unlikely(forwardIp > mflimit)) { - goto _last_literals; - } + if (unlikely(forwardIp > mflimit)) { + goto _last_literals; + } - match = LZ4_getPositionOnHash(h, cctx->hashTable, tableType, base); - if (dict==usingExtDict) { - if (match < (const BYTE*)source) { - refDelta = dictDelta; - lowLimit = dictionary; - } else { - refDelta = 0; - lowLimit = (const BYTE*)source; - } - } - forwardH = LZ4_hashPosition(forwardIp, tableType); - LZ4_putPositionOnHash(ip, h, cctx->hashTable, tableType, base); + match = LZ4_getPositionOnHash(h, cctx->hashTable, tableType, base); + if (dict == usingExtDict) { + if (match < (const BYTE*)source) { + refDelta = dictDelta; + lowLimit = dictionary; + } + else { + refDelta = 0; + lowLimit = (const BYTE*)source; + } + } + forwardH = LZ4_hashPosition(forwardIp, tableType); + LZ4_putPositionOnHash(ip, h, cctx->hashTable, tableType, base); - } while ( ((dictIssue==dictSmall) ? (match < lowRefLimit) : 0) - || ((tableType==byU16) ? 0 : (match + MAX_DISTANCE < ip)) - || (LZ4_read32(match+refDelta) != LZ4_read32(ip)) ); - } + } while (((dictIssue == dictSmall) ? (match < lowRefLimit) : 0) || ((tableType == byU16) ? 0 : (match + MAX_DISTANCE < ip)) || (LZ4_read32(match + refDelta) != LZ4_read32(ip))); + } - /* Catch up */ - while (((ip>anchor) & (match+refDelta > lowLimit)) && (unlikely(ip[-1]==match[refDelta-1]))) { - ip--; - match--; - } + /* Catch up */ + while (((ip > anchor) & (match + refDelta > lowLimit)) && (unlikely(ip[-1] == match[refDelta - 1]))) { + ip--; + match--; + } - /* Encode Literals */ - { - unsigned const litLength = (unsigned)(ip - anchor); - token = op++; - if ((outputLimited) && /* Check output buffer overflow */ - (unlikely(op + litLength + (2 + 1 + LASTLITERALS) + (litLength/255) > olimit))) { - return 0; - } - if (litLength >= RUN_MASK) { - int len = (int)litLength-RUN_MASK; - *token = (RUN_MASK<= 255 ; len-=255) { - *op++ = 255; - } - *op++ = (BYTE)len; - } else { - *token = (BYTE)(litLength< olimit))) { + return 0; + } + if (litLength >= RUN_MASK) { + int len = (int)litLength - RUN_MASK; + *token = (RUN_MASK << ML_BITS); + for (; len >= 255; len -= 255) { + *op++ = 255; + } + *op++ = (BYTE)len; + } + else { + *token = (BYTE)(litLength << ML_BITS); + } - /* Copy Literals */ - LZ4_wildCopy(op, anchor, op+litLength); - op+=litLength; - } + /* Copy Literals */ + LZ4_wildCopy(op, anchor, op + litLength); + op += litLength; + } -_next_match: - /* Encode Offset */ - LZ4_writeLE16(op, (U16)(ip-match)); - op+=2; + _next_match: + /* Encode Offset */ + LZ4_writeLE16(op, (U16)(ip - match)); + op += 2; - /* Encode MatchLength */ - { - unsigned matchCode; + /* Encode MatchLength */ + { + unsigned matchCode; - if ((dict==usingExtDict) && (lowLimit==dictionary)) { - const BYTE* limit; - match += refDelta; - limit = ip + (dictEnd-match); - if (limit > matchlimit) { - limit = matchlimit; - } - matchCode = LZ4_count(ip+MINMATCH, match+MINMATCH, limit); - ip += MINMATCH + matchCode; - if (ip==limit) { - unsigned const more = LZ4_count(ip, (const BYTE*)source, matchlimit); - matchCode += more; - ip += more; - } - } else { - matchCode = LZ4_count(ip+MINMATCH, match+MINMATCH, matchlimit); - ip += MINMATCH + matchCode; - } + if ((dict == usingExtDict) && (lowLimit == dictionary)) { + const BYTE* limit; + match += refDelta; + limit = ip + (dictEnd - match); + if (limit > matchlimit) { + limit = matchlimit; + } + matchCode = LZ4_count(ip + MINMATCH, match + MINMATCH, limit); + ip += MINMATCH + matchCode; + if (ip == limit) { + unsigned const more = LZ4_count(ip, (const BYTE*)source, matchlimit); + matchCode += more; + ip += more; + } + } + else { + matchCode = LZ4_count(ip + MINMATCH, match + MINMATCH, matchlimit); + ip += MINMATCH + matchCode; + } - if ( outputLimited && /* Check output buffer overflow */ - (unlikely(op + (1 + LASTLITERALS) + (matchCode>>8) > olimit)) ) { - return 0; - } - if (matchCode >= ML_MASK) { - *token += ML_MASK; - matchCode -= ML_MASK; - LZ4_write32(op, 0xFFFFFFFF); - while (matchCode >= 4*255) { - op+=4; - LZ4_write32(op, 0xFFFFFFFF); - matchCode -= 4*255; - } - op += matchCode / 255; - *op++ = (BYTE)(matchCode % 255); - } else { - *token += (BYTE)(matchCode); - } - } + if (outputLimited && /* Check output buffer overflow */ + (unlikely(op + (1 + LASTLITERALS) + (matchCode >> 8) > olimit))) { + return 0; + } + if (matchCode >= ML_MASK) { + *token += ML_MASK; + matchCode -= ML_MASK; + LZ4_write32(op, 0xFFFFFFFF); + while (matchCode >= 4 * 255) { + op += 4; + LZ4_write32(op, 0xFFFFFFFF); + matchCode -= 4 * 255; + } + op += matchCode / 255; + *op++ = (BYTE)(matchCode % 255); + } + else { + *token += (BYTE)(matchCode); + } + } - anchor = ip; + anchor = ip; - /* Test end of chunk */ - if (ip > mflimit) { - break; - } + /* Test end of chunk */ + if (ip > mflimit) { + break; + } - /* Fill table */ - LZ4_putPosition(ip-2, cctx->hashTable, tableType, base); + /* Fill table */ + LZ4_putPosition(ip - 2, cctx->hashTable, tableType, base); - /* Test next position */ - match = LZ4_getPosition(ip, cctx->hashTable, tableType, base); - if (dict==usingExtDict) { - if (match < (const BYTE*)source) { - refDelta = dictDelta; - lowLimit = dictionary; - } else { - refDelta = 0; - lowLimit = (const BYTE*)source; - } - } - LZ4_putPosition(ip, cctx->hashTable, tableType, base); - if ( ((dictIssue==dictSmall) ? (match>=lowRefLimit) : 1) - && (match+MAX_DISTANCE>=ip) - && (LZ4_read32(match+refDelta)==LZ4_read32(ip)) ) { - token=op++; - *token=0; - goto _next_match; - } + /* Test next position */ + match = LZ4_getPosition(ip, cctx->hashTable, tableType, base); + if (dict == usingExtDict) { + if (match < (const BYTE*)source) { + refDelta = dictDelta; + lowLimit = dictionary; + } + else { + refDelta = 0; + lowLimit = (const BYTE*)source; + } + } + LZ4_putPosition(ip, cctx->hashTable, tableType, base); + if (((dictIssue == dictSmall) ? (match >= lowRefLimit) : 1) && (match + MAX_DISTANCE >= ip) && (LZ4_read32(match + refDelta) == LZ4_read32(ip))) { + token = op++; + *token = 0; + goto _next_match; + } - /* Prepare next loop */ - forwardH = LZ4_hashPosition(++ip, tableType); - } + /* Prepare next loop */ + forwardH = LZ4_hashPosition(++ip, tableType); + } _last_literals: - /* Encode Last Literals */ - { - size_t const lastRun = (size_t)(iend - anchor); - if ( (outputLimited) && /* Check output buffer overflow */ - ((op - (BYTE*)dest) + lastRun + 1 + ((lastRun+255-RUN_MASK)/255) > (U32)maxOutputSize) ) { - return 0; - } - if (lastRun >= RUN_MASK) { - size_t accumulator = lastRun - RUN_MASK; - *op++ = RUN_MASK << ML_BITS; - for(; accumulator >= 255 ; accumulator-=255) { - *op++ = 255; - } - *op++ = (BYTE) accumulator; - } else { - *op++ = (BYTE)(lastRun< (U32)maxOutputSize)) { + return 0; + } + if (lastRun >= RUN_MASK) { + size_t accumulator = lastRun - RUN_MASK; + *op++ = RUN_MASK << ML_BITS; + for (; accumulator >= 255; accumulator -= 255) { + *op++ = 255; + } + *op++ = (BYTE)accumulator; + } + else { + *op++ = (BYTE)(lastRun << ML_BITS); + } + memcpy(op, anchor, lastRun); + op += lastRun; + } - /* End */ - return (int) (((char*)op)-dest); + /* End */ + return (int)(((char*)op) - dest); } static inline int LZ4_compress_fast_extState(void* state, const char* source, char* dest, int inputSize, int maxOutputSize, int acceleration) { - LZ4_stream_t_internal* ctx = &((LZ4_stream_t*)state)->internal_donotuse; - LZ4_resetStream((LZ4_stream_t*)state); - //if (acceleration < 1) acceleration = ACCELERATION_DEFAULT; + LZ4_stream_t_internal* ctx = &((LZ4_stream_t*)state)->internal_donotuse; + LZ4_resetStream((LZ4_stream_t*)state); + // if (acceleration < 1) acceleration = ACCELERATION_DEFAULT; - if (maxOutputSize >= LZ4_compressBound(inputSize)) { - if (inputSize < LZ4_64Klimit) { - return LZ4_compress_generic(ctx, source, dest, inputSize, 0, notLimited, byU16, noDict, noDictIssue, acceleration); - } else { - return LZ4_compress_generic(ctx, source, dest, inputSize, 0, notLimited, (sizeof(void*)==8) ? byU32 : byPtr, noDict, noDictIssue, acceleration); - } - } else { - if (inputSize < LZ4_64Klimit) { - return LZ4_compress_generic(ctx, source, dest, inputSize, maxOutputSize, limitedOutput, byU16, noDict, noDictIssue, acceleration); - } else { - return LZ4_compress_generic(ctx, source, dest, inputSize, maxOutputSize, limitedOutput, (sizeof(void*)==8) ? byU32 : byPtr, noDict, noDictIssue, acceleration); - } - } + if (maxOutputSize >= LZ4_compressBound(inputSize)) { + if (inputSize < LZ4_64Klimit) { + return LZ4_compress_generic(ctx, source, dest, inputSize, 0, notLimited, byU16, noDict, noDictIssue, acceleration); + } + else { + return LZ4_compress_generic(ctx, source, dest, inputSize, 0, notLimited, (sizeof(void*) == 8) ? byU32 : byPtr, noDict, noDictIssue, acceleration); + } + } + else { + if (inputSize < LZ4_64Klimit) { + return LZ4_compress_generic(ctx, source, dest, inputSize, maxOutputSize, limitedOutput, byU16, noDict, noDictIssue, acceleration); + } + else { + return LZ4_compress_generic(ctx, source, dest, inputSize, maxOutputSize, limitedOutput, (sizeof(void*) == 8) ? byU32 : byPtr, noDict, noDictIssue, acceleration); + } + } } static inline int LZ4_compress_fast(const char* source, char* dest, int inputSize, int maxOutputSize, int acceleration) { #if (HEAPMODE) - void* ctxPtr = ALLOCATOR(1, sizeof(LZ4_stream_t)); /* malloc-calloc always properly aligned */ + void* ctxPtr = ALLOCATOR(1, sizeof(LZ4_stream_t)); /* malloc-calloc always properly aligned */ #else - LZ4_stream_t ctx; - void* const ctxPtr = &ctx; + LZ4_stream_t ctx; + void* const ctxPtr = &ctx; #endif - int const result = LZ4_compress_fast_extState(ctxPtr, source, dest, inputSize, maxOutputSize, acceleration); + int const result = LZ4_compress_fast_extState(ctxPtr, source, dest, inputSize, maxOutputSize, acceleration); #if (HEAPMODE) - FREEMEM(ctxPtr); + FREEMEM(ctxPtr); #endif - return result; + return result; } -static inline void LZ4_resetStream (LZ4_stream_t* LZ4_stream) +static inline void LZ4_resetStream(LZ4_stream_t* LZ4_stream) { - MEM_INIT(LZ4_stream, 0, sizeof(LZ4_stream_t)); + MEM_INIT(LZ4_stream, 0, sizeof(LZ4_stream_t)); } FORCE_INLINE int LZ4_decompress_generic( - const char* const source, - char* const dest, - int inputSize, - int outputSize, /* If endOnInput==endOnInputSize, this value is the max size of Output Buffer. */ + const char* const source, + char* const dest, + int inputSize, + int outputSize, /* If endOnInput==endOnInputSize, this value is the max size of Output Buffer. */ - int endOnInput, /* endOnOutputSize, endOnInputSize */ - int partialDecoding, /* full, partial */ - int targetOutputSize, /* only used if partialDecoding==partial */ - int dict, /* noDict, withPrefix64k, usingExtDict */ - const BYTE* const lowPrefix, /* == dest when no prefix */ - const BYTE* const dictStart, /* only if dict==usingExtDict */ - const size_t dictSize /* note : = 0 if noDict */ - ) + int endOnInput, /* endOnOutputSize, endOnInputSize */ + int partialDecoding, /* full, partial */ + int targetOutputSize, /* only used if partialDecoding==partial */ + int dict, /* noDict, withPrefix64k, usingExtDict */ + const BYTE* const lowPrefix, /* == dest when no prefix */ + const BYTE* const dictStart, /* only if dict==usingExtDict */ + const size_t dictSize /* note : = 0 if noDict */ +) { - /* Local Variables */ - const BYTE* ip = (const BYTE*) source; - const BYTE* const iend = ip + inputSize; + /* Local Variables */ + const BYTE* ip = (const BYTE*)source; + const BYTE* const iend = ip + inputSize; - BYTE* op = (BYTE*) dest; - BYTE* const oend = op + outputSize; - BYTE* cpy; - BYTE* oexit = op + targetOutputSize; - const BYTE* const lowLimit = lowPrefix - dictSize; + BYTE* op = (BYTE*)dest; + BYTE* const oend = op + outputSize; + BYTE* cpy; + BYTE* oexit = op + targetOutputSize; + const BYTE* const lowLimit = lowPrefix - dictSize; - const BYTE* const dictEnd = (const BYTE*)dictStart + dictSize; - const unsigned dec32table[] = {0, 1, 2, 1, 4, 4, 4, 4}; - const int dec64table[] = {0, 0, 0, -1, 0, 1, 2, 3}; + const BYTE* const dictEnd = (const BYTE*)dictStart + dictSize; + const unsigned dec32table[] = { 0, 1, 2, 1, 4, 4, 4, 4 }; + const int dec64table[] = { 0, 0, 0, -1, 0, 1, 2, 3 }; - const int safeDecode = (endOnInput==endOnInputSize); - const int checkOffset = ((safeDecode) && (dictSize < (int)(64 KB))); + const int safeDecode = (endOnInput == endOnInputSize); + const int checkOffset = ((safeDecode) && (dictSize < (int)(64 KB))); + /* Special cases */ + if ((partialDecoding) && (oexit > oend - MFLIMIT)) { + oexit = oend - MFLIMIT; /* targetOutputSize too high => decode everything */ + } + if ((endOnInput) && (unlikely(outputSize == 0))) { + return ((inputSize == 1) && (*ip == 0)) ? 0 : -1; /* Empty output buffer */ + } + if ((! endOnInput) && (unlikely(outputSize == 0))) { + return (*ip == 0 ? 1 : -1); + } - /* Special cases */ - if ((partialDecoding) && (oexit > oend-MFLIMIT)) { - oexit = oend-MFLIMIT; /* targetOutputSize too high => decode everything */ - } - if ((endOnInput) && (unlikely(outputSize==0))) { - return ((inputSize==1) && (*ip==0)) ? 0 : -1; /* Empty output buffer */ - } - if ((!endOnInput) && (unlikely(outputSize==0))) { - return (*ip==0?1:-1); - } + /* Main Loop : decode sequences */ + while (1) { + size_t length; + const BYTE* match; + size_t offset; - /* Main Loop : decode sequences */ - while (1) { - size_t length; - const BYTE* match; - size_t offset; + /* get literal length */ + unsigned const token = *ip++; + if ((length = (token >> ML_BITS)) == RUN_MASK) { + unsigned s; + do { + s = *ip++; + length += s; + } while (likely(endOnInput ? ip < iend - RUN_MASK : 1) & (s == 255)); + if ((safeDecode) && unlikely((uptrval)(op) + length < (uptrval)(op))) { + goto _output_error; /* overflow detection */ + } + if ((safeDecode) && unlikely((uptrval)(ip) + length < (uptrval)(ip))) { + goto _output_error; /* overflow detection */ + } + } - /* get literal length */ - unsigned const token = *ip++; - if ((length=(token>>ML_BITS)) == RUN_MASK) { - unsigned s; - do { - s = *ip++; - length += s; - } while ( likely(endOnInput ? ip (partialDecoding ? oexit : oend - MFLIMIT)) || (ip + length > iend - (2 + 1 + LASTLITERALS)))) || ((! endOnInput) && (cpy > oend - WILDCOPYLENGTH))) { + if (partialDecoding) { + if (cpy > oend) { + goto _output_error; /* Error : write attempt beyond end of output buffer */ + } + if ((endOnInput) && (ip + length > iend)) { + goto _output_error; /* Error : read attempt beyond end of input buffer */ + } + } + else { + if ((! endOnInput) && (cpy != oend)) { + goto _output_error; /* Error : block decoding must stop exactly there */ + } + if ((endOnInput) && ((ip + length != iend) || (cpy > oend))) { + goto _output_error; /* Error : input must be consumed */ + } + } + memcpy(op, ip, length); + ip += length; + op += length; + break; /* Necessarily EOF, due to parsing restrictions */ + } + LZ4_wildCopy(op, ip, cpy); + ip += length; + op = cpy; - /* copy literals */ - cpy = op+length; - if ( ((endOnInput) && ((cpy>(partialDecoding?oexit:oend-MFLIMIT)) || (ip+length>iend-(2+1+LASTLITERALS))) ) - || ((!endOnInput) && (cpy>oend-WILDCOPYLENGTH)) ) { - if (partialDecoding) { - if (cpy > oend) { - goto _output_error; /* Error : write attempt beyond end of output buffer */ - } - if ((endOnInput) && (ip+length > iend)) { - goto _output_error; /* Error : read attempt beyond end of input buffer */ - } - } else { - if ((!endOnInput) && (cpy != oend)) { - goto _output_error; /* Error : block decoding must stop exactly there */ - } - if ((endOnInput) && ((ip+length != iend) || (cpy > oend))) { - goto _output_error; /* Error : input must be consumed */ - } - } - memcpy(op, ip, length); - ip += length; - op += length; - break; /* Necessarily EOF, due to parsing restrictions */ - } - LZ4_wildCopy(op, ip, cpy); - ip += length; - op = cpy; + /* get offset */ + offset = LZ4_readLE16(ip); + ip += 2; + match = op - offset; + if ((checkOffset) && (unlikely(match < lowLimit))) { + goto _output_error; /* Error : offset outside buffers */ + } + LZ4_write32(op, (U32)offset); /* costs ~1%; silence an msan warning when offset==0 */ - /* get offset */ - offset = LZ4_readLE16(ip); - ip += 2; - match = op - offset; - if ((checkOffset) && (unlikely(match < lowLimit))) { - goto _output_error; /* Error : offset outside buffers */ - } - LZ4_write32(op, (U32)offset); /* costs ~1%; silence an msan warning when offset==0 */ + /* get matchlength */ + length = token & ML_MASK; + if (length == ML_MASK) { + unsigned s; + do { + s = *ip++; + if ((endOnInput) && (ip > iend - LASTLITERALS)) { + goto _output_error; + } + length += s; + } while (s == 255); + if ((safeDecode) && unlikely((uptrval)(op) + length < (uptrval)op)) { + goto _output_error; /* overflow detection */ + } + } + length += MINMATCH; - /* get matchlength */ - length = token & ML_MASK; - if (length == ML_MASK) { - unsigned s; - do { - s = *ip++; - if ((endOnInput) && (ip > iend-LASTLITERALS)) { - goto _output_error; - } - length += s; - } while (s==255); - if ((safeDecode) && unlikely((uptrval)(op)+length<(uptrval)op)) { - goto _output_error; /* overflow detection */ - } - } - length += MINMATCH; + /* check external dictionary */ + if ((dict == usingExtDict) && (match < lowPrefix)) { + if (unlikely(op + length > oend - LASTLITERALS)) { + goto _output_error; /* doesn't respect parsing restriction */ + } - /* check external dictionary */ - if ((dict==usingExtDict) && (match < lowPrefix)) { - if (unlikely(op+length > oend-LASTLITERALS)) { - goto _output_error; /* doesn't respect parsing restriction */ - } + if (length <= (size_t)(lowPrefix - match)) { + /* match can be copied as a single segment from external dictionary */ + memmove(op, dictEnd - (lowPrefix - match), length); + op += length; + } + else { + /* match encompass external dictionary and current block */ + size_t const copySize = (size_t)(lowPrefix - match); + size_t const restSize = length - copySize; + memcpy(op, dictEnd - copySize, copySize); + op += copySize; + if (restSize > (size_t)(op - lowPrefix)) { /* overlap copy */ + BYTE* const endOfMatch = op + restSize; + const BYTE* copyFrom = lowPrefix; + while (op < endOfMatch) { + *op++ = *copyFrom++; + } + } + else { + memcpy(op, lowPrefix, restSize); + op += restSize; + } + } + continue; + } - if (length <= (size_t)(lowPrefix-match)) { - /* match can be copied as a single segment from external dictionary */ - memmove(op, dictEnd - (lowPrefix-match), length); - op += length; - } else { - /* match encompass external dictionary and current block */ - size_t const copySize = (size_t)(lowPrefix-match); - size_t const restSize = length - copySize; - memcpy(op, dictEnd - copySize, copySize); - op += copySize; - if (restSize > (size_t)(op-lowPrefix)) { /* overlap copy */ - BYTE* const endOfMatch = op + restSize; - const BYTE* copyFrom = lowPrefix; - while (op < endOfMatch) { - *op++ = *copyFrom++; - } - } else { - memcpy(op, lowPrefix, restSize); - op += restSize; - } - } - continue; - } + /* copy match within block */ + cpy = op + length; + if (unlikely(offset < 8)) { + const int dec64 = dec64table[offset]; + op[0] = match[0]; + op[1] = match[1]; + op[2] = match[2]; + op[3] = match[3]; + match += dec32table[offset]; + memcpy(op + 4, match, 4); + match -= dec64; + } + else { + LZ4_copy8(op, match); + match += 8; + } + op += 8; - /* copy match within block */ - cpy = op + length; - if (unlikely(offset<8)) { - const int dec64 = dec64table[offset]; - op[0] = match[0]; - op[1] = match[1]; - op[2] = match[2]; - op[3] = match[3]; - match += dec32table[offset]; - memcpy(op+4, match, 4); - match -= dec64; - } else { - LZ4_copy8(op, match); - match+=8; - } - op += 8; + if (unlikely(cpy > oend - 12)) { + BYTE* const oCopyLimit = oend - (WILDCOPYLENGTH - 1); + if (cpy > oend - LASTLITERALS) { + goto _output_error; /* Error : last LASTLITERALS bytes must be literals (uncompressed) */ + } + if (op < oCopyLimit) { + LZ4_wildCopy(op, match, oCopyLimit); + match += oCopyLimit - op; + op = oCopyLimit; + } + while (op < cpy) { + *op++ = *match++; + } + } + else { + LZ4_copy8(op, match); + if (length > 16) { + LZ4_wildCopy(op + 8, match + 8, cpy); + } + } + op = cpy; /* correction */ + } - if (unlikely(cpy>oend-12)) { - BYTE* const oCopyLimit = oend-(WILDCOPYLENGTH-1); - if (cpy > oend-LASTLITERALS) { - goto _output_error; /* Error : last LASTLITERALS bytes must be literals (uncompressed) */ - } - if (op < oCopyLimit) { - LZ4_wildCopy(op, match, oCopyLimit); - match += oCopyLimit - op; - op = oCopyLimit; - } - while (op16) { - LZ4_wildCopy(op+8, match+8, cpy); - } - } - op=cpy; /* correction */ - } - - /* end of decoding */ - if (endOnInput) { - return (int) (((char*)op)-dest); /* Nb of output bytes decoded */ - } else { - return (int) (((const char*)ip)-source); /* Nb of input bytes read */ - } - /* Overflow error detected */ + /* end of decoding */ + if (endOnInput) { + return (int)(((char*)op) - dest); /* Nb of output bytes decoded */ + } + else { + return (int)(((const char*)ip) - source); /* Nb of input bytes read */ + } + /* Overflow error detected */ _output_error: - return (int) (-(((const char*)ip)-source))-1; + return (int)(-(((const char*)ip) - source)) - 1; } static inline int LZ4_decompress_safe(const char* source, char* dest, int compressedSize, int maxDecompressedSize) { - return LZ4_decompress_generic(source, dest, compressedSize, maxDecompressedSize, endOnInputSize, full, 0, noDict, (BYTE*)dest, NULL, 0); + return LZ4_decompress_generic(source, dest, compressedSize, maxDecompressedSize, endOnInputSize, full, 0, noDict, (BYTE*)dest, NULL, 0); } -} // anonymous namespace +} // anonymous namespace /************************************************************************** */ /************************************************************************** */ -const unsigned char Packet::ZERO_KEY[32] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }; +const unsigned char Packet::ZERO_KEY[32] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; -void Packet::armor(const void *key,bool encryptPayload,const AES aesKeys[2]) +void Packet::armor(const void* key, bool encryptPayload, bool extendedArmor, const AES aesKeys[2], const Identity& identity) { - uint8_t *const data = reinterpret_cast(unsafeData()); - if ((aesKeys) && (encryptPayload)) { - //char tmp0[16],tmp1[16]; - setCipher(ZT_PROTO_CIPHER_SUITE__AES_GMAC_SIV); + uint8_t* const data = reinterpret_cast(unsafeData()); - uint8_t *const payload = data + ZT_PACKET_IDX_VERB; - const unsigned int payloadLen = size() - ZT_PACKET_IDX_VERB; + this->setExtendedArmor(extendedArmor); - AES::GMACSIVEncryptor enc(aesKeys[0],aesKeys[1]); - enc.init(Utils::loadMachineEndian(data + ZT_PACKET_IDX_IV),payload); - enc.aad(data + ZT_PACKET_IDX_DEST,11); - enc.update1(payload,payloadLen); - enc.finish1(); - enc.update2(payload,payloadLen); - const uint64_t *const tag = enc.finish2(); + if ((aesKeys) && (encryptPayload)) { + setCipher(ZT_PROTO_CIPHER_SUITE__AES_GMAC_SIV); + + uint8_t* const payload = data + ZT_PACKET_IDX_VERB; + const unsigned int payloadLen = size() - ZT_PACKET_IDX_VERB; + + AES::GMACSIVEncryptor enc(aesKeys[0], aesKeys[1]); + enc.init(Utils::loadMachineEndian(data + ZT_PACKET_IDX_IV), payload); + enc.aad(data + ZT_PACKET_IDX_DEST, 11); + enc.update1(payload, payloadLen); + enc.finish1(); + enc.update2(payload, payloadLen); + const uint64_t* const tag = enc.finish2(); #ifdef ZT_NO_UNALIGNED_ACCESS - Utils::copy<8>(data,tag); - Utils::copy<8>(data + ZT_PACKET_IDX_MAC,tag + 1); + Utils::copy<8>(data, tag); + Utils::copy<8>(data + ZT_PACKET_IDX_MAC, tag + 1); #else - *reinterpret_cast(data + ZT_PACKET_IDX_IV) = tag[0]; - *reinterpret_cast(data + ZT_PACKET_IDX_MAC) = tag[1]; + *reinterpret_cast(data + ZT_PACKET_IDX_IV) = tag[0]; + *reinterpret_cast(data + ZT_PACKET_IDX_MAC) = tag[1]; #endif - } else { - setCipher(encryptPayload ? ZT_PROTO_CIPHER_SUITE__C25519_POLY1305_SALSA2012 : ZT_PROTO_CIPHER_SUITE__C25519_POLY1305_NONE); + } + else { + setCipher(encryptPayload ? ZT_PROTO_CIPHER_SUITE__C25519_POLY1305_SALSA2012 : ZT_PROTO_CIPHER_SUITE__C25519_POLY1305_NONE); - uint8_t mangledKey[32]; - _salsa20MangleKey((const unsigned char *)key,mangledKey); + uint8_t mangledKey[32]; + _salsa20MangleKey((const unsigned char*)key, mangledKey); + + if (ZT_HAS_FAST_CRYPTO()) { + const unsigned int payloadLen = (encryptPayload) ? (size() - ZT_PACKET_IDX_VERB) : 0; + uint64_t keyStream[(ZT_PROTO_MAX_PACKET_LENGTH + 64 + 8) / 8]; + uint64_t mac[2]; + + ZT_FAST_SINGLE_PASS_SALSA2012(keyStream, payloadLen + 64, (data + ZT_PACKET_IDX_IV), mangledKey); + Salsa20::memxor(data + ZT_PACKET_IDX_VERB, reinterpret_cast(keyStream + 8), payloadLen); + Poly1305::compute(mac, data + ZT_PACKET_IDX_VERB, size() - ZT_PACKET_IDX_VERB, keyStream); - if (ZT_HAS_FAST_CRYPTO()) { - const unsigned int payloadLen = (encryptPayload) ? (size() - ZT_PACKET_IDX_VERB) : 0; - uint64_t keyStream[(ZT_PROTO_MAX_PACKET_LENGTH + 64 + 8) / 8]; - ZT_FAST_SINGLE_PASS_SALSA2012(keyStream,payloadLen + 64,(data + ZT_PACKET_IDX_IV),mangledKey); - Salsa20::memxor(data + ZT_PACKET_IDX_VERB,reinterpret_cast(keyStream + 8),payloadLen); - uint64_t mac[2]; - Poly1305::compute(mac,data + ZT_PACKET_IDX_VERB,size() - ZT_PACKET_IDX_VERB,keyStream); #ifdef ZT_NO_TYPE_PUNNING - memcpy(data + ZT_PACKET_IDX_MAC,mac,8); + memcpy(data + ZT_PACKET_IDX_MAC, mac, 8); #else - (*reinterpret_cast(data + ZT_PACKET_IDX_MAC)) = mac[0]; + (*reinterpret_cast(data + ZT_PACKET_IDX_MAC)) = mac[0]; #endif - } else { - Salsa20 s20(mangledKey,data + ZT_PACKET_IDX_IV); + } + else { + uint64_t macKey[4]; + uint64_t mac[2]; - uint64_t macKey[4]; - s20.crypt12(ZERO_KEY,macKey,sizeof(macKey)); + Salsa20 s20(mangledKey, data + ZT_PACKET_IDX_IV); + s20.crypt12(ZERO_KEY, macKey, sizeof(macKey)); - uint8_t *const payload = data + ZT_PACKET_IDX_VERB; - const unsigned int payloadLen = size() - ZT_PACKET_IDX_VERB; - if (encryptPayload) { - s20.crypt12(payload,payload,payloadLen); - } - uint64_t mac[2]; + uint8_t* const payload = data + ZT_PACKET_IDX_VERB; + const unsigned int payloadLen = size() - ZT_PACKET_IDX_VERB; + if (encryptPayload) { + s20.crypt12(payload, payload, payloadLen); + } - Poly1305::compute(mac,payload,payloadLen,macKey); - memcpy(data + ZT_PACKET_IDX_MAC,mac,8); - } - } + Poly1305::compute(mac, payload, payloadLen, macKey); + memcpy(data + ZT_PACKET_IDX_MAC, mac, 8); + } + } + + /* NOTE: this is currently only ever used with NONE encryption for HELLO packets. */ + if (extendedArmor) { + ECC::Pair ephemeralKeyPair = ECC::generate(); + uint8_t ephemeralSymmetric[32]; + ECC::agree(ephemeralKeyPair, identity.publicKey(), ephemeralSymmetric, 32); + + AES cipher(ephemeralSymmetric); + AES::CTR aesCtr(cipher); + aesCtr.init(data, 0, data + ZT_PACKET_IDX_EXTENDED_ARMOR_START); + aesCtr.crypt(data + ZT_PACKET_IDX_EXTENDED_ARMOR_START, size() - ZT_PACKET_IDX_EXTENDED_ARMOR_START); + aesCtr.finish(); + + this->append(ephemeralKeyPair.pub.data, ZT_ECC_EPHEMERAL_PUBLIC_KEY_LEN); + } } -bool Packet::dearmor(const void *key,const AES aesKeys[2]) +bool Packet::dearmor(const void* key, const AES aesKeys[2], const Identity& identity) { - uint8_t *const data = reinterpret_cast(unsafeData()); - const unsigned int payloadLen = size() - ZT_PACKET_IDX_VERB; - unsigned char *const payload = data + ZT_PACKET_IDX_VERB; - const unsigned int cs = cipher(); + uint8_t* const data = reinterpret_cast(unsafeData()); + const unsigned int cs = cipher(); + + if (extendedArmor() && (cs == ZT_PROTO_CIPHER_SUITE__C25519_POLY1305_NONE)) { + if (size() < (ZT_PACKET_IDX_VERB + 1 + ZT_ECC_EPHEMERAL_PUBLIC_KEY_LEN)) { + return false; + } + uint8_t ephemeralSymmetric[32]; + ECC::Public ephemeralKey; + memcpy(ephemeralKey.data, data + (size() - ZT_ECC_EPHEMERAL_PUBLIC_KEY_LEN), ZT_ECC_EPHEMERAL_PUBLIC_KEY_LEN); + ECC::agree(identity.privateKeyPair(), ephemeralKey, ephemeralSymmetric, 32); + + AES cipher(ephemeralSymmetric); + AES::CTR aesCtr(cipher); + aesCtr.init(data, 0, data + ZT_PACKET_IDX_EXTENDED_ARMOR_START); + aesCtr.crypt(data + ZT_PACKET_IDX_EXTENDED_ARMOR_START, (size() - ZT_PACKET_IDX_EXTENDED_ARMOR_START) - ZT_ECC_EPHEMERAL_PUBLIC_KEY_LEN); + aesCtr.finish(); + + this->setSize(size() - ZT_ECC_EPHEMERAL_PUBLIC_KEY_LEN); + + /* Note: both the MAC and the data were encrypted with the ephemeral key. We don't need + * a separate MAC for the ephemeral encryption because the MAC check below is obviously + * going to fail if the ephemeral key was incorrect. */ + } + + const unsigned int payloadLen = size() - ZT_PACKET_IDX_VERB; + unsigned char* const payload = data + ZT_PACKET_IDX_VERB; + + if (cs == ZT_PROTO_CIPHER_SUITE__AES_GMAC_SIV) { + if (aesKeys) { + uint64_t tag[2]; - if (cs == ZT_PROTO_CIPHER_SUITE__AES_GMAC_SIV) { - if (aesKeys) { - uint64_t tag[2]; #ifdef ZT_NO_UNALIGNED_ACCESS - Utils::copy<8>(tag, data); - Utils::copy<8>(tag + 1, data + ZT_PACKET_IDX_MAC); + Utils::copy<8>(tag, data); + Utils::copy<8>(tag + 1, data + ZT_PACKET_IDX_MAC); #else - tag[0] = *reinterpret_cast(data + ZT_PACKET_IDX_IV); - tag[1] = *reinterpret_cast(data + ZT_PACKET_IDX_MAC); + tag[0] = *reinterpret_cast(data + ZT_PACKET_IDX_IV); + tag[1] = *reinterpret_cast(data + ZT_PACKET_IDX_MAC); #endif - AES::GMACSIVDecryptor dec(aesKeys[0],aesKeys[1]); - dec.init(tag, payload); - const uint8_t oldFlags = data[ZT_PACKET_IDX_FLAGS]; - data[ZT_PACKET_IDX_FLAGS] &= 0xf8; - dec.aad(data + ZT_PACKET_IDX_DEST,11); - data[ZT_PACKET_IDX_FLAGS] = oldFlags; - dec.update(payload, payloadLen); - return dec.finish(); - } - } else if ((cs == ZT_PROTO_CIPHER_SUITE__C25519_POLY1305_NONE)||(cs == ZT_PROTO_CIPHER_SUITE__C25519_POLY1305_SALSA2012)) { - uint8_t mangledKey[32]; - _salsa20MangleKey((const unsigned char *)key,mangledKey); - if (ZT_HAS_FAST_CRYPTO()) { - uint64_t keyStream[(ZT_PROTO_MAX_PACKET_LENGTH + 64 + 8) / 8]; - ZT_FAST_SINGLE_PASS_SALSA2012(keyStream,((cs == ZT_PROTO_CIPHER_SUITE__C25519_POLY1305_SALSA2012) ? (payloadLen + 64) : 64),(data + ZT_PACKET_IDX_IV),mangledKey); - uint64_t mac[2]; - Poly1305::compute(mac,payload,payloadLen,keyStream); + AES::GMACSIVDecryptor dec(aesKeys[0], aesKeys[1]); + dec.init(tag, payload); + const uint8_t oldFlags = data[ZT_PACKET_IDX_FLAGS]; + data[ZT_PACKET_IDX_FLAGS] &= 0xf8; + dec.aad(data + ZT_PACKET_IDX_DEST, 11); + data[ZT_PACKET_IDX_FLAGS] = oldFlags; + dec.update(payload, payloadLen); + return dec.finish(); + } + } + else if ((cs == ZT_PROTO_CIPHER_SUITE__C25519_POLY1305_NONE) || (cs == ZT_PROTO_CIPHER_SUITE__C25519_POLY1305_SALSA2012)) { + uint8_t mangledKey[32]; + _salsa20MangleKey((const unsigned char*)key, mangledKey); + if (ZT_HAS_FAST_CRYPTO()) { + uint64_t keyStream[(ZT_PROTO_MAX_PACKET_LENGTH + 64 + 8) / 8]; + ZT_FAST_SINGLE_PASS_SALSA2012(keyStream, ((cs == ZT_PROTO_CIPHER_SUITE__C25519_POLY1305_SALSA2012) ? (payloadLen + 64) : 64), (data + ZT_PACKET_IDX_IV), mangledKey); + uint64_t mac[2]; + Poly1305::compute(mac, payload, payloadLen, keyStream); #ifdef ZT_NO_TYPE_PUNNING - if (!Utils::secureEq(mac,data + ZT_PACKET_IDX_MAC,8)) { - return false; - } + if (! Utils::secureEq(mac, data + ZT_PACKET_IDX_MAC, 8)) { + return false; + } #else - if ((*reinterpret_cast(data + ZT_PACKET_IDX_MAC)) != mac[0]) { // also secure, constant time - return false; - } + if ((*reinterpret_cast(data + ZT_PACKET_IDX_MAC)) != mac[0]) { // also secure, constant time + return false; + } #endif - if (cs == ZT_PROTO_CIPHER_SUITE__C25519_POLY1305_SALSA2012) { - Salsa20::memxor(data + ZT_PACKET_IDX_VERB,reinterpret_cast(keyStream + 8),payloadLen); - } - } else { - Salsa20 s20(mangledKey,data + ZT_PACKET_IDX_IV); - uint64_t macKey[4]; - s20.crypt12(ZERO_KEY,macKey,sizeof(macKey)); - uint64_t mac[2]; - Poly1305::compute(mac,payload,payloadLen,macKey); + if (cs == ZT_PROTO_CIPHER_SUITE__C25519_POLY1305_SALSA2012) { + Salsa20::memxor(data + ZT_PACKET_IDX_VERB, reinterpret_cast(keyStream + 8), payloadLen); + } + } + else { + Salsa20 s20(mangledKey, data + ZT_PACKET_IDX_IV); + uint64_t macKey[4]; + s20.crypt12(ZERO_KEY, macKey, sizeof(macKey)); + uint64_t mac[2]; + Poly1305::compute(mac, payload, payloadLen, macKey); #ifdef ZT_NO_TYPE_PUNNING - if (!Utils::secureEq(mac,data + ZT_PACKET_IDX_MAC,8)) { - return false; - } + if (! Utils::secureEq(mac, data + ZT_PACKET_IDX_MAC, 8)) { + return false; + } #else - if ((*reinterpret_cast(data + ZT_PACKET_IDX_MAC)) != mac[0]) { // also secure, constant time - return false; - } + if ((*reinterpret_cast(data + ZT_PACKET_IDX_MAC)) != mac[0]) { // also secure, constant time + return false; + } #endif - if (cs == ZT_PROTO_CIPHER_SUITE__C25519_POLY1305_SALSA2012) { - s20.crypt12(payload,payload,payloadLen); - } - } - return true; - } + if (cs == ZT_PROTO_CIPHER_SUITE__C25519_POLY1305_SALSA2012) { + s20.crypt12(payload, payload, payloadLen); + } + } + return true; + } - return false; + return false; } -void Packet::cryptField(const void *key,unsigned int start,unsigned int len) +void Packet::cryptField(const void* key, unsigned int start, unsigned int len) { - uint8_t *const data = reinterpret_cast(unsafeData()); - uint8_t iv[8]; - for(int i=0;i<8;++i) { - iv[i] = data[i]; - } - iv[7] &= 0xf8; // mask off least significant 3 bits of packet ID / IV since this is unset when this function gets called - Salsa20 s20(key,iv); - s20.crypt12(data + start,data + start,len); + uint8_t* const data = reinterpret_cast(unsafeData()); + uint8_t iv[8]; + for (int i = 0; i < 8; ++i) { + iv[i] = data[i]; + } + iv[7] &= 0xf8; // mask off least significant 3 bits of packet ID / IV since this is unset when this function gets called + Salsa20 s20(key, iv); + s20.crypt12(data + start, data + start, len); } bool Packet::compress() { - char *const data = reinterpret_cast(unsafeData()); - char buf[ZT_PROTO_MAX_PACKET_LENGTH * 2]; + char* const data = reinterpret_cast(unsafeData()); + char buf[ZT_PROTO_MAX_PACKET_LENGTH * 2]; - if ((!compressed())&&(size() > (ZT_PACKET_IDX_PAYLOAD + 64))) { // don't bother compressing tiny packets - int pl = (int)(size() - ZT_PACKET_IDX_PAYLOAD); - int cl = LZ4_compress_fast(data + ZT_PACKET_IDX_PAYLOAD,buf,pl,ZT_PROTO_MAX_PACKET_LENGTH * 2,1); - if ((cl > 0)&&(cl < pl)) { - data[ZT_PACKET_IDX_VERB] |= (char)ZT_PROTO_VERB_FLAG_COMPRESSED; - setSize((unsigned int)cl + ZT_PACKET_IDX_PAYLOAD); - memcpy(data + ZT_PACKET_IDX_PAYLOAD,buf,cl); - return true; - } - } - data[ZT_PACKET_IDX_VERB] &= (char)(~ZT_PROTO_VERB_FLAG_COMPRESSED); + if ((! compressed()) && (size() > (ZT_PACKET_IDX_PAYLOAD + 64))) { // don't bother compressing tiny packets + int pl = (int)(size() - ZT_PACKET_IDX_PAYLOAD); + int cl = LZ4_compress_fast(data + ZT_PACKET_IDX_PAYLOAD, buf, pl, ZT_PROTO_MAX_PACKET_LENGTH * 2, 1); + if ((cl > 0) && (cl < pl)) { + data[ZT_PACKET_IDX_VERB] |= (char)ZT_PROTO_VERB_FLAG_COMPRESSED; + setSize((unsigned int)cl + ZT_PACKET_IDX_PAYLOAD); + memcpy(data + ZT_PACKET_IDX_PAYLOAD, buf, cl); + return true; + } + } + data[ZT_PACKET_IDX_VERB] &= (char)(~ZT_PROTO_VERB_FLAG_COMPRESSED); - return false; + return false; } bool Packet::uncompress() { - char *const data = reinterpret_cast(unsafeData()); - char buf[ZT_PROTO_MAX_PACKET_LENGTH]; + char* const data = reinterpret_cast(unsafeData()); + char buf[ZT_PROTO_MAX_PACKET_LENGTH]; - if ((compressed())&&(size() >= ZT_PROTO_MIN_PACKET_LENGTH)) { - if (size() > ZT_PACKET_IDX_PAYLOAD) { - unsigned int compLen = size() - ZT_PACKET_IDX_PAYLOAD; - int ucl = LZ4_decompress_safe((const char *)data + ZT_PACKET_IDX_PAYLOAD,buf,compLen,sizeof(buf)); - if ((ucl > 0)&&(ucl <= (int)(capacity() - ZT_PACKET_IDX_PAYLOAD))) { - setSize((unsigned int)ucl + ZT_PACKET_IDX_PAYLOAD); - memcpy(data + ZT_PACKET_IDX_PAYLOAD,buf,ucl); - } else { - return false; - } - } - data[ZT_PACKET_IDX_VERB] &= (char)(~ZT_PROTO_VERB_FLAG_COMPRESSED); - } + if ((compressed()) && (size() >= ZT_PROTO_MIN_PACKET_LENGTH)) { + if (size() > ZT_PACKET_IDX_PAYLOAD) { + unsigned int compLen = size() - ZT_PACKET_IDX_PAYLOAD; + int ucl = LZ4_decompress_safe((const char*)data + ZT_PACKET_IDX_PAYLOAD, buf, compLen, sizeof(buf)); + if ((ucl > 0) && (ucl <= (int)(capacity() - ZT_PACKET_IDX_PAYLOAD))) { + setSize((unsigned int)ucl + ZT_PACKET_IDX_PAYLOAD); + memcpy(data + ZT_PACKET_IDX_PAYLOAD, buf, ucl); + } + else { + return false; + } + } + data[ZT_PACKET_IDX_VERB] &= (char)(~ZT_PROTO_VERB_FLAG_COMPRESSED); + } - return true; + return true; } -} // namespace ZeroTier +} // namespace ZeroTier diff --git a/node/Packet.hpp b/node/Packet.hpp index f607d1f5..3059043f 100644 --- a/node/Packet.hpp +++ b/node/Packet.hpp @@ -14,21 +14,20 @@ #ifndef ZT_N_PACKET_HPP #define ZT_N_PACKET_HPP -#include -#include -#include - -#include -#include - -#include "Constants.hpp" - +#include "AES.hpp" #include "Address.hpp" +#include "Buffer.hpp" +#include "Constants.hpp" +#include "Identity.hpp" #include "Poly1305.hpp" #include "Salsa20.hpp" -#include "AES.hpp" #include "Utils.hpp" -#include "Buffer.hpp" + +#include +#include +#include +#include +#include /** * Protocol version -- incremented only for major changes @@ -59,10 +58,15 @@ * 10 - 1.4.0 ... 1.4.6 * 11 - 1.4.7 ... 1.4.8 * + Multipath capability and load balancing (beta) - * 12 - 1.4.8 ... CURRENT (1.4 series) + * 12 - 1.4.8 ... 1.16.0 * + AES-GMAC-SIV backported for faster peer-to-peer crypto + * 13 - 1.16.0 ... CURRENT + * + Old deprecated "encrypted" flag removed + * + Ephemeral keying with second encryption pass to hide HELLO etc. + * + Encrypted HELLO packets to anyone but roots + * + Remove deprecated parsing of LAN announcements */ -#define ZT_PROTO_VERSION 12 +#define ZT_PROTO_VERSION 13 /** * Minimum supported protocol version @@ -100,6 +104,18 @@ */ #define ZT_PROTO_CIPHER_SUITE__C25519_POLY1305_SALSA2012 1 +/** + * Cipher suite: NONE + * + * This differs from POLY1305/NONE in that *no* crypto is done, not even + * authentication. This is for trusted local LAN interconnects for internal + * SDN use within a data center. + * + * For this mode the MAC field becomes a trusted path ID and must match the + * configured ID of a trusted path or the packet is discarded. + */ +#define ZT_PROTO_CIPHER_SUITE__NO_CRYPTO_TRUSTED_PATH 2 + /** * AES-GMAC-SIV backported from 2.x */ @@ -116,23 +132,15 @@ #define ZT_KBKDF_LABEL_AES_GMAC_SIV_K1 '1' /** - * Cipher suite: NONE + * Header flag indicating ephemeral keying and second encryption pass. * - * This differs from POLY1305/NONE in that *no* crypto is done, not even - * authentication. This is for trusted local LAN interconnects for internal - * SDN use within a data center. + * If this is set, the packet will have an ephemeral key appended to it its payload + * will be encrypted with AES-CTR using this ephemeral key and the packet's header + * as an IV. * - * For this mode the MAC field becomes a trusted path ID and must match the - * configured ID of a trusted path or the packet is discarded. + * Note that this is a reuse of a flag that has long been deprecated and ignored. */ -#define ZT_PROTO_CIPHER_SUITE__NO_CRYPTO_TRUSTED_PATH 2 - -/** - * DEPRECATED payload encrypted flag, may be re-used in the future. - * - * This has been replaced by the three-bit cipher suite selection field. - */ -#define ZT_PROTO_FLAG_ENCRYPTED 0x80 +#define ZT_PROTO_FLAG_EXTENDED_ARMOR 0x80 /** * Header flag indicating that a packet is fragmented @@ -147,66 +155,8 @@ */ #define ZT_PROTO_VERB_FLAG_COMPRESSED 0x80 -/** - * Rounds used for Salsa20 encryption in ZT - * - * Discussion: - * - * DJB (Salsa20's designer) designed Salsa20 with a significant margin of 20 - * rounds, but has said repeatedly that 12 is likely sufficient. So far (as of - * July 2015) there are no published attacks against 12 rounds, let alone 20. - * - * In cryptography, a "break" means something different from what it means in - * common discussion. If a cipher is 256 bits strong and someone finds a way - * to reduce key search to 254 bits, this constitutes a "break" in the academic - * literature. 254 bits is still far beyond what can be leveraged to accomplish - * a "break" as most people would understand it -- the actual decryption and - * reading of traffic. - * - * Nevertheless, "attacks only get better" as cryptographers like to say. As - * a result, they recommend not using anything that's shown any weakness even - * if that weakness is so far only meaningful to academics. It may be a sign - * of a deeper problem. - * - * So why choose a lower round count? - * - * Turns out the speed difference is nontrivial. On a Macbook Pro (Core i3) 20 - * rounds of SSE-optimized Salsa20 achieves ~508mb/sec/core, while 12 rounds - * hits ~832mb/sec/core. ZeroTier is designed for multiple objectives: - * security, simplicity, and performance. In this case a deference was made - * for performance. - * - * Meta discussion: - * - * The cipher is not the thing you should be paranoid about. - * - * I'll qualify that. If the cipher is known to be weak, like RC4, or has a - * key size that is too small, like DES, then yes you should worry about - * the cipher. - * - * But if the cipher is strong and your adversary is anyone other than the - * intelligence apparatus of a major superpower, you are fine in that - * department. - * - * Go ahead. Search for the last ten vulnerabilities discovered in SSL. Not - * a single one involved the breaking of a cipher. Now broaden your search. - * Look for issues with SSH, IPSec, etc. The only cipher-related issues you - * will find might involve the use of RC4 or MD5, algorithms with known - * issues or small key/digest sizes. But even weak ciphers are difficult to - * exploit in the real world -- you usually need a lot of data and a lot of - * compute time. No, virtually EVERY security vulnerability you will find - * involves a problem with the IMPLEMENTATION not with the cipher. - * - * A flaw in ZeroTier's protocol or code is incredibly, unbelievably - * more likely than a flaw in Salsa20 or any other cipher or cryptographic - * primitive it uses. We're talking odds of dying in a car wreck vs. odds of - * being personally impacted on the head by a meteorite. Nobody without a - * billion dollar budget is going to break into your network by actually - * cracking Salsa20/12 (or even /8) in the field. - * - * So stop worrying about the cipher unless you are, say, the Kremlin and your - * adversary is the NSA and the GCHQ. In that case... well that's above my - * pay grade. I'll just say defense in depth. +/* + * Rounds used for deprecated Salsa20 encryption */ #define ZT_PROTO_SALSA20_ROUNDS 12 @@ -221,14 +171,19 @@ #define ZT_PUSH_DIRECT_PATHS_FLAG_CLUSTER_REDIRECT 0x02 // Field indexes in packet header -#define ZT_PACKET_IDX_IV 0 -#define ZT_PACKET_IDX_DEST 8 -#define ZT_PACKET_IDX_SOURCE 13 -#define ZT_PACKET_IDX_FLAGS 18 -#define ZT_PACKET_IDX_MAC 19 -#define ZT_PACKET_IDX_VERB 27 +#define ZT_PACKET_IDX_IV 0 +#define ZT_PACKET_IDX_DEST 8 +#define ZT_PACKET_IDX_SOURCE 13 +#define ZT_PACKET_IDX_FLAGS 18 +#define ZT_PACKET_IDX_MAC 19 +#define ZT_PACKET_IDX_VERB 27 #define ZT_PACKET_IDX_PAYLOAD 28 +/** + * Index where extended armor encryption starts (right after flags, before MAC) + */ +#define ZT_PACKET_IDX_EXTENDED_ARMOR_START ZT_PACKET_IDX_MAC + /** * Packet buffer size (can be changed) */ @@ -240,12 +195,12 @@ #define ZT_PROTO_MIN_PACKET_LENGTH ZT_PACKET_IDX_PAYLOAD // Indexes of fields in fragment header -#define ZT_PACKET_FRAGMENT_IDX_PACKET_ID 0 -#define ZT_PACKET_FRAGMENT_IDX_DEST 8 +#define ZT_PACKET_FRAGMENT_IDX_PACKET_ID 0 +#define ZT_PACKET_FRAGMENT_IDX_DEST 8 #define ZT_PACKET_FRAGMENT_IDX_FRAGMENT_INDICATOR 13 -#define ZT_PACKET_FRAGMENT_IDX_FRAGMENT_NO 14 -#define ZT_PACKET_FRAGMENT_IDX_HOPS 15 -#define ZT_PACKET_FRAGMENT_IDX_PAYLOAD 16 +#define ZT_PACKET_FRAGMENT_IDX_FRAGMENT_NO 14 +#define ZT_PACKET_FRAGMENT_IDX_HOPS 15 +#define ZT_PACKET_FRAGMENT_IDX_PAYLOAD 16 /** * Magic number found at ZT_PACKET_FRAGMENT_IDX_FRAGMENT_INDICATOR @@ -264,89 +219,89 @@ // See their respective handler functions. #define ZT_PROTO_VERB_HELLO_IDX_PROTOCOL_VERSION (ZT_PACKET_IDX_PAYLOAD) -#define ZT_PROTO_VERB_HELLO_IDX_MAJOR_VERSION (ZT_PROTO_VERB_HELLO_IDX_PROTOCOL_VERSION + 1) -#define ZT_PROTO_VERB_HELLO_IDX_MINOR_VERSION (ZT_PROTO_VERB_HELLO_IDX_MAJOR_VERSION + 1) -#define ZT_PROTO_VERB_HELLO_IDX_REVISION (ZT_PROTO_VERB_HELLO_IDX_MINOR_VERSION + 1) -#define ZT_PROTO_VERB_HELLO_IDX_TIMESTAMP (ZT_PROTO_VERB_HELLO_IDX_REVISION + 2) -#define ZT_PROTO_VERB_HELLO_IDX_IDENTITY (ZT_PROTO_VERB_HELLO_IDX_TIMESTAMP + 8) +#define ZT_PROTO_VERB_HELLO_IDX_MAJOR_VERSION (ZT_PROTO_VERB_HELLO_IDX_PROTOCOL_VERSION + 1) +#define ZT_PROTO_VERB_HELLO_IDX_MINOR_VERSION (ZT_PROTO_VERB_HELLO_IDX_MAJOR_VERSION + 1) +#define ZT_PROTO_VERB_HELLO_IDX_REVISION (ZT_PROTO_VERB_HELLO_IDX_MINOR_VERSION + 1) +#define ZT_PROTO_VERB_HELLO_IDX_TIMESTAMP (ZT_PROTO_VERB_HELLO_IDX_REVISION + 2) +#define ZT_PROTO_VERB_HELLO_IDX_IDENTITY (ZT_PROTO_VERB_HELLO_IDX_TIMESTAMP + 8) -#define ZT_PROTO_VERB_ERROR_IDX_IN_RE_VERB (ZT_PACKET_IDX_PAYLOAD) +#define ZT_PROTO_VERB_ERROR_IDX_IN_RE_VERB (ZT_PACKET_IDX_PAYLOAD) #define ZT_PROTO_VERB_ERROR_IDX_IN_RE_PACKET_ID (ZT_PROTO_VERB_ERROR_IDX_IN_RE_VERB + 1) -#define ZT_PROTO_VERB_ERROR_IDX_ERROR_CODE (ZT_PROTO_VERB_ERROR_IDX_IN_RE_PACKET_ID + 8) -#define ZT_PROTO_VERB_ERROR_IDX_PAYLOAD (ZT_PROTO_VERB_ERROR_IDX_ERROR_CODE + 1) +#define ZT_PROTO_VERB_ERROR_IDX_ERROR_CODE (ZT_PROTO_VERB_ERROR_IDX_IN_RE_PACKET_ID + 8) +#define ZT_PROTO_VERB_ERROR_IDX_PAYLOAD (ZT_PROTO_VERB_ERROR_IDX_ERROR_CODE + 1) -#define ZT_PROTO_VERB_OK_IDX_IN_RE_VERB (ZT_PACKET_IDX_PAYLOAD) +#define ZT_PROTO_VERB_OK_IDX_IN_RE_VERB (ZT_PACKET_IDX_PAYLOAD) #define ZT_PROTO_VERB_OK_IDX_IN_RE_PACKET_ID (ZT_PROTO_VERB_OK_IDX_IN_RE_VERB + 1) -#define ZT_PROTO_VERB_OK_IDX_PAYLOAD (ZT_PROTO_VERB_OK_IDX_IN_RE_PACKET_ID + 8) +#define ZT_PROTO_VERB_OK_IDX_PAYLOAD (ZT_PROTO_VERB_OK_IDX_IN_RE_PACKET_ID + 8) #define ZT_PROTO_VERB_WHOIS_IDX_ZTADDRESS (ZT_PACKET_IDX_PAYLOAD) -#define ZT_PROTO_VERB_RENDEZVOUS_IDX_FLAGS (ZT_PACKET_IDX_PAYLOAD) +#define ZT_PROTO_VERB_RENDEZVOUS_IDX_FLAGS (ZT_PACKET_IDX_PAYLOAD) #define ZT_PROTO_VERB_RENDEZVOUS_IDX_ZTADDRESS (ZT_PROTO_VERB_RENDEZVOUS_IDX_FLAGS + 1) -#define ZT_PROTO_VERB_RENDEZVOUS_IDX_PORT (ZT_PROTO_VERB_RENDEZVOUS_IDX_ZTADDRESS + 5) -#define ZT_PROTO_VERB_RENDEZVOUS_IDX_ADDRLEN (ZT_PROTO_VERB_RENDEZVOUS_IDX_PORT + 2) -#define ZT_PROTO_VERB_RENDEZVOUS_IDX_ADDRESS (ZT_PROTO_VERB_RENDEZVOUS_IDX_ADDRLEN + 1) +#define ZT_PROTO_VERB_RENDEZVOUS_IDX_PORT (ZT_PROTO_VERB_RENDEZVOUS_IDX_ZTADDRESS + 5) +#define ZT_PROTO_VERB_RENDEZVOUS_IDX_ADDRLEN (ZT_PROTO_VERB_RENDEZVOUS_IDX_PORT + 2) +#define ZT_PROTO_VERB_RENDEZVOUS_IDX_ADDRESS (ZT_PROTO_VERB_RENDEZVOUS_IDX_ADDRLEN + 1) #define ZT_PROTO_VERB_FRAME_IDX_NETWORK_ID (ZT_PACKET_IDX_PAYLOAD) -#define ZT_PROTO_VERB_FRAME_IDX_ETHERTYPE (ZT_PROTO_VERB_FRAME_IDX_NETWORK_ID + 8) -#define ZT_PROTO_VERB_FRAME_IDX_PAYLOAD (ZT_PROTO_VERB_FRAME_IDX_ETHERTYPE + 2) +#define ZT_PROTO_VERB_FRAME_IDX_ETHERTYPE (ZT_PROTO_VERB_FRAME_IDX_NETWORK_ID + 8) +#define ZT_PROTO_VERB_FRAME_IDX_PAYLOAD (ZT_PROTO_VERB_FRAME_IDX_ETHERTYPE + 2) #define ZT_PROTO_VERB_EXT_FRAME_IDX_NETWORK_ID (ZT_PACKET_IDX_PAYLOAD) #define ZT_PROTO_VERB_EXT_FRAME_LEN_NETWORK_ID 8 -#define ZT_PROTO_VERB_EXT_FRAME_IDX_FLAGS (ZT_PROTO_VERB_EXT_FRAME_IDX_NETWORK_ID + ZT_PROTO_VERB_EXT_FRAME_LEN_NETWORK_ID) -#define ZT_PROTO_VERB_EXT_FRAME_LEN_FLAGS 1 -#define ZT_PROTO_VERB_EXT_FRAME_IDX_COM (ZT_PROTO_VERB_EXT_FRAME_IDX_FLAGS + ZT_PROTO_VERB_EXT_FRAME_LEN_FLAGS) -#define ZT_PROTO_VERB_EXT_FRAME_IDX_TO (ZT_PROTO_VERB_EXT_FRAME_IDX_FLAGS + ZT_PROTO_VERB_EXT_FRAME_LEN_FLAGS) -#define ZT_PROTO_VERB_EXT_FRAME_LEN_TO 6 -#define ZT_PROTO_VERB_EXT_FRAME_IDX_FROM (ZT_PROTO_VERB_EXT_FRAME_IDX_TO + ZT_PROTO_VERB_EXT_FRAME_LEN_TO) -#define ZT_PROTO_VERB_EXT_FRAME_LEN_FROM 6 -#define ZT_PROTO_VERB_EXT_FRAME_IDX_ETHERTYPE (ZT_PROTO_VERB_EXT_FRAME_IDX_FROM + ZT_PROTO_VERB_EXT_FRAME_LEN_FROM) -#define ZT_PROTO_VERB_EXT_FRAME_LEN_ETHERTYPE 2 -#define ZT_PROTO_VERB_EXT_FRAME_IDX_PAYLOAD (ZT_PROTO_VERB_EXT_FRAME_IDX_ETHERTYPE + ZT_PROTO_VERB_EXT_FRAME_LEN_ETHERTYPE) +#define ZT_PROTO_VERB_EXT_FRAME_IDX_FLAGS (ZT_PROTO_VERB_EXT_FRAME_IDX_NETWORK_ID + ZT_PROTO_VERB_EXT_FRAME_LEN_NETWORK_ID) +#define ZT_PROTO_VERB_EXT_FRAME_LEN_FLAGS 1 +#define ZT_PROTO_VERB_EXT_FRAME_IDX_COM (ZT_PROTO_VERB_EXT_FRAME_IDX_FLAGS + ZT_PROTO_VERB_EXT_FRAME_LEN_FLAGS) +#define ZT_PROTO_VERB_EXT_FRAME_IDX_TO (ZT_PROTO_VERB_EXT_FRAME_IDX_FLAGS + ZT_PROTO_VERB_EXT_FRAME_LEN_FLAGS) +#define ZT_PROTO_VERB_EXT_FRAME_LEN_TO 6 +#define ZT_PROTO_VERB_EXT_FRAME_IDX_FROM (ZT_PROTO_VERB_EXT_FRAME_IDX_TO + ZT_PROTO_VERB_EXT_FRAME_LEN_TO) +#define ZT_PROTO_VERB_EXT_FRAME_LEN_FROM 6 +#define ZT_PROTO_VERB_EXT_FRAME_IDX_ETHERTYPE (ZT_PROTO_VERB_EXT_FRAME_IDX_FROM + ZT_PROTO_VERB_EXT_FRAME_LEN_FROM) +#define ZT_PROTO_VERB_EXT_FRAME_LEN_ETHERTYPE 2 +#define ZT_PROTO_VERB_EXT_FRAME_IDX_PAYLOAD (ZT_PROTO_VERB_EXT_FRAME_IDX_ETHERTYPE + ZT_PROTO_VERB_EXT_FRAME_LEN_ETHERTYPE) #define ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST_IDX_NETWORK_ID (ZT_PACKET_IDX_PAYLOAD) -#define ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST_IDX_DICT_LEN (ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST_IDX_NETWORK_ID + 8) -#define ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST_IDX_DICT (ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST_IDX_DICT_LEN + 2) +#define ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST_IDX_DICT_LEN (ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST_IDX_NETWORK_ID + 8) +#define ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST_IDX_DICT (ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST_IDX_DICT_LEN + 2) -#define ZT_PROTO_VERB_MULTICAST_GATHER_IDX_NETWORK_ID (ZT_PACKET_IDX_PAYLOAD) -#define ZT_PROTO_VERB_MULTICAST_GATHER_IDX_FLAGS (ZT_PROTO_VERB_MULTICAST_GATHER_IDX_NETWORK_ID + 8) -#define ZT_PROTO_VERB_MULTICAST_GATHER_IDX_MAC (ZT_PROTO_VERB_MULTICAST_GATHER_IDX_FLAGS + 1) -#define ZT_PROTO_VERB_MULTICAST_GATHER_IDX_ADI (ZT_PROTO_VERB_MULTICAST_GATHER_IDX_MAC + 6) +#define ZT_PROTO_VERB_MULTICAST_GATHER_IDX_NETWORK_ID (ZT_PACKET_IDX_PAYLOAD) +#define ZT_PROTO_VERB_MULTICAST_GATHER_IDX_FLAGS (ZT_PROTO_VERB_MULTICAST_GATHER_IDX_NETWORK_ID + 8) +#define ZT_PROTO_VERB_MULTICAST_GATHER_IDX_MAC (ZT_PROTO_VERB_MULTICAST_GATHER_IDX_FLAGS + 1) +#define ZT_PROTO_VERB_MULTICAST_GATHER_IDX_ADI (ZT_PROTO_VERB_MULTICAST_GATHER_IDX_MAC + 6) #define ZT_PROTO_VERB_MULTICAST_GATHER_IDX_GATHER_LIMIT (ZT_PROTO_VERB_MULTICAST_GATHER_IDX_ADI + 4) -#define ZT_PROTO_VERB_MULTICAST_GATHER_IDX_COM (ZT_PROTO_VERB_MULTICAST_GATHER_IDX_GATHER_LIMIT + 4) +#define ZT_PROTO_VERB_MULTICAST_GATHER_IDX_COM (ZT_PROTO_VERB_MULTICAST_GATHER_IDX_GATHER_LIMIT + 4) // Note: COM, GATHER_LIMIT, and SOURCE_MAC are optional, and so are specified without size -#define ZT_PROTO_VERB_MULTICAST_FRAME_IDX_NETWORK_ID (ZT_PACKET_IDX_PAYLOAD) -#define ZT_PROTO_VERB_MULTICAST_FRAME_IDX_FLAGS (ZT_PROTO_VERB_MULTICAST_FRAME_IDX_NETWORK_ID + 8) -#define ZT_PROTO_VERB_MULTICAST_FRAME_IDX_COM (ZT_PROTO_VERB_MULTICAST_FRAME_IDX_FLAGS + 1) +#define ZT_PROTO_VERB_MULTICAST_FRAME_IDX_NETWORK_ID (ZT_PACKET_IDX_PAYLOAD) +#define ZT_PROTO_VERB_MULTICAST_FRAME_IDX_FLAGS (ZT_PROTO_VERB_MULTICAST_FRAME_IDX_NETWORK_ID + 8) +#define ZT_PROTO_VERB_MULTICAST_FRAME_IDX_COM (ZT_PROTO_VERB_MULTICAST_FRAME_IDX_FLAGS + 1) #define ZT_PROTO_VERB_MULTICAST_FRAME_IDX_GATHER_LIMIT (ZT_PROTO_VERB_MULTICAST_FRAME_IDX_FLAGS + 1) -#define ZT_PROTO_VERB_MULTICAST_FRAME_IDX_SOURCE_MAC (ZT_PROTO_VERB_MULTICAST_FRAME_IDX_FLAGS + 1) -#define ZT_PROTO_VERB_MULTICAST_FRAME_IDX_DEST_MAC (ZT_PROTO_VERB_MULTICAST_FRAME_IDX_FLAGS + 1) -#define ZT_PROTO_VERB_MULTICAST_FRAME_IDX_DEST_ADI (ZT_PROTO_VERB_MULTICAST_FRAME_IDX_DEST_MAC + 6) -#define ZT_PROTO_VERB_MULTICAST_FRAME_IDX_ETHERTYPE (ZT_PROTO_VERB_MULTICAST_FRAME_IDX_DEST_ADI + 4) -#define ZT_PROTO_VERB_MULTICAST_FRAME_IDX_FRAME (ZT_PROTO_VERB_MULTICAST_FRAME_IDX_ETHERTYPE + 2) +#define ZT_PROTO_VERB_MULTICAST_FRAME_IDX_SOURCE_MAC (ZT_PROTO_VERB_MULTICAST_FRAME_IDX_FLAGS + 1) +#define ZT_PROTO_VERB_MULTICAST_FRAME_IDX_DEST_MAC (ZT_PROTO_VERB_MULTICAST_FRAME_IDX_FLAGS + 1) +#define ZT_PROTO_VERB_MULTICAST_FRAME_IDX_DEST_ADI (ZT_PROTO_VERB_MULTICAST_FRAME_IDX_DEST_MAC + 6) +#define ZT_PROTO_VERB_MULTICAST_FRAME_IDX_ETHERTYPE (ZT_PROTO_VERB_MULTICAST_FRAME_IDX_DEST_ADI + 4) +#define ZT_PROTO_VERB_MULTICAST_FRAME_IDX_FRAME (ZT_PROTO_VERB_MULTICAST_FRAME_IDX_ETHERTYPE + 2) -#define ZT_PROTO_VERB_HELLO__OK__IDX_TIMESTAMP (ZT_PROTO_VERB_OK_IDX_PAYLOAD) +#define ZT_PROTO_VERB_HELLO__OK__IDX_TIMESTAMP (ZT_PROTO_VERB_OK_IDX_PAYLOAD) #define ZT_PROTO_VERB_HELLO__OK__IDX_PROTOCOL_VERSION (ZT_PROTO_VERB_HELLO__OK__IDX_TIMESTAMP + 8) -#define ZT_PROTO_VERB_HELLO__OK__IDX_MAJOR_VERSION (ZT_PROTO_VERB_HELLO__OK__IDX_PROTOCOL_VERSION + 1) -#define ZT_PROTO_VERB_HELLO__OK__IDX_MINOR_VERSION (ZT_PROTO_VERB_HELLO__OK__IDX_MAJOR_VERSION + 1) -#define ZT_PROTO_VERB_HELLO__OK__IDX_REVISION (ZT_PROTO_VERB_HELLO__OK__IDX_MINOR_VERSION + 1) +#define ZT_PROTO_VERB_HELLO__OK__IDX_MAJOR_VERSION (ZT_PROTO_VERB_HELLO__OK__IDX_PROTOCOL_VERSION + 1) +#define ZT_PROTO_VERB_HELLO__OK__IDX_MINOR_VERSION (ZT_PROTO_VERB_HELLO__OK__IDX_MAJOR_VERSION + 1) +#define ZT_PROTO_VERB_HELLO__OK__IDX_REVISION (ZT_PROTO_VERB_HELLO__OK__IDX_MINOR_VERSION + 1) #define ZT_PROTO_VERB_WHOIS__OK__IDX_IDENTITY (ZT_PROTO_VERB_OK_IDX_PAYLOAD) #define ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST__OK__IDX_NETWORK_ID (ZT_PROTO_VERB_OK_IDX_PAYLOAD) -#define ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST__OK__IDX_DICT_LEN (ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST__OK__IDX_NETWORK_ID + 8) -#define ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST__OK__IDX_DICT (ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST__OK__IDX_DICT_LEN + 2) +#define ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST__OK__IDX_DICT_LEN (ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST__OK__IDX_NETWORK_ID + 8) +#define ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST__OK__IDX_DICT (ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST__OK__IDX_DICT_LEN + 2) -#define ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_NETWORK_ID (ZT_PROTO_VERB_OK_IDX_PAYLOAD) -#define ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_MAC (ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_NETWORK_ID + 8) -#define ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_ADI (ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_MAC + 6) +#define ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_NETWORK_ID (ZT_PROTO_VERB_OK_IDX_PAYLOAD) +#define ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_MAC (ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_NETWORK_ID + 8) +#define ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_ADI (ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_MAC + 6) #define ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_GATHER_RESULTS (ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_ADI + 4) -#define ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_NETWORK_ID (ZT_PROTO_VERB_OK_IDX_PAYLOAD) -#define ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_MAC (ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_NETWORK_ID + 8) -#define ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_ADI (ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_MAC + 6) -#define ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_FLAGS (ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_ADI + 4) +#define ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_NETWORK_ID (ZT_PROTO_VERB_OK_IDX_PAYLOAD) +#define ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_MAC (ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_NETWORK_ID + 8) +#define ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_ADI (ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_MAC + 6) +#define ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_FLAGS (ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_ADI + 4) #define ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_COM_AND_GATHER_RESULTS (ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_FLAGS + 1) // --------------------------------------------------------------------------- @@ -388,1049 +343,1123 @@ namespace ZeroTier { * For unencrypted packets, MAC is computed on plaintext. Only HELLO is ever * sent in the clear, as it's the "here is my public key" message. */ -class Packet : public Buffer -{ -public: - /** - * A packet fragment - * - * Fragments are sent if a packet is larger than UDP MTU. The first fragment - * is sent with its normal header with the fragmented flag set. Remaining - * fragments are sent this way. - * - * The fragmented bit indicates that there is at least one fragment. Fragments - * themselves contain the total, so the receiver must "learn" this from the - * first fragment it receives. - * - * Fragments are sent with the following format: - * <[8] packet ID of packet whose fragment this belongs to> - * <[5] destination ZT address> - * <[1] 0xff, a reserved address, signals that this isn't a normal packet> - * <[1] total fragments (most significant 4 bits), fragment no (LS 4 bits)> - * <[1] ZT hop count (top 5 bits unused and must be zero)> - * <[...] fragment data> - * - * The protocol supports a maximum of 16 fragments. If a fragment is received - * before its main packet header, it should be cached for a brief period of - * time to see if its parent arrives. Loss of any fragment constitutes packet - * loss; there is no retransmission mechanism. The receiver must wait for full - * receipt to authenticate and decrypt; there is no per-fragment MAC. (But if - * fragments are corrupt, the MAC will fail for the whole assembled packet.) - */ - class Fragment : public Buffer - { - public: - Fragment() : - Buffer() - { - } - - template - Fragment(const Buffer &b) : - Buffer(b) - { - } - - Fragment(const void *data,unsigned int len) : - Buffer(data,len) - { - } - - /** - * Initialize from a packet - * - * @param p Original assembled packet - * @param fragStart Start of fragment (raw index in packet data) - * @param fragLen Length of fragment in bytes - * @param fragNo Which fragment (>= 1, since 0 is Packet with end chopped off) - * @param fragTotal Total number of fragments (including 0) - */ - Fragment(const Packet &p,unsigned int fragStart,unsigned int fragLen,unsigned int fragNo,unsigned int fragTotal) - { - init(p,fragStart,fragLen,fragNo,fragTotal); - } - - /** - * Initialize from a packet - * - * @param p Original assembled packet - * @param fragStart Start of fragment (raw index in packet data) - * @param fragLen Length of fragment in bytes - * @param fragNo Which fragment (>= 1, since 0 is Packet with end chopped off) - * @param fragTotal Total number of fragments (including 0) - */ - inline void init(const Packet &p,unsigned int fragStart,unsigned int fragLen,unsigned int fragNo,unsigned int fragTotal) - { - if ((fragStart + fragLen) > p.size()) { - throw ZT_EXCEPTION_OUT_OF_BOUNDS; - } - setSize(fragLen + ZT_PROTO_MIN_FRAGMENT_LENGTH); - - // NOTE: this copies both the IV/packet ID and the destination address. - memcpy(field(ZT_PACKET_FRAGMENT_IDX_PACKET_ID,13),p.field(ZT_PACKET_IDX_IV,13),13); - - (*this)[ZT_PACKET_FRAGMENT_IDX_FRAGMENT_INDICATOR] = ZT_PACKET_FRAGMENT_INDICATOR; - (*this)[ZT_PACKET_FRAGMENT_IDX_FRAGMENT_NO] = (char)(((fragTotal & 0xf) << 4) | (fragNo & 0xf)); - (*this)[ZT_PACKET_FRAGMENT_IDX_HOPS] = 0; - - memcpy(field(ZT_PACKET_FRAGMENT_IDX_PAYLOAD,fragLen),p.field(fragStart,fragLen),fragLen); - } - - /** - * Get this fragment's destination - * - * @return Destination ZT address - */ - inline Address destination() const { return Address(field(ZT_PACKET_FRAGMENT_IDX_DEST,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); } - - /** - * @return True if fragment is of a valid length - */ - inline bool lengthValid() const { return (size() >= ZT_PACKET_FRAGMENT_IDX_PAYLOAD); } - - /** - * @return ID of packet this is a fragment of - */ - inline uint64_t packetId() const { return at(ZT_PACKET_FRAGMENT_IDX_PACKET_ID); } - - /** - * @return Total number of fragments in packet - */ - inline unsigned int totalFragments() const { return (((unsigned int)((*this)[ZT_PACKET_FRAGMENT_IDX_FRAGMENT_NO]) >> 4) & 0xf); } - - /** - * @return Fragment number of this fragment - */ - inline unsigned int fragmentNumber() const { return ((unsigned int)((*this)[ZT_PACKET_FRAGMENT_IDX_FRAGMENT_NO]) & 0xf); } - - /** - * @return Fragment ZT hop count - */ - inline unsigned int hops() const { return (unsigned int)((*this)[ZT_PACKET_FRAGMENT_IDX_HOPS]); } - - /** - * Increment this packet's hop count - */ - inline void incrementHops() - { - (*this)[ZT_PACKET_FRAGMENT_IDX_HOPS] = (((*this)[ZT_PACKET_FRAGMENT_IDX_HOPS]) + 1) & ZT_PROTO_MAX_HOPS; - } - - /** - * @return Length of payload in bytes - */ - inline unsigned int payloadLength() const { return ((size() > ZT_PACKET_FRAGMENT_IDX_PAYLOAD) ? (size() - ZT_PACKET_FRAGMENT_IDX_PAYLOAD) : 0); } - - /** - * @return Raw packet payload - */ - inline const unsigned char *payload() const - { - return field(ZT_PACKET_FRAGMENT_IDX_PAYLOAD,size() - ZT_PACKET_FRAGMENT_IDX_PAYLOAD); - } - }; - - /** - * ZeroTier protocol verbs - */ - enum Verb /* Max value: 32 (5 bits) */ - { - /** - * No operation (ignored, no reply) - */ - VERB_NOP = 0x00, - - /** - * Announcement of a node's existence and vitals: - * <[1] protocol version> - * <[1] software major version> - * <[1] software minor version> - * <[2] software revision> - * <[8] timestamp for determining latency> - * <[...] binary serialized identity (see Identity)> - * <[...] physical destination address of packet> - * <[8] 64-bit world ID of current planet> - * <[8] 64-bit timestamp of current planet> - * [... remainder if packet is encrypted using cryptField() ...] - * <[2] 16-bit number of moons> - * [<[1] 8-bit type ID of moon>] - * [<[8] 64-bit world ID of moon>] - * [<[8] 64-bit timestamp of moon>] - * [... additional moon type/ID/timestamp tuples ...] - * - * HELLO is sent in the clear as it is how peers share their identity - * public keys. A few additional fields are sent in the clear too, but - * these are things that are public info or are easy to determine. As - * of 1.2.0 we have added a few more fields, but since these could have - * the potential to be sensitive we introduced the encryption of the - * remainder of the packet. See cryptField(). Packet MAC is still - * performed of course, so authentication occurs as normal. - * - * Destination address is the actual wire address to which the packet - * was sent. See InetAddress::serialize() for format. - * - * OK payload: - * <[8] HELLO timestamp field echo> - * <[1] protocol version> - * <[1] software major version> - * <[1] software minor version> - * <[2] software revision> - * <[...] physical destination address of packet> - * <[2] 16-bit length of world update(s) or 0 if none> - * [[...] updates to planets and/or moons] - * - * With the exception of the timestamp, the other fields pertain to the - * respondent who is sending OK and are not echoes. - * - * Note that OK is fully encrypted so no selective cryptField() of - * potentially sensitive fields is needed. - * - * ERROR has no payload. - */ - VERB_HELLO = 0x01, - - /** - * Error response: - * <[1] in-re verb> - * <[8] in-re packet ID> - * <[1] error code> - * <[...] error-dependent payload> - */ - VERB_ERROR = 0x02, - - /** - * Success response: - * <[1] in-re verb> - * <[8] in-re packet ID> - * <[...] request-specific payload> - */ - VERB_OK = 0x03, - - /** - * Query an identity by address: - * <[5] address to look up> - * [<[...] additional addresses to look up> - * - * OK response payload: - * <[...] binary serialized identity> - * [<[...] additional binary serialized identities>] - * - * If querying a cluster, duplicate OK responses may occasionally occur. - * These must be tolerated, which is easy since they'll have info you - * already have. - * - * If the address is not found, no response is generated. The semantics - * of WHOIS is similar to ARP and NDP in that persistent retrying can - * be performed. - */ - VERB_WHOIS = 0x04, - - /** - * Relay-mediated NAT traversal or firewall punching initiation: - * <[1] flags (unused, currently 0)> - * <[5] ZeroTier address of peer that might be found at this address> - * <[2] 16-bit protocol address port> - * <[1] protocol address length (4 for IPv4, 16 for IPv6)> - * <[...] protocol address (network byte order)> - * - * An upstream node can send this to inform both sides of a relay of - * information they might use to establish a direct connection. - * - * Upon receipt a peer sends HELLO to establish a direct link. - * - * No OK or ERROR is generated. - */ - VERB_RENDEZVOUS = 0x05, - - /** - * ZT-to-ZT unicast ethernet frame (shortened EXT_FRAME): - * <[8] 64-bit network ID> - * <[2] 16-bit ethertype> - * <[...] ethernet payload> - * - * MAC addresses are derived from the packet's source and destination - * ZeroTier addresses. This is a shortened EXT_FRAME that elides full - * Ethernet framing and other optional flags and features when they - * are not necessary. - * - * ERROR may be generated if a membership certificate is needed for a - * closed network. Payload will be network ID. - */ - VERB_FRAME = 0x06, - - /** - * Full Ethernet frame with MAC addressing and optional fields: - * <[8] 64-bit network ID> - * <[1] flags> - * <[6] destination MAC or all zero for destination node> - * <[6] source MAC or all zero for node of origin> - * <[2] 16-bit ethertype> - * <[...] ethernet payload> - * - * Flags: - * 0x01 - Certificate of network membership attached (DEPRECATED) - * 0x02 - Most significant bit of subtype (see below) - * 0x04 - Middle bit of subtype (see below) - * 0x08 - Least significant bit of subtype (see below) - * 0x10 - ACK requested in the form of OK(EXT_FRAME) - * - * Subtypes (0..7): - * 0x0 - Normal frame (bridging can be determined by checking MAC) - * 0x1 - TEEd outbound frame - * 0x2 - REDIRECTed outbound frame - * 0x3 - WATCHed outbound frame (TEE with ACK, ACK bit also set) - * 0x4 - TEEd inbound frame - * 0x5 - REDIRECTed inbound frame - * 0x6 - WATCHed inbound frame - * 0x7 - (reserved for future use) - * - * An extended frame carries full MAC addressing, making it a - * superset of VERB_FRAME. It is used for bridged traffic, - * redirected or observed traffic via rules, and can in theory - * be used for multicast though MULTICAST_FRAME exists for that - * purpose and has additional options and capabilities. - * - * OK payload (if ACK flag is set): - * <[8] 64-bit network ID> - */ - VERB_EXT_FRAME = 0x07, - - /** - * ECHO request (a.k.a. ping): - * <[...] arbitrary payload> - * - * This generates OK with a copy of the transmitted payload. No ERROR - * is generated. Response to ECHO requests is optional and ECHO may be - * ignored if a node detects a possible flood. - */ - VERB_ECHO = 0x08, - - /** - * Announce interest in multicast group(s): - * <[8] 64-bit network ID> - * <[6] multicast Ethernet address> - * <[4] multicast additional distinguishing information (ADI)> - * [... additional tuples of network/address/adi ...] - * - * LIKEs may be sent to any peer, though a good implementation should - * restrict them to peers on the same network they're for and to network - * controllers and root servers. In the current network, root servers - * will provide the service of final multicast cache. - * - * VERB_NETWORK_CREDENTIALS should be pushed along with this, especially - * if using upstream (e.g. root) nodes as multicast databases. This allows - * GATHERs to be authenticated. - * - * OK/ERROR are not generated. - */ - VERB_MULTICAST_LIKE = 0x09, - - /** - * Network credentials push: - * [<[...] one or more certificates of membership>] - * <[1] 0x00, null byte marking end of COM array> - * <[2] 16-bit number of capabilities> - * <[...] one or more serialized Capability> - * <[2] 16-bit number of tags> - * <[...] one or more serialized Tags> - * <[2] 16-bit number of revocations> - * <[...] one or more serialized Revocations> - * <[2] 16-bit number of certificates of ownership> - * <[...] one or more serialized CertificateOfOwnership> - * - * This can be sent by anyone at any time to push network credentials. - * These will of course only be accepted if they are properly signed. - * Credentials can be for any number of networks. - * - * The use of a zero byte to terminate the COM section is for legacy - * backward compatibility. Newer fields are prefixed with a length. - * - * OK/ERROR are not generated. - */ - VERB_NETWORK_CREDENTIALS = 0x0a, - - /** - * Network configuration request: - * <[8] 64-bit network ID> - * <[2] 16-bit length of request meta-data dictionary> - * <[...] string-serialized request meta-data> - * <[8] 64-bit revision of netconf we currently have> - * <[8] 64-bit timestamp of netconf we currently have> - * - * This message requests network configuration from a node capable of - * providing it. - * - * Responses to this are always whole configs intended for the recipient. - * For patches and other updates a NETWORK_CONFIG is sent instead. - * - * It would be valid and correct as of 1.2.0 to use NETWORK_CONFIG always, - * but OK(NETWORK_CONFIG_REQUEST) should be sent for compatibility. - * - * OK response payload: - * <[8] 64-bit network ID> - * <[2] 16-bit length of network configuration dictionary chunk> - * <[...] network configuration dictionary (may be incomplete)> - * [ ... end of legacy single chunk response ... ] - * <[1] 8-bit flags> - * <[8] 64-bit config update ID (should never be 0)> - * <[4] 32-bit total length of assembled dictionary> - * <[4] 32-bit index of chunk> - * [ ... end signed portion ... ] - * <[1] 8-bit chunk signature type> - * <[2] 16-bit length of chunk signature> - * <[...] chunk signature> - * - * The chunk signature signs the entire payload of the OK response. - * Currently only one signature type is supported: ed25519 (1). - * - * Each config chunk is signed to prevent memory exhaustion or - * traffic crowding DOS attacks against config fragment assembly. - * - * If the packet is from the network controller it is permitted to end - * before the config update ID or other chunking related or signature - * fields. This is to support older controllers that don't include - * these fields and may be removed in the future. - * - * ERROR response payload: - * <[8] 64-bit network ID> - * <[2] 16-bit length of error-related data (optional)> - * <[...] error-related data (optional)> - * - * Error related data is a Dictionary containing things like a URL - * for authentication or a human-readable error message, and is - * optional and may be absent or empty. - */ - VERB_NETWORK_CONFIG_REQUEST = 0x0b, - - /** - * Network configuration data push: - * <[8] 64-bit network ID> - * <[2] 16-bit length of network configuration dictionary chunk> - * <[...] network configuration dictionary (may be incomplete)> - * <[1] 8-bit flags> - * <[8] 64-bit config update ID (should never be 0)> - * <[4] 32-bit total length of assembled dictionary> - * <[4] 32-bit index of chunk> - * [ ... end signed portion ... ] - * <[1] 8-bit chunk signature type> - * <[2] 16-bit length of chunk signature> - * <[...] chunk signature> - * - * This is a direct push variant for network config updates. It otherwise - * carries the same payload as OK(NETWORK_CONFIG_REQUEST) and has the same - * semantics. - * - * The legacy mode missing the additional chunking fields is not supported - * here. - * - * Flags: - * 0x01 - Use fast propagation - * - * An OK should be sent if the config is successfully received and - * accepted. - * - * OK payload: - * <[8] 64-bit network ID> - * <[8] 64-bit config update ID> - */ - VERB_NETWORK_CONFIG = 0x0c, - - /** - * Request endpoints for multicast distribution: - * <[8] 64-bit network ID> - * <[1] flags> - * <[6] MAC address of multicast group being queried> - * <[4] 32-bit ADI for multicast group being queried> - * <[4] 32-bit requested max number of multicast peers> - * [<[...] network certificate of membership>] - * - * Flags: - * 0x01 - COM is attached - * - * This message asks a peer for additional known endpoints that have - * LIKEd a given multicast group. It's sent when the sender wishes - * to send multicast but does not have the desired number of recipient - * peers. - * - * More than one OK response can occur if the response is broken up across - * multiple packets or if querying a clustered node. - * - * The COM should be included so that upstream nodes that are not - * members of our network can validate our request. - * - * OK response payload: - * <[8] 64-bit network ID> - * <[6] MAC address of multicast group being queried> - * <[4] 32-bit ADI for multicast group being queried> - * [begin gather results -- these same fields can be in OK(MULTICAST_FRAME)] - * <[4] 32-bit total number of known members in this multicast group> - * <[2] 16-bit number of members enumerated in this packet> - * <[...] series of 5-byte ZeroTier addresses of enumerated members> - * - * ERROR is not generated; queries that return no response are dropped. - */ - VERB_MULTICAST_GATHER = 0x0d, - - /** - * Multicast frame: - * <[8] 64-bit network ID> - * <[1] flags> - * [<[4] 32-bit implicit gather limit>] - * [<[6] source MAC>] - * <[6] destination MAC (multicast address)> - * <[4] 32-bit multicast ADI (multicast address extension)> - * <[2] 16-bit ethertype> - * <[...] ethernet payload> - * - * Flags: - * 0x01 - Network certificate of membership attached (DEPRECATED) - * 0x02 - Implicit gather limit field is present - * 0x04 - Source MAC is specified -- otherwise it's computed from sender - * 0x08 - Please replicate (sent to multicast replicators) - * - * OK and ERROR responses are optional. OK may be generated if there are - * implicit gather results or if the recipient wants to send its own - * updated certificate of network membership to the sender. ERROR may be - * generated if a certificate is needed or if multicasts to this group - * are no longer wanted (multicast unsubscribe). - * - * OK response payload: - * <[8] 64-bit network ID> - * <[6] MAC address of multicast group> - * <[4] 32-bit ADI for multicast group> - * <[1] flags> - * [<[...] network certificate of membership (DEPRECATED)>] - * [<[...] implicit gather results if flag 0x01 is set>] - * - * OK flags (same bits as request flags): - * 0x01 - OK includes certificate of network membership (DEPRECATED) - * 0x02 - OK includes implicit gather results - * - * ERROR response payload: - * <[8] 64-bit network ID> - * <[6] multicast group MAC> - * <[4] 32-bit multicast group ADI> - */ - VERB_MULTICAST_FRAME = 0x0e, - - /** - * Push of potential endpoints for direct communication: - * <[2] 16-bit number of paths> - * <[...] paths> - * - * Path record format: - * <[1] 8-bit path flags> - * <[2] length of extended path characteristics or 0 for none> - * <[...] extended path characteristics> - * <[1] address type> - * <[1] address length in bytes> - * <[...] address> - * - * Path record flags: - * 0x01 - Forget this path if currently known (not implemented yet) - * 0x02 - Cluster redirect -- use this in preference to others - * - * The receiver may, upon receiving a push, attempt to establish a - * direct link to one or more of the indicated addresses. It is the - * responsibility of the sender to limit which peers it pushes direct - * paths to to those with whom it has a trust relationship. The receiver - * must obey any restrictions provided such as exclusivity or blacklists. - * OK responses to this message are optional. - * - * Note that a direct path push does not imply that learned paths can't - * be used unless they are blacklisted explicitly or unless flag 0x01 - * is set. - * - * OK and ERROR are not generated. - */ - VERB_PUSH_DIRECT_PATHS = 0x10, - - // 0x11 -- deprecated - - /** - * An acknowledgment of receipt of a series of recent packets from another - * peer. This is used to calculate relative throughput values and to detect - * packet loss. Only VERB_FRAME and VERB_EXT_FRAME packets are counted. - * - * ACK response format: - * <[4] 32-bit number of bytes received since last ACK> - * - * Upon receipt of this packet, the local peer will verify that the correct - * number of bytes were received by the remote peer. If these values do - * not agree that could be an indication of packet loss. - * - * Additionally, the local peer knows the interval of time that has - * elapsed since the last received ACK. With this information it can compute - * a rough estimate of the current throughput. - * - * This is sent at a maximum rate of once per every ZT_QOS_ACK_INTERVAL - */ - VERB_ACK = 0x12, - - /** - * A packet containing timing measurements useful for estimating path quality. - * Composed of a list of pairs for an - * arbitrary set of recent packets. This is used to sample for latency and - * packet delay variance (PDV, "jitter"). - * - * QoS record format: - * - * <[8] 64-bit packet ID of previously-received packet> - * <[1] 8-bit packet sojourn time> - * <...repeat until end of max 1400 byte packet...> - * - * The number of possible records per QoS packet is: (1400 * 8) / 72 = 155 - * This packet should be sent very rarely (every few seconds) as it can be - * somewhat large if the connection is saturated. Future versions might use - * a bloom table to probabilistically determine these values in a vastly - * more space-efficient manner. - * - * Note: The 'internal packet sojourn time' is a slight misnomer as it is a - * measure of the amount of time between when a packet was received and the - * egress time of its tracking QoS packet. - * - * This is sent at a maximum rate of once per every - * ZT_QOS_MEASUREMENT_INTERVAL - */ - VERB_QOS_MEASUREMENT = 0x13, - - /** - * A message with arbitrary user-definable content: - * <[8] 64-bit arbitrary message type ID> - * [<[...] message payload>] - * - * This can be used to send arbitrary messages over VL1. It generates no - * OK or ERROR and has no special semantics outside of whatever the user - * (via the ZeroTier core API) chooses to give it. - * - * Message type IDs less than or equal to 65535 are reserved for use by - * ZeroTier, Inc. itself. We recommend making up random ones for your own - * implementations. - */ - VERB_USER_MESSAGE = 0x14, - - /** - * A trace for remote debugging or diagnostics: - * <[...] null-terminated dictionary containing trace information> - * [<[...] additional null-terminated dictionaries>] - * - * This message contains a remote trace event. Remote trace events can - * be sent to observers configured at the network level for those that - * pertain directly to activity on a network, or to global observers if - * locally configured. - * - * The instance ID is a random 64-bit value generated by each ZeroTier - * node on startup. This is helpful in identifying traces from different - * members of a cluster. - */ - VERB_REMOTE_TRACE = 0x15, - - /** - * A request to a peer to use a specific path in a multi-path scenario: - * <[2] 16-bit unsigned integer that encodes a path choice utility> - * - * This is sent when a node operating in multipath mode observes that - * its inbound and outbound traffic aren't going over the same path. The - * node will compute its perceived utility for using its chosen outbound - * path and send this to a peer in an attempt to petition it to send - * its traffic over this same path. - * - * Scenarios: - * - * (1) Remote peer utility is GREATER than ours: - * - Remote peer will refuse the petition and continue using current path - * (2) Remote peer utility is LESS than than ours: - * - Remote peer will accept the petition and switch to our chosen path - * (3) Remote peer utility is EQUAL to our own: - * - To prevent confusion and flapping, both side will agree to use the - * numerical values of their identities to determine which path to use. - * The peer with the greatest identity will win. - * - * If a node petitions a peer repeatedly with no effect it will regard - * that as a refusal by the remote peer, in this case if the utility is - * negligible it will voluntarily switch to the remote peer's chosen path. - */ - VERB_PATH_NEGOTIATION_REQUEST = 0x16 - }; - - /** - * Error codes for VERB_ERROR - */ - enum ErrorCode - { - /* No error, not actually used in transit */ - ERROR_NONE = 0x00, - - /* Invalid request */ - ERROR_INVALID_REQUEST = 0x01, - - /* Bad/unsupported protocol version */ - ERROR_BAD_PROTOCOL_VERSION = 0x02, - - /* Unknown object queried */ - ERROR_OBJ_NOT_FOUND = 0x03, - - /* HELLO pushed an identity whose address is already claimed */ - ERROR_IDENTITY_COLLISION = 0x04, - - /* Verb or use case not supported/enabled by this node */ - ERROR_UNSUPPORTED_OPERATION = 0x05, - - /* Network membership certificate update needed */ - ERROR_NEED_MEMBERSHIP_CERTIFICATE = 0x06, - - /* Tried to join network, but you're not a member */ - ERROR_NETWORK_ACCESS_DENIED_ = 0x07, /* extra _ at end to avoid Windows name conflict */ - - /* Multicasts to this group are not wanted */ - ERROR_UNWANTED_MULTICAST = 0x08, - - /* Network requires external or 2FA authentication (e.g. SSO). */ - ERROR_NETWORK_AUTHENTICATION_REQUIRED = 0x09 - }; - - template - Packet(const Buffer &b) : - Buffer(b) - { - } - - Packet(const void *data,unsigned int len) : - Buffer(data,len) - { - } - - /** - * Construct a new empty packet with a unique random packet ID - * - * Flags and hops will be zero. Other fields and data region are undefined. - * Use the header access methods (setDestination() and friends) to fill out - * the header. Payload should be appended; initial size is header size. - */ - Packet() : - Buffer(ZT_PROTO_MIN_PACKET_LENGTH) - { - Utils::getSecureRandom(field(ZT_PACKET_IDX_IV,8),8); - (*this)[ZT_PACKET_IDX_FLAGS] = 0; // zero flags, cipher ID, and hops - } - - /** - * Make a copy of a packet with a new initialization vector and destination address - * - * This can be used to take one draft prototype packet and quickly make copies to - * encrypt for different destinations. - * - * @param prototype Prototype packet - * @param dest Destination ZeroTier address for new packet - */ - Packet(const Packet &prototype,const Address &dest) : - Buffer(prototype) - { - Utils::getSecureRandom(field(ZT_PACKET_IDX_IV,8),8); - setDestination(dest); - } - - /** - * Construct a new empty packet with a unique random packet ID - * - * @param dest Destination ZT address - * @param source Source ZT address - * @param v Verb - */ - Packet(const Address &dest,const Address &source,const Verb v) : - Buffer(ZT_PROTO_MIN_PACKET_LENGTH) - { - Utils::getSecureRandom(field(ZT_PACKET_IDX_IV,8),8); - setDestination(dest); - setSource(source); - (*this)[ZT_PACKET_IDX_FLAGS] = 0; // zero flags and hops - setVerb(v); - } - - /** - * Reset this packet structure for reuse in place - * - * @param dest Destination ZT address - * @param source Source ZT address - * @param v Verb - */ - inline void reset(const Address &dest,const Address &source,const Verb v) - { - setSize(ZT_PROTO_MIN_PACKET_LENGTH); - Utils::getSecureRandom(field(ZT_PACKET_IDX_IV,8),8); - setDestination(dest); - setSource(source); - (*this)[ZT_PACKET_IDX_FLAGS] = 0; // zero flags, cipher ID, and hops - setVerb(v); - } - - /** - * Generate a new IV / packet ID in place - * - * This can be used to re-use a packet buffer multiple times to send - * technically different but otherwise identical copies of the same - * packet. - */ - inline void newInitializationVector() { Utils::getSecureRandom(field(ZT_PACKET_IDX_IV,8),8); } - - /** - * Set this packet's destination - * - * @param dest ZeroTier address of destination - */ - inline void setDestination(const Address &dest) { dest.copyTo(field(ZT_PACKET_IDX_DEST,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); } - - /** - * Set this packet's source - * - * @param source ZeroTier address of source - */ - inline void setSource(const Address &source) { source.copyTo(field(ZT_PACKET_IDX_SOURCE,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); } - - /** - * Get this packet's destination - * - * @return Destination ZT address - */ - inline Address destination() const { return Address(field(ZT_PACKET_IDX_DEST,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); } - - /** - * Get this packet's source - * - * @return Source ZT address - */ - inline Address source() const { return Address(field(ZT_PACKET_IDX_SOURCE,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); } - - /** - * @return True if packet is of valid length - */ - inline bool lengthValid() const { return (size() >= ZT_PROTO_MIN_PACKET_LENGTH); } - - /** - * @return True if packet is fragmented (expect fragments) - */ - inline bool fragmented() const { return (((unsigned char)(*this)[ZT_PACKET_IDX_FLAGS] & ZT_PROTO_FLAG_FRAGMENTED) != 0); } - - /** - * Set this packet's fragmented flag - * - * @param f Fragmented flag value - */ - inline void setFragmented(bool f) - { - if (f) { - (*this)[ZT_PACKET_IDX_FLAGS] |= (char)ZT_PROTO_FLAG_FRAGMENTED; - } else { - (*this)[ZT_PACKET_IDX_FLAGS] &= (char)(~ZT_PROTO_FLAG_FRAGMENTED); - } - } - - /** - * @return True if compressed (result only valid if unencrypted) - */ - inline bool compressed() const { return (((unsigned char)(*this)[ZT_PACKET_IDX_VERB] & ZT_PROTO_VERB_FLAG_COMPRESSED) != 0); } - - /** - * @return ZeroTier forwarding hops (0 to 7) - */ - inline unsigned int hops() const { return ((unsigned int)(*this)[ZT_PACKET_IDX_FLAGS] & 0x07); } - - /** - * Increment this packet's hop count - */ - inline void incrementHops() - { - unsigned char &b = (*this)[ZT_PACKET_IDX_FLAGS]; - b = (b & 0xf8) | ((b + 1) & 0x07); - } - - /** - * @return Cipher suite selector: 0 - 7 (see #defines) - */ - inline unsigned int cipher() const - { - return (((unsigned int)(*this)[ZT_PACKET_IDX_FLAGS] & 0x38) >> 3); - } - - /** - * @return Whether this packet is currently encrypted - */ - inline bool isEncrypted() const - { - return (cipher() == ZT_PROTO_CIPHER_SUITE__C25519_POLY1305_SALSA2012) || (cipher() == ZT_PROTO_CIPHER_SUITE__AES_GMAC_SIV); - } - - /** - * Set this packet's cipher suite - */ - inline void setCipher(unsigned int c) - { - unsigned char &b = (*this)[ZT_PACKET_IDX_FLAGS]; - b = (b & 0xc7) | (unsigned char)((c << 3) & 0x38); // bits: FFCCCHHH - // Set DEPRECATED "encrypted" flag -- used by pre-1.0.3 peers - if (c == ZT_PROTO_CIPHER_SUITE__C25519_POLY1305_SALSA2012) { - b |= ZT_PROTO_FLAG_ENCRYPTED; - } else { - b &= (~ZT_PROTO_FLAG_ENCRYPTED); - } - } - - /** - * Get the trusted path ID for this packet (only meaningful if cipher is trusted path) - * - * @return Trusted path ID (from MAC field) - */ - inline uint64_t trustedPathId() const { return at(ZT_PACKET_IDX_MAC); } - - /** - * Set this packet's trusted path ID and set the cipher spec to trusted path - * - * @param tpid Trusted path ID - */ - inline void setTrusted(const uint64_t tpid) - { - setCipher(ZT_PROTO_CIPHER_SUITE__NO_CRYPTO_TRUSTED_PATH); - setAt(ZT_PACKET_IDX_MAC,tpid); - } - - /** - * Get this packet's unique ID (the IV field interpreted as uint64_t) - * - * Note that the least significant 3 bits of this ID will change when armor() - * is called to armor the packet for transport. This is because armor() will - * mask the last 3 bits against the send counter for QoS monitoring use prior - * to actually using the IV to encrypt and MAC the packet. Be aware of this - * when grabbing the packetId of a new packet prior to armor/send. - * - * @return Packet ID - */ - inline uint64_t packetId() const { return at(ZT_PACKET_IDX_IV); } - - /** - * Set packet verb - * - * This also has the side-effect of clearing any verb flags, such as - * compressed, and so must only be done during packet composition. - * - * @param v New packet verb - */ - inline void setVerb(Verb v) { (*this)[ZT_PACKET_IDX_VERB] = (char)v; } - - /** - * @return Packet verb (not including flag bits) - */ - inline Verb verb() const { return (Verb)((*this)[ZT_PACKET_IDX_VERB] & 0x1f); } - - /** - * @return Length of packet payload - */ - inline unsigned int payloadLength() const { return ((size() < ZT_PROTO_MIN_PACKET_LENGTH) ? 0 : (size() - ZT_PROTO_MIN_PACKET_LENGTH)); } - - /** - * @return Raw packet payload - */ - inline const unsigned char *payload() const { return field(ZT_PACKET_IDX_PAYLOAD,size() - ZT_PACKET_IDX_PAYLOAD); } - - /** - * Armor packet for transport - * - * @param key 32-byte key - * @param encryptPayload If true, encrypt packet payload, else just MAC - * @param aesKeys If non-NULL these are the two keys for AES-GMAC-SIV - */ - void armor(const void *key,bool encryptPayload,const AES aesKeys[2]); - - /** - * Verify and (if encrypted) decrypt packet - * - * This does not handle trusted path mode packets and will return false - * for these. These are handled in IncomingPacket if the sending physical - * address and MAC field match a trusted path. - * - * @param key 32-byte key - * @param aesKeys If non-NULL these are the two keys for AES-GMAC-SIV - * @return False if packet is invalid or failed MAC authenticity check - */ - bool dearmor(const void *key,const AES aesKeys[2]); - - /** - * Encrypt/decrypt a separately armored portion of a packet - * - * This is currently only used to mask portions of HELLO as an extra - * security precaution since most of that message is sent in the clear. - * - * This must NEVER be used more than once in the same packet, as doing - * so will result in re-use of the same key stream. - * - * @param key 32-byte key - * @param start Start of encrypted portion - * @param len Length of encrypted portion - */ - void cryptField(const void *key,unsigned int start,unsigned int len); - - /** - * Attempt to compress payload if not already (must be unencrypted) - * - * This requires that the payload at least contain the verb byte already - * set. The compressed flag in the verb is set if compression successfully - * results in a size reduction. If no size reduction occurs, compression - * is not done and the flag is left cleared. - * - * @return True if compression occurred - */ - bool compress(); - - /** - * Attempt to decompress payload if it is compressed (must be unencrypted) - * - * If payload is compressed, it is decompressed and the compressed verb - * flag is cleared. Otherwise nothing is done and true is returned. - * - * @return True if data is now decompressed and valid, false on error - */ - bool uncompress(); - -private: - static const unsigned char ZERO_KEY[32]; - - /** - * Deterministically mangle a 256-bit crypto key based on packet - * - * This uses extra data from the packet to mangle the secret, giving us an - * effective IV that is somewhat more than 64 bits. This is "free" for - * Salsa20 since it has negligible key setup time so using a different - * key each time is fine. - * - * @param in Input key (32 bytes) - * @param out Output buffer (32 bytes) - */ - inline void _salsa20MangleKey(const unsigned char *in,unsigned char *out) const - { - const unsigned char *d = (const unsigned char *)data(); - - // IV and source/destination addresses. Using the addresses divides the - // key space into two halves-- A->B and B->A (since order will change). - for(unsigned int i=0;i<18;++i) { // 8 + (ZT_ADDRESS_LENGTH * 2) == 18 - out[i] = in[i] ^ d[i]; - } - - // Flags, but with hop count masked off. Hop count is altered by forwarding - // nodes. It's one of the only parts of a packet modifiable by people - // without the key. - out[18] = in[18] ^ (d[ZT_PACKET_IDX_FLAGS] & 0xf8); - - // Raw packet size in bytes -- thus each packet size defines a new - // key space. - out[19] = in[19] ^ (unsigned char)(size() & 0xff); - out[20] = in[20] ^ (unsigned char)((size() >> 8) & 0xff); // little endian - - // Rest of raw key is used unchanged - for(unsigned int i=21;i<32;++i) { - out[i] = in[i]; - } - } +class Packet : public Buffer { + public: + /** + * A packet fragment + * + * Fragments are sent if a packet is larger than UDP MTU. The first fragment + * is sent with its normal header with the fragmented flag set. Remaining + * fragments are sent this way. + * + * The fragmented bit indicates that there is at least one fragment. Fragments + * themselves contain the total, so the receiver must "learn" this from the + * first fragment it receives. + * + * Fragments are sent with the following format: + * <[8] packet ID of packet whose fragment this belongs to> + * <[5] destination ZT address> + * <[1] 0xff, a reserved address, signals that this isn't a normal packet> + * <[1] total fragments (most significant 4 bits), fragment no (LS 4 bits)> + * <[1] ZT hop count (top 5 bits unused and must be zero)> + * <[...] fragment data> + * + * The protocol supports a maximum of 16 fragments. If a fragment is received + * before its main packet header, it should be cached for a brief period of + * time to see if its parent arrives. Loss of any fragment constitutes packet + * loss; there is no retransmission mechanism. The receiver must wait for full + * receipt to authenticate and decrypt; there is no per-fragment MAC. (But if + * fragments are corrupt, the MAC will fail for the whole assembled packet.) + */ + class Fragment : public Buffer { + public: + Fragment() : Buffer() + { + } + + template Fragment(const Buffer& b) : Buffer(b) + { + } + + Fragment(const void* data, unsigned int len) : Buffer(data, len) + { + } + + /** + * Initialize from a packet + * + * @param p Original assembled packet + * @param fragStart Start of fragment (raw index in packet data) + * @param fragLen Length of fragment in bytes + * @param fragNo Which fragment (>= 1, since 0 is Packet with end chopped off) + * @param fragTotal Total number of fragments (including 0) + */ + Fragment(const Packet& p, unsigned int fragStart, unsigned int fragLen, unsigned int fragNo, unsigned int fragTotal) + { + init(p, fragStart, fragLen, fragNo, fragTotal); + } + + /** + * Initialize from a packet + * + * @param p Original assembled packet + * @param fragStart Start of fragment (raw index in packet data) + * @param fragLen Length of fragment in bytes + * @param fragNo Which fragment (>= 1, since 0 is Packet with end chopped off) + * @param fragTotal Total number of fragments (including 0) + */ + inline void init(const Packet& p, unsigned int fragStart, unsigned int fragLen, unsigned int fragNo, unsigned int fragTotal) + { + if ((fragStart + fragLen) > p.size()) { + throw ZT_EXCEPTION_OUT_OF_BOUNDS; + } + setSize(fragLen + ZT_PROTO_MIN_FRAGMENT_LENGTH); + + // NOTE: this copies both the IV/packet ID and the destination address. + memcpy(field(ZT_PACKET_FRAGMENT_IDX_PACKET_ID, 13), p.field(ZT_PACKET_IDX_IV, 13), 13); + + (*this)[ZT_PACKET_FRAGMENT_IDX_FRAGMENT_INDICATOR] = ZT_PACKET_FRAGMENT_INDICATOR; + (*this)[ZT_PACKET_FRAGMENT_IDX_FRAGMENT_NO] = (char)(((fragTotal & 0xf) << 4) | (fragNo & 0xf)); + (*this)[ZT_PACKET_FRAGMENT_IDX_HOPS] = 0; + + memcpy(field(ZT_PACKET_FRAGMENT_IDX_PAYLOAD, fragLen), p.field(fragStart, fragLen), fragLen); + } + + /** + * Get this fragment's destination + * + * @return Destination ZT address + */ + inline Address destination() const + { + return Address(field(ZT_PACKET_FRAGMENT_IDX_DEST, ZT_ADDRESS_LENGTH), ZT_ADDRESS_LENGTH); + } + + /** + * @return True if fragment is of a valid length + */ + inline bool lengthValid() const + { + return (size() >= ZT_PACKET_FRAGMENT_IDX_PAYLOAD); + } + + /** + * @return ID of packet this is a fragment of + */ + inline uint64_t packetId() const + { + return at(ZT_PACKET_FRAGMENT_IDX_PACKET_ID); + } + + /** + * @return Total number of fragments in packet + */ + inline unsigned int totalFragments() const + { + return (((unsigned int)((*this)[ZT_PACKET_FRAGMENT_IDX_FRAGMENT_NO]) >> 4) & 0xf); + } + + /** + * @return Fragment number of this fragment + */ + inline unsigned int fragmentNumber() const + { + return ((unsigned int)((*this)[ZT_PACKET_FRAGMENT_IDX_FRAGMENT_NO]) & 0xf); + } + + /** + * @return Fragment ZT hop count + */ + inline unsigned int hops() const + { + return (unsigned int)((*this)[ZT_PACKET_FRAGMENT_IDX_HOPS]); + } + + /** + * Increment this packet's hop count + */ + inline void incrementHops() + { + (*this)[ZT_PACKET_FRAGMENT_IDX_HOPS] = (((*this)[ZT_PACKET_FRAGMENT_IDX_HOPS]) + 1) & ZT_PROTO_MAX_HOPS; + } + + /** + * @return Length of payload in bytes + */ + inline unsigned int payloadLength() const + { + return ((size() > ZT_PACKET_FRAGMENT_IDX_PAYLOAD) ? (size() - ZT_PACKET_FRAGMENT_IDX_PAYLOAD) : 0); + } + + /** + * @return Raw packet payload + */ + inline const unsigned char* payload() const + { + return field(ZT_PACKET_FRAGMENT_IDX_PAYLOAD, size() - ZT_PACKET_FRAGMENT_IDX_PAYLOAD); + } + }; + + /** + * ZeroTier protocol verbs + */ + enum Verb /* Max value: 32 (5 bits) */ + { + /** + * No operation (ignored, no reply) + */ + VERB_NOP = 0x00, + + /** + * Announcement of a node's existence and vitals: + * <[1] protocol version> + * <[1] software major version> + * <[1] software minor version> + * <[2] software revision> + * <[8] timestamp for determining latency> + * <[...] binary serialized identity (see Identity)> + * <[...] physical destination address of packet> + * <[8] 64-bit world ID of current planet> + * <[8] 64-bit timestamp of current planet> + * [... remainder if packet is encrypted using cryptField() ...] + * <[2] 16-bit number of moons> + * [<[1] 8-bit type ID of moon>] + * [<[8] 64-bit world ID of moon>] + * [<[8] 64-bit timestamp of moon>] + * [... additional moon type/ID/timestamp tuples ...] + * + * HELLO is sent in the clear as it is how peers share their identity + * public keys. A few additional fields are sent in the clear too, but + * these are things that are public info or are easy to determine. As + * of 1.2.0 we have added a few more fields, but since these could have + * the potential to be sensitive we introduced the encryption of the + * remainder of the packet. See cryptField(). Packet MAC is still + * performed of course, so authentication occurs as normal. + * + * Destination address is the actual wire address to which the packet + * was sent. See InetAddress::serialize() for format. + * + * OK payload: + * <[8] HELLO timestamp field echo> + * <[1] protocol version> + * <[1] software major version> + * <[1] software minor version> + * <[2] software revision> + * <[...] physical destination address of packet> + * <[2] 16-bit length of world update(s) or 0 if none> + * [[...] updates to planets and/or moons] + * + * With the exception of the timestamp, the other fields pertain to the + * respondent who is sending OK and are not echoes. + * + * Note that OK is fully encrypted so no selective cryptField() of + * potentially sensitive fields is needed. + * + * ERROR has no payload. + */ + VERB_HELLO = 0x01, + + /** + * Error response: + * <[1] in-re verb> + * <[8] in-re packet ID> + * <[1] error code> + * <[...] error-dependent payload> + */ + VERB_ERROR = 0x02, + + /** + * Success response: + * <[1] in-re verb> + * <[8] in-re packet ID> + * <[...] request-specific payload> + */ + VERB_OK = 0x03, + + /** + * Query an identity by address: + * <[5] address to look up> + * [<[...] additional addresses to look up> + * + * OK response payload: + * <[...] binary serialized identity> + * [<[...] additional binary serialized identities>] + * + * If querying a cluster, duplicate OK responses may occasionally occur. + * These must be tolerated, which is easy since they'll have info you + * already have. + * + * If the address is not found, no response is generated. The semantics + * of WHOIS is similar to ARP and NDP in that persistent retrying can + * be performed. + */ + VERB_WHOIS = 0x04, + + /** + * Relay-mediated NAT traversal or firewall punching initiation: + * <[1] flags (unused, currently 0)> + * <[5] ZeroTier address of peer that might be found at this address> + * <[2] 16-bit protocol address port> + * <[1] protocol address length (4 for IPv4, 16 for IPv6)> + * <[...] protocol address (network byte order)> + * + * An upstream node can send this to inform both sides of a relay of + * information they might use to establish a direct connection. + * + * Upon receipt a peer sends HELLO to establish a direct link. + * + * No OK or ERROR is generated. + */ + VERB_RENDEZVOUS = 0x05, + + /** + * ZT-to-ZT unicast ethernet frame (shortened EXT_FRAME): + * <[8] 64-bit network ID> + * <[2] 16-bit ethertype> + * <[...] ethernet payload> + * + * MAC addresses are derived from the packet's source and destination + * ZeroTier addresses. This is a shortened EXT_FRAME that elides full + * Ethernet framing and other optional flags and features when they + * are not necessary. + * + * ERROR may be generated if a membership certificate is needed for a + * closed network. Payload will be network ID. + */ + VERB_FRAME = 0x06, + + /** + * Full Ethernet frame with MAC addressing and optional fields: + * <[8] 64-bit network ID> + * <[1] flags> + * <[6] destination MAC or all zero for destination node> + * <[6] source MAC or all zero for node of origin> + * <[2] 16-bit ethertype> + * <[...] ethernet payload> + * + * Flags: + * 0x01 - Certificate of network membership attached (DEPRECATED) + * 0x02 - Most significant bit of subtype (see below) + * 0x04 - Middle bit of subtype (see below) + * 0x08 - Least significant bit of subtype (see below) + * 0x10 - ACK requested in the form of OK(EXT_FRAME) + * + * Subtypes (0..7): + * 0x0 - Normal frame (bridging can be determined by checking MAC) + * 0x1 - TEEd outbound frame + * 0x2 - REDIRECTed outbound frame + * 0x3 - WATCHed outbound frame (TEE with ACK, ACK bit also set) + * 0x4 - TEEd inbound frame + * 0x5 - REDIRECTed inbound frame + * 0x6 - WATCHed inbound frame + * 0x7 - (reserved for future use) + * + * An extended frame carries full MAC addressing, making it a + * superset of VERB_FRAME. It is used for bridged traffic, + * redirected or observed traffic via rules, and can in theory + * be used for multicast though MULTICAST_FRAME exists for that + * purpose and has additional options and capabilities. + * + * OK payload (if ACK flag is set): + * <[8] 64-bit network ID> + */ + VERB_EXT_FRAME = 0x07, + + /** + * ECHO request (a.k.a. ping): + * <[...] arbitrary payload> + * + * This generates OK with a copy of the transmitted payload. No ERROR + * is generated. Response to ECHO requests is optional and ECHO may be + * ignored if a node detects a possible flood. + */ + VERB_ECHO = 0x08, + + /** + * Announce interest in multicast group(s): + * <[8] 64-bit network ID> + * <[6] multicast Ethernet address> + * <[4] multicast additional distinguishing information (ADI)> + * [... additional tuples of network/address/adi ...] + * + * LIKEs may be sent to any peer, though a good implementation should + * restrict them to peers on the same network they're for and to network + * controllers and root servers. In the current network, root servers + * will provide the service of final multicast cache. + * + * VERB_NETWORK_CREDENTIALS should be pushed along with this, especially + * if using upstream (e.g. root) nodes as multicast databases. This allows + * GATHERs to be authenticated. + * + * OK/ERROR are not generated. + */ + VERB_MULTICAST_LIKE = 0x09, + + /** + * Network credentials push: + * [<[...] one or more certificates of membership>] + * <[1] 0x00, null byte marking end of COM array> + * <[2] 16-bit number of capabilities> + * <[...] one or more serialized Capability> + * <[2] 16-bit number of tags> + * <[...] one or more serialized Tags> + * <[2] 16-bit number of revocations> + * <[...] one or more serialized Revocations> + * <[2] 16-bit number of certificates of ownership> + * <[...] one or more serialized CertificateOfOwnership> + * + * This can be sent by anyone at any time to push network credentials. + * These will of course only be accepted if they are properly signed. + * Credentials can be for any number of networks. + * + * The use of a zero byte to terminate the COM section is for legacy + * backward compatibility. Newer fields are prefixed with a length. + * + * OK/ERROR are not generated. + */ + VERB_NETWORK_CREDENTIALS = 0x0a, + + /** + * Network configuration request: + * <[8] 64-bit network ID> + * <[2] 16-bit length of request meta-data dictionary> + * <[...] string-serialized request meta-data> + * <[8] 64-bit revision of netconf we currently have> + * <[8] 64-bit timestamp of netconf we currently have> + * + * This message requests network configuration from a node capable of + * providing it. + * + * Responses to this are always whole configs intended for the recipient. + * For patches and other updates a NETWORK_CONFIG is sent instead. + * + * It would be valid and correct as of 1.2.0 to use NETWORK_CONFIG always, + * but OK(NETWORK_CONFIG_REQUEST) should be sent for compatibility. + * + * OK response payload: + * <[8] 64-bit network ID> + * <[2] 16-bit length of network configuration dictionary chunk> + * <[...] network configuration dictionary (may be incomplete)> + * [ ... end of legacy single chunk response ... ] + * <[1] 8-bit flags> + * <[8] 64-bit config update ID (should never be 0)> + * <[4] 32-bit total length of assembled dictionary> + * <[4] 32-bit index of chunk> + * [ ... end signed portion ... ] + * <[1] 8-bit chunk signature type> + * <[2] 16-bit length of chunk signature> + * <[...] chunk signature> + * + * The chunk signature signs the entire payload of the OK response. + * Currently only one signature type is supported: ed25519 (1). + * + * Each config chunk is signed to prevent memory exhaustion or + * traffic crowding DOS attacks against config fragment assembly. + * + * If the packet is from the network controller it is permitted to end + * before the config update ID or other chunking related or signature + * fields. This is to support older controllers that don't include + * these fields and may be removed in the future. + * + * ERROR response payload: + * <[8] 64-bit network ID> + * <[2] 16-bit length of error-related data (optional)> + * <[...] error-related data (optional)> + * + * Error related data is a Dictionary containing things like a URL + * for authentication or a human-readable error message, and is + * optional and may be absent or empty. + */ + VERB_NETWORK_CONFIG_REQUEST = 0x0b, + + /** + * Network configuration data push: + * <[8] 64-bit network ID> + * <[2] 16-bit length of network configuration dictionary chunk> + * <[...] network configuration dictionary (may be incomplete)> + * <[1] 8-bit flags> + * <[8] 64-bit config update ID (should never be 0)> + * <[4] 32-bit total length of assembled dictionary> + * <[4] 32-bit index of chunk> + * [ ... end signed portion ... ] + * <[1] 8-bit chunk signature type> + * <[2] 16-bit length of chunk signature> + * <[...] chunk signature> + * + * This is a direct push variant for network config updates. It otherwise + * carries the same payload as OK(NETWORK_CONFIG_REQUEST) and has the same + * semantics. + * + * The legacy mode missing the additional chunking fields is not supported + * here. + * + * Flags: + * 0x01 - Use fast propagation + * + * An OK should be sent if the config is successfully received and + * accepted. + * + * OK payload: + * <[8] 64-bit network ID> + * <[8] 64-bit config update ID> + */ + VERB_NETWORK_CONFIG = 0x0c, + + /** + * Request endpoints for multicast distribution: + * <[8] 64-bit network ID> + * <[1] flags> + * <[6] MAC address of multicast group being queried> + * <[4] 32-bit ADI for multicast group being queried> + * <[4] 32-bit requested max number of multicast peers> + * [<[...] network certificate of membership>] + * + * Flags: + * 0x01 - COM is attached + * + * This message asks a peer for additional known endpoints that have + * LIKEd a given multicast group. It's sent when the sender wishes + * to send multicast but does not have the desired number of recipient + * peers. + * + * More than one OK response can occur if the response is broken up across + * multiple packets or if querying a clustered node. + * + * The COM should be included so that upstream nodes that are not + * members of our network can validate our request. + * + * OK response payload: + * <[8] 64-bit network ID> + * <[6] MAC address of multicast group being queried> + * <[4] 32-bit ADI for multicast group being queried> + * [begin gather results -- these same fields can be in OK(MULTICAST_FRAME)] + * <[4] 32-bit total number of known members in this multicast group> + * <[2] 16-bit number of members enumerated in this packet> + * <[...] series of 5-byte ZeroTier addresses of enumerated members> + * + * ERROR is not generated; queries that return no response are dropped. + */ + VERB_MULTICAST_GATHER = 0x0d, + + /** + * Multicast frame: + * <[8] 64-bit network ID> + * <[1] flags> + * [<[4] 32-bit implicit gather limit>] + * [<[6] source MAC>] + * <[6] destination MAC (multicast address)> + * <[4] 32-bit multicast ADI (multicast address extension)> + * <[2] 16-bit ethertype> + * <[...] ethernet payload> + * + * Flags: + * 0x01 - Network certificate of membership attached (DEPRECATED) + * 0x02 - Implicit gather limit field is present + * 0x04 - Source MAC is specified -- otherwise it's computed from sender + * 0x08 - Please replicate (sent to multicast replicators) + * + * OK and ERROR responses are optional. OK may be generated if there are + * implicit gather results or if the recipient wants to send its own + * updated certificate of network membership to the sender. ERROR may be + * generated if a certificate is needed or if multicasts to this group + * are no longer wanted (multicast unsubscribe). + * + * OK response payload: + * <[8] 64-bit network ID> + * <[6] MAC address of multicast group> + * <[4] 32-bit ADI for multicast group> + * <[1] flags> + * [<[...] network certificate of membership (DEPRECATED)>] + * [<[...] implicit gather results if flag 0x01 is set>] + * + * OK flags (same bits as request flags): + * 0x01 - OK includes certificate of network membership (DEPRECATED) + * 0x02 - OK includes implicit gather results + * + * ERROR response payload: + * <[8] 64-bit network ID> + * <[6] multicast group MAC> + * <[4] 32-bit multicast group ADI> + */ + VERB_MULTICAST_FRAME = 0x0e, + + /** + * Push of potential endpoints for direct communication: + * <[2] 16-bit number of paths> + * <[...] paths> + * + * Path record format: + * <[1] 8-bit path flags> + * <[2] length of extended path characteristics or 0 for none> + * <[...] extended path characteristics> + * <[1] address type> + * <[1] address length in bytes> + * <[...] address> + * + * Path record flags: + * 0x01 - Forget this path if currently known (not implemented yet) + * 0x02 - Cluster redirect -- use this in preference to others + * + * The receiver may, upon receiving a push, attempt to establish a + * direct link to one or more of the indicated addresses. It is the + * responsibility of the sender to limit which peers it pushes direct + * paths to to those with whom it has a trust relationship. The receiver + * must obey any restrictions provided such as exclusivity or blacklists. + * OK responses to this message are optional. + * + * Note that a direct path push does not imply that learned paths can't + * be used unless they are blacklisted explicitly or unless flag 0x01 + * is set. + * + * OK and ERROR are not generated. + */ + VERB_PUSH_DIRECT_PATHS = 0x10, + + // 0x11 -- deprecated + + /** + * An acknowledgment of receipt of a series of recent packets from another + * peer. This is used to calculate relative throughput values and to detect + * packet loss. Only VERB_FRAME and VERB_EXT_FRAME packets are counted. + * + * ACK response format: + * <[4] 32-bit number of bytes received since last ACK> + * + * Upon receipt of this packet, the local peer will verify that the correct + * number of bytes were received by the remote peer. If these values do + * not agree that could be an indication of packet loss. + * + * Additionally, the local peer knows the interval of time that has + * elapsed since the last received ACK. With this information it can compute + * a rough estimate of the current throughput. + * + * This is sent at a maximum rate of once per every ZT_QOS_ACK_INTERVAL + */ + VERB_ACK = 0x12, + + /** + * A packet containing timing measurements useful for estimating path quality. + * Composed of a list of pairs for an + * arbitrary set of recent packets. This is used to sample for latency and + * packet delay variance (PDV, "jitter"). + * + * QoS record format: + * + * <[8] 64-bit packet ID of previously-received packet> + * <[1] 8-bit packet sojourn time> + * <...repeat until end of max 1400 byte packet...> + * + * The number of possible records per QoS packet is: (1400 * 8) / 72 = 155 + * This packet should be sent very rarely (every few seconds) as it can be + * somewhat large if the connection is saturated. Future versions might use + * a bloom table to probabilistically determine these values in a vastly + * more space-efficient manner. + * + * Note: The 'internal packet sojourn time' is a slight misnomer as it is a + * measure of the amount of time between when a packet was received and the + * egress time of its tracking QoS packet. + * + * This is sent at a maximum rate of once per every + * ZT_QOS_MEASUREMENT_INTERVAL + */ + VERB_QOS_MEASUREMENT = 0x13, + + /** + * A message with arbitrary user-definable content: + * <[8] 64-bit arbitrary message type ID> + * [<[...] message payload>] + * + * This can be used to send arbitrary messages over VL1. It generates no + * OK or ERROR and has no special semantics outside of whatever the user + * (via the ZeroTier core API) chooses to give it. + * + * Message type IDs less than or equal to 65535 are reserved for use by + * ZeroTier, Inc. itself. We recommend making up random ones for your own + * implementations. + */ + VERB_USER_MESSAGE = 0x14, + + /** + * A trace for remote debugging or diagnostics: + * <[...] null-terminated dictionary containing trace information> + * [<[...] additional null-terminated dictionaries>] + * + * This message contains a remote trace event. Remote trace events can + * be sent to observers configured at the network level for those that + * pertain directly to activity on a network, or to global observers if + * locally configured. + * + * The instance ID is a random 64-bit value generated by each ZeroTier + * node on startup. This is helpful in identifying traces from different + * members of a cluster. + */ + VERB_REMOTE_TRACE = 0x15, + + /** + * A request to a peer to use a specific path in a multi-path scenario: + * <[2] 16-bit unsigned integer that encodes a path choice utility> + * + * This is sent when a node operating in multipath mode observes that + * its inbound and outbound traffic aren't going over the same path. The + * node will compute its perceived utility for using its chosen outbound + * path and send this to a peer in an attempt to petition it to send + * its traffic over this same path. + * + * Scenarios: + * + * (1) Remote peer utility is GREATER than ours: + * - Remote peer will refuse the petition and continue using current path + * (2) Remote peer utility is LESS than than ours: + * - Remote peer will accept the petition and switch to our chosen path + * (3) Remote peer utility is EQUAL to our own: + * - To prevent confusion and flapping, both side will agree to use the + * numerical values of their identities to determine which path to use. + * The peer with the greatest identity will win. + * + * If a node petitions a peer repeatedly with no effect it will regard + * that as a refusal by the remote peer, in this case if the utility is + * negligible it will voluntarily switch to the remote peer's chosen path. + */ + VERB_PATH_NEGOTIATION_REQUEST = 0x16 + }; + + /** + * Error codes for VERB_ERROR + */ + enum ErrorCode { + /* No error, not actually used in transit */ + ERROR_NONE = 0x00, + + /* Invalid request */ + ERROR_INVALID_REQUEST = 0x01, + + /* Bad/unsupported protocol version */ + ERROR_BAD_PROTOCOL_VERSION = 0x02, + + /* Unknown object queried */ + ERROR_OBJ_NOT_FOUND = 0x03, + + /* HELLO pushed an identity whose address is already claimed */ + ERROR_IDENTITY_COLLISION = 0x04, + + /* Verb or use case not supported/enabled by this node */ + ERROR_UNSUPPORTED_OPERATION = 0x05, + + /* Network membership certificate update needed */ + ERROR_NEED_MEMBERSHIP_CERTIFICATE = 0x06, + + /* Tried to join network, but you're not a member */ + ERROR_NETWORK_ACCESS_DENIED_ = 0x07, /* extra _ at end to avoid Windows name conflict */ + + /* Multicasts to this group are not wanted */ + ERROR_UNWANTED_MULTICAST = 0x08, + + /* Network requires external or 2FA authentication (e.g. SSO). */ + ERROR_NETWORK_AUTHENTICATION_REQUIRED = 0x09 + }; + + template Packet(const Buffer& b) : Buffer(b) + { + } + + Packet(const void* data, unsigned int len) : Buffer(data, len) + { + } + + /** + * Construct a new empty packet with a unique random packet ID + * + * Flags and hops will be zero. Other fields and data region are undefined. + * Use the header access methods (setDestination() and friends) to fill out + * the header. Payload should be appended; initial size is header size. + */ + Packet() : Buffer(ZT_PROTO_MIN_PACKET_LENGTH) + { + Utils::getSecureRandom(field(ZT_PACKET_IDX_IV, 8), 8); + (*this)[ZT_PACKET_IDX_FLAGS] = 0; // zero flags, cipher ID, and hops + } + + /** + * Make a copy of a packet with a new initialization vector and destination address + * + * This can be used to take one draft prototype packet and quickly make copies to + * encrypt for different destinations. + * + * @param prototype Prototype packet + * @param dest Destination ZeroTier address for new packet + */ + Packet(const Packet& prototype, const Address& dest) : Buffer(prototype) + { + Utils::getSecureRandom(field(ZT_PACKET_IDX_IV, 8), 8); + setDestination(dest); + } + + /** + * Construct a new empty packet with a unique random packet ID + * + * @param dest Destination ZT address + * @param source Source ZT address + * @param v Verb + */ + Packet(const Address& dest, const Address& source, const Verb v) : Buffer(ZT_PROTO_MIN_PACKET_LENGTH) + { + Utils::getSecureRandom(field(ZT_PACKET_IDX_IV, 8), 8); + setDestination(dest); + setSource(source); + (*this)[ZT_PACKET_IDX_FLAGS] = 0; // zero flags and hops + setVerb(v); + } + + /** + * Reset this packet structure for reuse in place + * + * @param dest Destination ZT address + * @param source Source ZT address + * @param v Verb + */ + inline void reset(const Address& dest, const Address& source, const Verb v) + { + setSize(ZT_PROTO_MIN_PACKET_LENGTH); + Utils::getSecureRandom(field(ZT_PACKET_IDX_IV, 8), 8); + setDestination(dest); + setSource(source); + (*this)[ZT_PACKET_IDX_FLAGS] = 0; // zero flags, cipher ID, and hops + setVerb(v); + } + + /** + * Generate a new IV / packet ID in place + * + * This can be used to re-use a packet buffer multiple times to send + * technically different but otherwise identical copies of the same + * packet. + */ + inline void newInitializationVector() + { + Utils::getSecureRandom(field(ZT_PACKET_IDX_IV, 8), 8); + } + + /** + * Set this packet's destination + * + * @param dest ZeroTier address of destination + */ + inline void setDestination(const Address& dest) + { + dest.copyTo(field(ZT_PACKET_IDX_DEST, ZT_ADDRESS_LENGTH), ZT_ADDRESS_LENGTH); + } + + /** + * Set this packet's source + * + * @param source ZeroTier address of source + */ + inline void setSource(const Address& source) + { + source.copyTo(field(ZT_PACKET_IDX_SOURCE, ZT_ADDRESS_LENGTH), ZT_ADDRESS_LENGTH); + } + + /** + * Get this packet's destination + * + * @return Destination ZT address + */ + inline Address destination() const + { + return Address(field(ZT_PACKET_IDX_DEST, ZT_ADDRESS_LENGTH), ZT_ADDRESS_LENGTH); + } + + /** + * Get this packet's source + * + * @return Source ZT address + */ + inline Address source() const + { + return Address(field(ZT_PACKET_IDX_SOURCE, ZT_ADDRESS_LENGTH), ZT_ADDRESS_LENGTH); + } + + /** + * @return True if packet is of valid length + */ + inline bool lengthValid() const + { + return (size() >= ZT_PROTO_MIN_PACKET_LENGTH); + } + + /** + * @return True if packet is fragmented (expect fragments) + */ + inline bool fragmented() const + { + return (((unsigned char)(*this)[ZT_PACKET_IDX_FLAGS] & ZT_PROTO_FLAG_FRAGMENTED) != 0); + } + + /** + * Set this packet's fragmented flag + * + * @param f Fragmented flag value + */ + inline void setFragmented(bool f) + { + if (f) { + (*this)[ZT_PACKET_IDX_FLAGS] |= (char)ZT_PROTO_FLAG_FRAGMENTED; + } + else { + (*this)[ZT_PACKET_IDX_FLAGS] &= (char)(~ZT_PROTO_FLAG_FRAGMENTED); + } + } + + /** + * @return True if packet is encrypted with an extra ephemeral key + */ + inline bool extendedArmor() const + { + return (((unsigned char)(*this)[ZT_PACKET_IDX_FLAGS] & ZT_PROTO_FLAG_EXTENDED_ARMOR) != 0); + } + + /** + * Set this packet's extended armor flag + * + * @param f Extended armor flag value + */ + inline void setExtendedArmor(bool f) + { + if (f) { + (*this)[ZT_PACKET_IDX_FLAGS] |= (char)ZT_PROTO_FLAG_EXTENDED_ARMOR; + } + else { + (*this)[ZT_PACKET_IDX_FLAGS] &= (char)(~ZT_PROTO_FLAG_EXTENDED_ARMOR); + } + } + + /** + * @return True if compressed (result only valid if unencrypted) + */ + inline bool compressed() const + { + return (((unsigned char)(*this)[ZT_PACKET_IDX_VERB] & ZT_PROTO_VERB_FLAG_COMPRESSED) != 0); + } + + /** + * @return ZeroTier forwarding hops (0 to 7) + */ + inline unsigned int hops() const + { + return ((unsigned int)(*this)[ZT_PACKET_IDX_FLAGS] & 0x07); + } + + /** + * Increment this packet's hop count + */ + inline void incrementHops() + { + unsigned char& b = (*this)[ZT_PACKET_IDX_FLAGS]; + b = (b & 0xf8) | ((b + 1) & 0x07); + } + + /** + * @return Cipher suite selector: 0 - 7 (see #defines) + */ + inline unsigned int cipher() const + { + return (((unsigned int)(*this)[ZT_PACKET_IDX_FLAGS] & 0x38) >> 3); + } + + /** + * @return Whether this packet is currently encrypted + */ + inline bool isEncrypted() const + { + return (cipher() == ZT_PROTO_CIPHER_SUITE__C25519_POLY1305_SALSA2012) || (cipher() == ZT_PROTO_CIPHER_SUITE__AES_GMAC_SIV); + } + + /** + * Set this packet's cipher suite + */ + inline void setCipher(unsigned int c) + { + unsigned char& b = (*this)[ZT_PACKET_IDX_FLAGS]; + b = (b & 0xc7) | (unsigned char)((c << 3) & 0x38); // bits: FFCCCHHH + } + + /** + * Get the trusted path ID for this packet (only meaningful if cipher is trusted path) + * + * @return Trusted path ID (from MAC field) + */ + inline uint64_t trustedPathId() const + { + return at(ZT_PACKET_IDX_MAC); + } + + /** + * Set this packet's trusted path ID and set the cipher spec to trusted path + * + * @param tpid Trusted path ID + */ + inline void setTrusted(const uint64_t tpid) + { + setCipher(ZT_PROTO_CIPHER_SUITE__NO_CRYPTO_TRUSTED_PATH); + setAt(ZT_PACKET_IDX_MAC, tpid); + } + + /** + * Get this packet's unique ID (the IV field interpreted as uint64_t) + * + * Note that the least significant 3 bits of this ID will change when armor() + * is called to armor the packet for transport. This is because armor() will + * mask the last 3 bits against the send counter for QoS monitoring use prior + * to actually using the IV to encrypt and MAC the packet. Be aware of this + * when grabbing the packetId of a new packet prior to armor/send. + * + * @return Packet ID + */ + inline uint64_t packetId() const + { + return at(ZT_PACKET_IDX_IV); + } + + /** + * Set packet verb + * + * This also has the side-effect of clearing any verb flags, such as + * compressed, and so must only be done during packet composition. + * + * @param v New packet verb + */ + inline void setVerb(Verb v) + { + (*this)[ZT_PACKET_IDX_VERB] = (char)v; + } + + /** + * @return Packet verb (not including flag bits) + */ + inline Verb verb() const + { + return (Verb)((*this)[ZT_PACKET_IDX_VERB] & 0x1f); + } + + /** + * @return Length of packet payload + */ + inline unsigned int payloadLength() const + { + return ((size() < ZT_PROTO_MIN_PACKET_LENGTH) ? 0 : (size() - ZT_PROTO_MIN_PACKET_LENGTH)); + } + + /** + * @return Raw packet payload + */ + inline const unsigned char* payload() const + { + return field(ZT_PACKET_IDX_PAYLOAD, size() - ZT_PACKET_IDX_PAYLOAD); + } + + /** + * Armor packet for transport + * + * @param key 32-byte key + * @param encryptPayload If true, encrypt packet payload, else just MAC + * @param extendedArmor Use an ephemeral key to encrypt payload (for encrypted HELLO) + * @param identity Identity of packet recipient/destination + * @param aesKeys If non-NULL these are the two keys for AES-GMAC-SIV + */ + void armor(const void* key, bool encryptPayload, bool extendedArmor, const AES aesKeys[2], const Identity& identity); + + /** + * Verify and (if encrypted) decrypt packet + * + * This does not handle trusted path mode packets and will return false + * for these. These are handled in IncomingPacket if the sending physical + * address and MAC field match a trusted path. + * + * @param key 32-byte key + * @param aesKeys If non-NULL these are the two keys for AES-GMAC-SIV + * @param identity Receiver's identity (must include secret) + * @return False if packet is invalid or failed MAC authenticity check + */ + bool dearmor(const void* key, const AES aesKeys[2], const Identity& identity); + + /** + * Encrypt/decrypt a separately armored portion of a packet + * + * This is currently only used to mask portions of HELLO as an extra + * security precaution since most of that message is sent in the clear. + * + * This must NEVER be used more than once in the same packet, as doing + * so will result in re-use of the same key stream. + * + * @param key 32-byte key + * @param start Start of encrypted portion + * @param len Length of encrypted portion + */ + void cryptField(const void* key, unsigned int start, unsigned int len); + + /** + * Attempt to compress payload if not already (must be unencrypted) + * + * This requires that the payload at least contain the verb byte already + * set. The compressed flag in the verb is set if compression successfully + * results in a size reduction. If no size reduction occurs, compression + * is not done and the flag is left cleared. + * + * @return True if compression occurred + */ + bool compress(); + + /** + * Attempt to decompress payload if it is compressed (must be unencrypted) + * + * If payload is compressed, it is decompressed and the compressed verb + * flag is cleared. Otherwise nothing is done and true is returned. + * + * @return True if data is now decompressed and valid, false on error + */ + bool uncompress(); + + private: + static const unsigned char ZERO_KEY[32]; + + /** + * Deterministically mangle a 256-bit crypto key based on packet + * + * This uses extra data from the packet to mangle the secret, giving us an + * effective IV that is somewhat more than 64 bits. This is "free" for + * Salsa20 since it has negligible key setup time so using a different + * key each time is fine. + * + * @param in Input key (32 bytes) + * @param out Output buffer (32 bytes) + */ + inline void _salsa20MangleKey(const unsigned char* in, unsigned char* out) const + { + const unsigned char* d = (const unsigned char*)data(); + + // IV and source/destination addresses. Using the addresses divides the + // key space into two halves-- A->B and B->A (since order will change). + for (unsigned int i = 0; i < 18; ++i) { // 8 + (ZT_ADDRESS_LENGTH * 2) == 18 + out[i] = in[i] ^ d[i]; + } + + // Flags, but with hop count masked off. Hop count is altered by forwarding + // nodes. It's one of the only parts of a packet modifiable by people + // without the key. + out[18] = in[18] ^ (d[ZT_PACKET_IDX_FLAGS] & 0xf8); + + // Raw packet size in bytes -- thus each packet size defines a new + // key space. + out[19] = in[19] ^ (unsigned char)(size() & 0xff); + out[20] = in[20] ^ (unsigned char)((size() >> 8) & 0xff); // little endian + + // Rest of raw key is used unchanged + for (unsigned int i = 21; i < 32; ++i) { + out[i] = in[i]; + } + } }; -} // namespace ZeroTier +} // namespace ZeroTier #endif diff --git a/node/PacketMultiplexer.cpp b/node/PacketMultiplexer.cpp index a1dc835a..5ad08795 100644 --- a/node/PacketMultiplexer.cpp +++ b/node/PacketMultiplexer.cpp @@ -13,9 +13,9 @@ #include "PacketMultiplexer.hpp" +#include "Constants.hpp" #include "Node.hpp" #include "RuntimeEnvironment.hpp" -#include "Constants.hpp" #include #include @@ -24,99 +24,99 @@ namespace ZeroTier { PacketMultiplexer::PacketMultiplexer(const RuntimeEnvironment* renv) { - RR = renv; + RR = renv; }; void PacketMultiplexer::putFrame(void* tPtr, uint64_t nwid, void** nuptr, const MAC& source, const MAC& dest, unsigned int etherType, unsigned int vlanId, const void* data, unsigned int len, unsigned int flowId) { #if defined(__APPLE__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__WINDOWS__) - RR->node->putFrame(tPtr,nwid,nuptr,source,dest,etherType,vlanId,(const void *)data,len); - return; + RR->node->putFrame(tPtr, nwid, nuptr, source, dest, etherType, vlanId, (const void*)data, len); + return; #endif - if (!_enabled) { - RR->node->putFrame(tPtr,nwid,nuptr,source,dest,etherType,vlanId,(const void *)data,len); - return; - } + if (! _enabled) { + RR->node->putFrame(tPtr, nwid, nuptr, source, dest, etherType, vlanId, (const void*)data, len); + return; + } - PacketRecord* packet; - _rxPacketVector_m.lock(); - if (_rxPacketVector.empty()) { - packet = new PacketRecord; - } - else { - packet = _rxPacketVector.back(); - _rxPacketVector.pop_back(); - } - _rxPacketVector_m.unlock(); + PacketRecord* packet; + _rxPacketVector_m.lock(); + if (_rxPacketVector.empty()) { + packet = new PacketRecord; + } + else { + packet = _rxPacketVector.back(); + _rxPacketVector.pop_back(); + } + _rxPacketVector_m.unlock(); - packet->tPtr = tPtr; - packet->nwid = nwid; - packet->nuptr = nuptr; - packet->source = source.toInt(); - packet->dest = dest.toInt(); - packet->etherType = etherType; - packet->vlanId = vlanId; - packet->len = len; - packet->flowId = flowId; - memcpy(packet->data, data, len); + packet->tPtr = tPtr; + packet->nwid = nwid; + packet->nuptr = nuptr; + packet->source = source.toInt(); + packet->dest = dest.toInt(); + packet->etherType = etherType; + packet->vlanId = vlanId; + packet->len = len; + packet->flowId = flowId; + memcpy(packet->data, data, len); - int bucket = flowId % _concurrency; - _rxPacketQueues[bucket]->postLimit(packet, 2048); + int bucket = flowId % _concurrency; + _rxPacketQueues[bucket]->postLimit(packet, 2048); } void PacketMultiplexer::setUpPostDecodeReceiveThreads(unsigned int concurrency, bool cpuPinningEnabled) { #if defined(__APPLE__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__WINDOWS__) - return; + return; #endif - _enabled = true; - _concurrency = concurrency; - bool _enablePinning = cpuPinningEnabled; + _enabled = true; + _concurrency = concurrency; + bool _enablePinning = cpuPinningEnabled; - for (unsigned int i = 0; i < _concurrency; ++i) { - fprintf(stderr, "Reserved queue for thread %d\n", i); - _rxPacketQueues.push_back(new BlockingQueue()); - } + for (unsigned int i = 0; i < _concurrency; ++i) { + fprintf(stderr, "Reserved queue for thread %d\n", i); + _rxPacketQueues.push_back(new BlockingQueue()); + } - // Each thread picks from its own queue to feed into the core - for (unsigned int i = 0; i < _concurrency; ++i) { - _rxThreads.push_back(std::thread([this, i, _enablePinning]() { - fprintf(stderr, "Created post-decode packet ingestion thread %d\n", i); + // Each thread picks from its own queue to feed into the core + for (unsigned int i = 0; i < _concurrency; ++i) { + _rxThreads.push_back(std::thread([this, i, _enablePinning]() { + fprintf(stderr, "Created post-decode packet ingestion thread %d\n", i); - PacketRecord* packet = nullptr; - for (;;) { - if (! _rxPacketQueues[i]->get(packet)) { - break; - } - if (! packet) { - break; - } + PacketRecord* packet = nullptr; + for (;;) { + if (! _rxPacketQueues[i]->get(packet)) { + break; + } + if (! packet) { + break; + } - // fprintf(stderr, "popped packet from queue %d\n", i); + // fprintf(stderr, "popped packet from queue %d\n", i); - MAC sourceMac = MAC(packet->source); - MAC destMac = MAC(packet->dest); + MAC sourceMac = MAC(packet->source); + MAC destMac = MAC(packet->dest); - RR->node->putFrame(packet->tPtr, packet->nwid, packet->nuptr, sourceMac, destMac, packet->etherType, 0, (const void*)packet->data, packet->len); - { - Mutex::Lock l(_rxPacketVector_m); - _rxPacketVector.push_back(packet); - } - /* - if (ZT_ResultCode_isFatal(err)) { - char tmp[256]; - OSUtils::ztsnprintf(tmp, sizeof(tmp), "error processing packet: %d", (int)err); - Mutex::Lock _l(_termReason_m); - _termReason = ONE_UNRECOVERABLE_ERROR; - _fatalErrorMessage = tmp; - this->terminate(); - break; - } - */ - } - })); - } + RR->node->putFrame(packet->tPtr, packet->nwid, packet->nuptr, sourceMac, destMac, packet->etherType, 0, (const void*)packet->data, packet->len); + { + Mutex::Lock l(_rxPacketVector_m); + _rxPacketVector.push_back(packet); + } + /* + if (ZT_ResultCode_isFatal(err)) { + char tmp[256]; + OSUtils::ztsnprintf(tmp, sizeof(tmp), "error processing packet: %d", (int)err); + Mutex::Lock _l(_termReason_m); + _termReason = ONE_UNRECOVERABLE_ERROR; + _fatalErrorMessage = tmp; + this->terminate(); + break; + } + */ + } + })); + } } -} // namespace ZeroTier \ No newline at end of file +} // namespace ZeroTier \ No newline at end of file diff --git a/node/PacketMultiplexer.hpp b/node/PacketMultiplexer.hpp index 4753180e..4a7317d4 100644 --- a/node/PacketMultiplexer.hpp +++ b/node/PacketMultiplexer.hpp @@ -25,41 +25,41 @@ namespace ZeroTier { struct PacketRecord { - void* tPtr; - uint64_t nwid; - void** nuptr; - uint64_t source; - uint64_t dest; - unsigned int etherType; - unsigned int vlanId; - uint8_t data[ZT_MAX_MTU]; - unsigned int len; - unsigned int flowId; + void* tPtr; + uint64_t nwid; + void** nuptr; + uint64_t source; + uint64_t dest; + unsigned int etherType; + unsigned int vlanId; + uint8_t data[ZT_MAX_MTU]; + unsigned int len; + unsigned int flowId; }; class PacketMultiplexer { public: - const RuntimeEnvironment* RR; + const RuntimeEnvironment* RR; - PacketMultiplexer(const RuntimeEnvironment* renv); + PacketMultiplexer(const RuntimeEnvironment* renv); - void setUpPostDecodeReceiveThreads(unsigned int concurrency, bool cpuPinningEnabled); + void setUpPostDecodeReceiveThreads(unsigned int concurrency, bool cpuPinningEnabled); - void putFrame(void* tPtr, uint64_t nwid, void** nuptr, const MAC& source, const MAC& dest, unsigned int etherType, unsigned int vlanId, const void* data, unsigned int len, unsigned int flowId); + void putFrame(void* tPtr, uint64_t nwid, void** nuptr, const MAC& source, const MAC& dest, unsigned int etherType, unsigned int vlanId, const void* data, unsigned int len, unsigned int flowId); - std::vector*> _rxPacketQueues; + std::vector*> _rxPacketQueues; - unsigned int _concurrency; - // pool - std::vector _rxPacketVector; - std::vector _rxPacketThreads; - Mutex _rxPacketVector_m, _rxPacketThreads_m; + unsigned int _concurrency; + // pool + std::vector _rxPacketVector; + std::vector _rxPacketThreads; + Mutex _rxPacketVector_m, _rxPacketThreads_m; - std::vector _rxThreads; - unsigned int _rxThreadCount; - bool _enabled; + std::vector _rxThreads; + unsigned int _rxThreadCount; + bool _enabled; }; -} // namespace ZeroTier +} // namespace ZeroTier -#endif // ZT_PACKET_MULTIPLEXER_HPP \ No newline at end of file +#endif // ZT_PACKET_MULTIPLEXER_HPP \ No newline at end of file diff --git a/node/Path.cpp b/node/Path.cpp index 00ea90f9..4d03deb4 100644 --- a/node/Path.cpp +++ b/node/Path.cpp @@ -12,18 +12,19 @@ /****/ #include "Path.hpp" -#include "RuntimeEnvironment.hpp" + #include "Node.hpp" +#include "RuntimeEnvironment.hpp" namespace ZeroTier { -bool Path::send(const RuntimeEnvironment *RR,void *tPtr,const void *data,unsigned int len,int64_t now) +bool Path::send(const RuntimeEnvironment* RR, void* tPtr, const void* data, unsigned int len, int64_t now) { - if (RR->node->putPacket(tPtr,_localSocket,_addr,data,len)) { - _lastOut = now; - return true; - } - return false; + if (RR->node->putPacket(tPtr, _localSocket, _addr, data, len)) { + _lastOut = now; + return true; + } + return false; } -} // namespace ZeroTier +} // namespace ZeroTier diff --git a/node/Path.hpp b/node/Path.hpp index d6167ce8..a363f6a9 100644 --- a/node/Path.hpp +++ b/node/Path.hpp @@ -14,20 +14,19 @@ #ifndef ZT_PATH_HPP #define ZT_PATH_HPP -#include -#include -#include - -#include -#include - +#include "AtomicCounter.hpp" #include "Constants.hpp" #include "InetAddress.hpp" -#include "SharedPtr.hpp" -#include "AtomicCounter.hpp" -#include "Utils.hpp" #include "Packet.hpp" #include "RingBuffer.hpp" +#include "SharedPtr.hpp" +#include "Utils.hpp" + +#include +#include +#include +#include +#include /** * Maximum return value of preferenceRank() @@ -41,368 +40,455 @@ class RuntimeEnvironment; /** * A path across the physical network */ -class Path -{ - friend class SharedPtr; - friend class Bond; +class Path { + friend class SharedPtr; + friend class Bond; -public: - /** - * Efficient unique key for paths in a Hashtable - */ - class HashKey - { - public: - HashKey() {} + public: + /** + * Efficient unique key for paths in a Hashtable + */ + class HashKey { + public: + HashKey() + { + } - HashKey(const int64_t l,const InetAddress &r) - { - if (r.ss_family == AF_INET) { - _k[0] = (uint64_t)reinterpret_cast(&r)->sin_addr.s_addr; - _k[1] = (uint64_t)reinterpret_cast(&r)->sin_port; - _k[2] = (uint64_t)l; - } else if (r.ss_family == AF_INET6) { - memcpy(_k,reinterpret_cast(&r)->sin6_addr.s6_addr,16); - _k[2] = ((uint64_t)reinterpret_cast(&r)->sin6_port << 32) ^ (uint64_t)l; - } else { - memcpy(_k,&r,std::min(sizeof(_k),sizeof(InetAddress))); - _k[2] += (uint64_t)l; - } - } + HashKey(const int64_t l, const InetAddress& r) + { + if (r.ss_family == AF_INET) { + _k[0] = (uint64_t)reinterpret_cast(&r)->sin_addr.s_addr; + _k[1] = (uint64_t)reinterpret_cast(&r)->sin_port; + _k[2] = (uint64_t)l; + } + else if (r.ss_family == AF_INET6) { + memcpy(_k, reinterpret_cast(&r)->sin6_addr.s6_addr, 16); + _k[2] = ((uint64_t)reinterpret_cast(&r)->sin6_port << 32) ^ (uint64_t)l; + } + else { + memcpy(_k, &r, std::min(sizeof(_k), sizeof(InetAddress))); + _k[2] += (uint64_t)l; + } + } - inline unsigned long hashCode() const { return (unsigned long)(_k[0] + _k[1] + _k[2]); } + inline unsigned long hashCode() const + { + return (unsigned long)(_k[0] + _k[1] + _k[2]); + } - inline bool operator==(const HashKey &k) const { return ( (_k[0] == k._k[0]) && (_k[1] == k._k[1]) && (_k[2] == k._k[2]) ); } - inline bool operator!=(const HashKey &k) const { return (!(*this == k)); } + inline bool operator==(const HashKey& k) const + { + return ((_k[0] == k._k[0]) && (_k[1] == k._k[1]) && (_k[2] == k._k[2])); + } + inline bool operator!=(const HashKey& k) const + { + return (! (*this == k)); + } - private: - uint64_t _k[3]; - }; + private: + uint64_t _k[3]; + }; - Path() : - _lastOut(0), - _lastIn(0), - _lastTrustEstablishedPacketReceived(0), - _lastEchoRequestReceived(0), - _localPort(0), - _localSocket(-1), - _latencyMean(0.0), - _latencyVariance(0.0), - _packetLossRatio(0.0), - _packetErrorRatio(0.0), - _assignedFlowCount(0), - _valid(true), - _eligible(false), - _bonded(false), - _mtu(0), - _givenLinkSpeed(0), - _relativeQuality(0), - _latency(0xffff), - _addr(), - _ipScope(InetAddress::IP_SCOPE_NONE) - {} + Path() + : _lastOut(0) + , _lastIn(0) + , _lastTrustEstablishedPacketReceived(0) + , _lastEchoRequestReceived(0) + , _localPort(0) + , _localSocket(-1) + , _latencyMean(0.0) + , _latencyVariance(0.0) + , _packetLossRatio(0.0) + , _packetErrorRatio(0.0) + , _assignedFlowCount(0) + , _valid(true) + , _eligible(false) + , _bonded(false) + , _mtu(0) + , _givenLinkSpeed(0) + , _relativeQuality(0) + , _latency(0xffff) + , _addr() + , _ipScope(InetAddress::IP_SCOPE_NONE) + { + } - Path(const int64_t localSocket,const InetAddress &addr) : - _lastOut(0), - _lastIn(0), - _lastTrustEstablishedPacketReceived(0), - _lastEchoRequestReceived(0), - _localPort(0), - _localSocket(localSocket), - _latencyMean(0.0), - _latencyVariance(0.0), - _packetLossRatio(0.0), - _packetErrorRatio(0.0), - _assignedFlowCount(0), - _valid(true), - _eligible(false), - _bonded(false), - _mtu(0), - _givenLinkSpeed(0), - _relativeQuality(0), - _latency(0xffff), - _addr(addr), - _ipScope(addr.ipScope()) - {} + Path(const int64_t localSocket, const InetAddress& addr) + : _lastOut(0) + , _lastIn(0) + , _lastTrustEstablishedPacketReceived(0) + , _lastEchoRequestReceived(0) + , _localPort(0) + , _localSocket(localSocket) + , _latencyMean(0.0) + , _latencyVariance(0.0) + , _packetLossRatio(0.0) + , _packetErrorRatio(0.0) + , _assignedFlowCount(0) + , _valid(true) + , _eligible(false) + , _bonded(false) + , _mtu(0) + , _givenLinkSpeed(0) + , _relativeQuality(0) + , _latency(0xffff) + , _addr(addr) + , _ipScope(addr.ipScope()) + { + } - /** - * Called when a packet is received from this remote path, regardless of content - * - * @param t Time of receive - */ - inline void received(const uint64_t t) - { - _lastIn = t; - } + /** + * Called when a packet is received from this remote path, regardless of content + * + * @param t Time of receive + */ + inline void received(const uint64_t t) + { + _lastIn = t; + } - /** - * Set time last trusted packet was received (done in Peer::received()) - */ - inline void trustedPacketReceived(const uint64_t t) { _lastTrustEstablishedPacketReceived = t; } + /** + * Set time last trusted packet was received (done in Peer::received()) + */ + inline void trustedPacketReceived(const uint64_t t) + { + _lastTrustEstablishedPacketReceived = t; + } - /** - * Send a packet via this path (last out time is also updated) - * - * @param RR Runtime environment - * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call - * @param data Packet data - * @param len Packet length - * @param now Current time - * @return True if transport reported success - */ - bool send(const RuntimeEnvironment *RR,void *tPtr,const void *data,unsigned int len,int64_t now); + /** + * Send a packet via this path (last out time is also updated) + * + * @param RR Runtime environment + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call + * @param data Packet data + * @param len Packet length + * @param now Current time + * @return True if transport reported success + */ + bool send(const RuntimeEnvironment* RR, void* tPtr, const void* data, unsigned int len, int64_t now); - /** - * Manually update last sent time - * - * @param t Time of send - */ - inline void sent(const int64_t t) { _lastOut = t; } + /** + * Manually update last sent time + * + * @param t Time of send + */ + inline void sent(const int64_t t) + { + _lastOut = t; + } - /** - * Update path latency with a new measurement - * - * @param l Measured latency - */ - inline void updateLatency(const unsigned int l, int64_t now) - { - unsigned int pl = _latency; - if (pl < 0xffff) { - _latency = (pl + l) / 2; - } else { - _latency = l; - } - } + /** + * Update path latency with a new measurement + * + * @param l Measured latency + */ + inline void updateLatency(const unsigned int l, int64_t now) + { + unsigned int pl = _latency; + if (pl < 0xffff) { + _latency = (pl + l) / 2; + } + else { + _latency = l; + } + } - /** - * @return Local socket as specified by external code - */ - inline int64_t localSocket() const { return _localSocket; } + /** + * @return Local socket as specified by external code + */ + inline int64_t localSocket() const + { + return _localSocket; + } - /** - * @return Local port corresponding to the localSocket - */ - inline int64_t localPort() const { return _localPort; } + /** + * @return Local port corresponding to the localSocket + */ + inline int64_t localPort() const + { + return _localPort; + } - /** - * @return Physical address - */ - inline const InetAddress &address() const { return _addr; } + /** + * @return Physical address + */ + inline const InetAddress& address() const + { + return _addr; + } - /** - * @return IP scope -- faster shortcut for address().ipScope() - */ - inline InetAddress::IpScope ipScope() const { return _ipScope; } + /** + * @return IP scope -- faster shortcut for address().ipScope() + */ + inline InetAddress::IpScope ipScope() const + { + return _ipScope; + } - /** - * @return True if path has received a trust established packet (e.g. common network membership) in the past ZT_TRUST_EXPIRATION ms - */ - inline bool trustEstablished(const int64_t now) const { return ((now - _lastTrustEstablishedPacketReceived) < ZT_TRUST_EXPIRATION); } + /** + * @return True if path has received a trust established packet (e.g. common network membership) in the past ZT_TRUST_EXPIRATION ms + */ + inline bool trustEstablished(const int64_t now) const + { + return ((now - _lastTrustEstablishedPacketReceived) < ZT_TRUST_EXPIRATION); + } - /** - * @return Preference rank, higher == better - */ - inline unsigned int preferenceRank() const - { - // This causes us to rank paths in order of IP scope rank (see InetAddress.hpp) but - // within each IP scope class to prefer IPv6 over IPv4. - return ( ((unsigned int)_ipScope << 1) | (unsigned int)(_addr.ss_family == AF_INET6) ); - } + /** + * @return Preference rank, higher == better + */ + inline unsigned int preferenceRank() const + { + // This causes us to rank paths in order of IP scope rank (see InetAddress.hpp) but + // within each IP scope class to prefer IPv6 over IPv4. + return (((unsigned int)_ipScope << 1) | (unsigned int)(_addr.ss_family == AF_INET6)); + } - /** - * Check whether this address is valid for a ZeroTier path - * - * This checks the address type and scope against address types and scopes - * that we currently support for ZeroTier communication. - * - * @param a Address to check - * @return True if address is good for ZeroTier path use - */ - static inline bool isAddressValidForPath(const InetAddress &a) - { - if ((a.ss_family == AF_INET)||(a.ss_family == AF_INET6)) { - switch(a.ipScope()) { - /* Note: we don't do link-local at the moment. Unfortunately these - * cause several issues. The first is that they usually require a - * device qualifier, which we don't handle yet and can't portably - * push in PUSH_DIRECT_PATHS. The second is that some OSes assign - * these very ephemerally or otherwise strangely. So we'll use - * private, pseudo-private, shared (e.g. carrier grade NAT), or - * global IP addresses. */ - case InetAddress::IP_SCOPE_PRIVATE: - case InetAddress::IP_SCOPE_PSEUDOPRIVATE: - case InetAddress::IP_SCOPE_SHARED: - case InetAddress::IP_SCOPE_GLOBAL: - if (a.ss_family == AF_INET6) { - // TEMPORARY HACK: for now, we are going to blacklist he.net IPv6 - // tunnels due to very spotty performance and low MTU issues over - // these IPv6 tunnel links. - const uint8_t *ipd = reinterpret_cast(reinterpret_cast(&a)->sin6_addr.s6_addr); - if ((ipd[0] == 0x20)&&(ipd[1] == 0x01)&&(ipd[2] == 0x04)&&(ipd[3] == 0x70)) { - return false; - } - } - return true; - default: - return false; - } - } - return false; - } + /** + * Check whether this address is valid for a ZeroTier path + * + * This checks the address type and scope against address types and scopes + * that we currently support for ZeroTier communication. + * + * @param a Address to check + * @return True if address is good for ZeroTier path use + */ + static inline bool isAddressValidForPath(const InetAddress& a) + { + if ((a.ss_family == AF_INET) || (a.ss_family == AF_INET6)) { + switch (a.ipScope()) { + /* Note: we don't do link-local at the moment. Unfortunately these + * cause several issues. The first is that they usually require a + * device qualifier, which we don't handle yet and can't portably + * push in PUSH_DIRECT_PATHS. The second is that some OSes assign + * these very ephemerally or otherwise strangely. So we'll use + * private, pseudo-private, shared (e.g. carrier grade NAT), or + * global IP addresses. */ + case InetAddress::IP_SCOPE_PRIVATE: + case InetAddress::IP_SCOPE_PSEUDOPRIVATE: + case InetAddress::IP_SCOPE_SHARED: + case InetAddress::IP_SCOPE_GLOBAL: + if (a.ss_family == AF_INET6) { + // TEMPORARY HACK: for now, we are going to blacklist he.net IPv6 + // tunnels due to very spotty performance and low MTU issues over + // these IPv6 tunnel links. + const uint8_t* ipd = reinterpret_cast(reinterpret_cast(&a)->sin6_addr.s6_addr); + if ((ipd[0] == 0x20) && (ipd[1] == 0x01) && (ipd[2] == 0x04) && (ipd[3] == 0x70)) { + return false; + } + } + return true; + default: + return false; + } + } + return false; + } - /** - * @return Latency or 0xffff if unknown - */ - inline unsigned int latency() const { return _latency; } + /** + * @return Latency or 0xffff if unknown + */ + inline unsigned int latency() const + { + return _latency; + } - /** - * @return Path quality -- lower is better - */ - inline long quality(const int64_t now) const - { - const int l = (long)_latency; - const int age = (long)std::min((now - _lastIn),(int64_t)(ZT_PATH_HEARTBEAT_PERIOD * 10)); // set an upper sanity limit to avoid overflow - return (((age < (ZT_PATH_HEARTBEAT_PERIOD + 5000)) ? l : (l + 0xffff + age)) * (long)((ZT_INETADDRESS_MAX_SCOPE - _ipScope) + 1)); - } + /** + * @return Path quality -- lower is better + */ + inline long quality(const int64_t now) const + { + const int l = (long)_latency; + const int age = (long)std::min((now - _lastIn), (int64_t)(ZT_PATH_HEARTBEAT_PERIOD * 10)); // set an upper sanity limit to avoid overflow + return (((age < (ZT_PATH_HEARTBEAT_PERIOD + 5000)) ? l : (l + 0xffff + age)) * (long)((ZT_INETADDRESS_MAX_SCOPE - _ipScope) + 1)); + } - /** - * @return True if this path is alive (receiving heartbeats) - */ - inline bool alive(const int64_t now) const { - return (now - _lastIn) < (ZT_PATH_HEARTBEAT_PERIOD + 5000); - } + /** + * @return True if this path is alive (receiving heartbeats) + */ + inline bool alive(const int64_t now) const + { + return (now - _lastIn) < (ZT_PATH_HEARTBEAT_PERIOD + 5000); + } - /** - * @return True if this path needs a heartbeat - */ - inline bool needsHeartbeat(const int64_t now) const { return ((now - _lastOut) >= ZT_PATH_HEARTBEAT_PERIOD); } + /** + * @return True if this path needs a heartbeat + */ + inline bool needsHeartbeat(const int64_t now) const + { + return ((now - _lastOut) >= ZT_PATH_HEARTBEAT_PERIOD); + } - /** - * @return Last time we sent something - */ - inline int64_t lastOut() const { return _lastOut; } + /** + * @return Last time we sent something + */ + inline int64_t lastOut() const + { + return _lastOut; + } - /** - * @return Last time we received anything - */ - inline int64_t lastIn() const { return _lastIn; } + /** + * @return Last time we received anything + */ + inline int64_t lastIn() const + { + return _lastIn; + } - /** - * @return the age of the path in terms of receiving packets - */ - inline int64_t age(int64_t now) { return (now - _lastIn); } + /** + * @return the age of the path in terms of receiving packets + */ + inline int64_t age(int64_t now) + { + return (now - _lastIn); + } - /** - * @return Time last trust-established packet was received - */ - inline int64_t lastTrustEstablishedPacketReceived() const { return _lastTrustEstablishedPacketReceived; } + /** + * @return Time last trust-established packet was received + */ + inline int64_t lastTrustEstablishedPacketReceived() const + { + return _lastTrustEstablishedPacketReceived; + } - /** - * Rate limit gate for inbound ECHO requests - */ - inline bool rateGateEchoRequest(const int64_t now) - { - if ((now - _lastEchoRequestReceived) >= (ZT_PEER_GENERAL_RATE_LIMIT / 6)) { - _lastEchoRequestReceived = now; - return true; - } - return false; - } + /** + * Rate limit gate for inbound ECHO requests + */ + inline bool rateGateEchoRequest(const int64_t now) + { + if ((now - _lastEchoRequestReceived) >= (ZT_PEER_GENERAL_RATE_LIMIT / 6)) { + _lastEchoRequestReceived = now; + return true; + } + return false; + } - /** - * @return Mean latency as reported by the bonding layer - */ - inline float latencyMean() const { return _latencyMean; } + /** + * @return Mean latency as reported by the bonding layer + */ + inline float latencyMean() const + { + return _latencyMean; + } - /** - * @return Latency variance as reported by the bonding layer - */ - inline float latencyVariance() const { return _latencyVariance; } + /** + * @return Latency variance as reported by the bonding layer + */ + inline float latencyVariance() const + { + return _latencyVariance; + } - /** - * @return Packet Loss Ratio as reported by the bonding layer - */ - inline float packetLossRatio() const { return _packetLossRatio; } + /** + * @return Packet Loss Ratio as reported by the bonding layer + */ + inline float packetLossRatio() const + { + return _packetLossRatio; + } - /** - * @return Packet Error Ratio as reported by the bonding layer - */ - inline float packetErrorRatio() const { return _packetErrorRatio; } + /** + * @return Packet Error Ratio as reported by the bonding layer + */ + inline float packetErrorRatio() const + { + return _packetErrorRatio; + } - /** - * @return Number of flows assigned to this path - */ - inline unsigned int assignedFlowCount() const { return _assignedFlowCount; } + /** + * @return Number of flows assigned to this path + */ + inline unsigned int assignedFlowCount() const + { + return _assignedFlowCount; + } - /** - * @return Whether this path is valid as reported by the bonding layer. The bonding layer - * actually checks with Phy to see if the interface is still up - */ - inline bool valid() const { return _valid; } + /** + * @return Whether this path is valid as reported by the bonding layer. The bonding layer + * actually checks with Phy to see if the interface is still up + */ + inline bool valid() const + { + return _valid; + } - /** - * @return Whether this path is eligible for use in a bond as reported by the bonding layer - */ - inline bool eligible() const { return _eligible; } + /** + * @return Whether this path is eligible for use in a bond as reported by the bonding layer + */ + inline bool eligible() const + { + return _eligible; + } - /** - * @return Whether this path is bonded as reported by the bonding layer - */ - inline bool bonded() const { return _bonded; } + /** + * @return Whether this path is bonded as reported by the bonding layer + */ + inline bool bonded() const + { + return _bonded; + } - /** - * @return Whether the user-specified MTU for this path (determined by MTU for parent link) - */ - inline uint16_t mtu() const { return _mtu; } + /** + * @return Whether the user-specified MTU for this path (determined by MTU for parent link) + */ + inline uint16_t mtu() const + { + return _mtu; + } - /** - * @return Given link capacity as reported by the bonding layer - */ - inline uint32_t givenLinkSpeed() const { return _givenLinkSpeed; } + /** + * @return Given link capacity as reported by the bonding layer + */ + inline uint32_t givenLinkSpeed() const + { + return _givenLinkSpeed; + } - /** - * @return Path's quality as reported by the bonding layer - */ - inline float relativeQuality() const { return _relativeQuality; } + /** + * @return Path's quality as reported by the bonding layer + */ + inline float relativeQuality() const + { + return _relativeQuality; + } - /** - * @return Physical interface name that this path lives on - */ - char *ifname() { - return _ifname; - } + /** + * @return Physical interface name that this path lives on + */ + char* ifname() + { + return _ifname; + } -private: + private: + char _ifname[ZT_MAX_PHYSIFNAME] = {}; - char _ifname[ZT_MAX_PHYSIFNAME] = { }; + volatile int64_t _lastOut; + volatile int64_t _lastIn; + volatile int64_t _lastTrustEstablishedPacketReceived; - volatile int64_t _lastOut; - volatile int64_t _lastIn; - volatile int64_t _lastTrustEstablishedPacketReceived; + int64_t _lastEchoRequestReceived; - int64_t _lastEchoRequestReceived; + uint16_t _localPort; + int64_t _localSocket; - uint16_t _localPort; - int64_t _localSocket; + volatile float _latencyMean; + volatile float _latencyVariance; + volatile float _packetLossRatio; + volatile float _packetErrorRatio; + volatile uint16_t _assignedFlowCount; + volatile bool _valid; + volatile bool _eligible; + volatile bool _bonded; + volatile uint16_t _mtu; + volatile uint32_t _givenLinkSpeed; + volatile float _relativeQuality; - volatile float _latencyMean; - volatile float _latencyVariance; - volatile float _packetLossRatio; - volatile float _packetErrorRatio; - volatile uint16_t _assignedFlowCount; - volatile bool _valid; - volatile bool _eligible; - volatile bool _bonded; - volatile uint16_t _mtu; - volatile uint32_t _givenLinkSpeed; - volatile float _relativeQuality; - - volatile unsigned int _latency; - InetAddress _addr; - InetAddress::IpScope _ipScope; // memoize this since it's a computed value checked often - AtomicCounter __refCount; + volatile unsigned int _latency; + InetAddress _addr; + InetAddress::IpScope _ipScope; // memoize this since it's a computed value checked often + AtomicCounter __refCount; }; -} // namespace ZeroTier +} // namespace ZeroTier #endif diff --git a/node/Peer.cpp b/node/Peer.cpp index f77b4e6f..872be568 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -11,692 +11,710 @@ */ /****/ +#include "Peer.hpp" + #include "../version.h" #include "Constants.hpp" -#include "Peer.hpp" -#include "Switch.hpp" -#include "Network.hpp" -#include "SelfAwareness.hpp" -#include "Packet.hpp" -#include "Trace.hpp" +#include "Identity.hpp" #include "InetAddress.hpp" -#include "RingBuffer.hpp" -#include "Utils.hpp" #include "Metrics.hpp" +#include "Network.hpp" +#include "Packet.hpp" +#include "RingBuffer.hpp" +#include "SelfAwareness.hpp" +#include "Switch.hpp" +#include "Trace.hpp" +#include "Utils.hpp" +#include "Switch.hpp" namespace ZeroTier { static unsigned char s_freeRandomByteCounter = 0; -Peer::Peer(const RuntimeEnvironment *renv,const Identity &myIdentity,const Identity &peerIdentity) - : RR(renv) - , _lastReceive(0) - , _lastNontrivialReceive(0) - , _lastTriedMemorizedPath(0) - , _lastDirectPathPushSent(0) - , _lastDirectPathPushReceive(0) - , _lastCredentialRequestSent(0) - , _lastWhoisRequestReceived(0) - , _lastCredentialsReceived(0) - , _lastTrustEstablishedPacketReceived(0) - , _lastSentFullHello(0) - , _lastEchoCheck(0) - , _freeRandomByte((unsigned char)((uintptr_t)this >> 4) ^ ++s_freeRandomByteCounter) - , _vProto(0) - , _vMajor(0) - , _vMinor(0) - , _vRevision(0) - , _id(peerIdentity) - , _directPathPushCutoffCount(0) - , _echoRequestCutoffCount(0) - , _localMultipathSupported(false) - , _lastComputedAggregateMeanLatency(0) +Peer::Peer(const RuntimeEnvironment* renv, const Identity& myIdentity, const Identity& peerIdentity) + : RR(renv) + , _lastReceive(0) + , _lastNontrivialReceive(0) + , _lastTriedMemorizedPath(0) + , _lastDirectPathPushSent(0) + , _lastDirectPathPushReceive(0) + , _lastCredentialRequestSent(0) + , _lastWhoisRequestReceived(0) + , _lastCredentialsReceived(0) + , _lastTrustEstablishedPacketReceived(0) + , _lastSentFullHello(0) + , _lastEchoCheck(0) + , _freeRandomByte((unsigned char)((uintptr_t)this >> 4) ^ ++s_freeRandomByteCounter) + , _vProto(0) + , _vMajor(0) + , _vMinor(0) + , _vRevision(0) + , _id(peerIdentity) + , _directPathPushCutoffCount(0) + , _echoRequestCutoffCount(0) + , _localMultipathSupported(false) + , _lastComputedAggregateMeanLatency(0) #ifndef ZT_NO_PEER_METRICS - , _peer_latency{Metrics::peer_latency.Add({{"node_id", OSUtils::nodeIDStr(peerIdentity.address().toInt())}}, std::vector{1,3,6,10,30,60,100,300,600,1000})} - , _alive_path_count{Metrics::peer_path_count.Add({{"node_id", OSUtils::nodeIDStr(peerIdentity.address().toInt())},{"status","alive"}})} - , _dead_path_count{Metrics::peer_path_count.Add({{"node_id", OSUtils::nodeIDStr(peerIdentity.address().toInt())},{"status","dead"}})} - , _incoming_packet{Metrics::peer_packets.Add({{"direction", "rx"},{"node_id", OSUtils::nodeIDStr(peerIdentity.address().toInt())}})} - , _outgoing_packet{Metrics::peer_packets.Add({{"direction", "tx"},{"node_id", OSUtils::nodeIDStr(peerIdentity.address().toInt())}})} - , _packet_errors{Metrics::peer_packet_errors.Add({{"node_id", OSUtils::nodeIDStr(peerIdentity.address().toInt())}})} + , _peer_latency { Metrics::peer_latency.Add({ { "node_id", OSUtils::nodeIDStr(peerIdentity.address().toInt()) } }, std::vector { 1, 3, 6, 10, 30, 60, 100, 300, 600, 1000 }) } + , _alive_path_count { Metrics::peer_path_count.Add({ { "node_id", OSUtils::nodeIDStr(peerIdentity.address().toInt()) }, { "status", "alive" } }) } + , _dead_path_count { Metrics::peer_path_count.Add({ { "node_id", OSUtils::nodeIDStr(peerIdentity.address().toInt()) }, { "status", "dead" } }) } + , _incoming_packet { Metrics::peer_packets.Add({ { "direction", "rx" }, { "node_id", OSUtils::nodeIDStr(peerIdentity.address().toInt()) } }) } + , _outgoing_packet { Metrics::peer_packets.Add({ { "direction", "tx" }, { "node_id", OSUtils::nodeIDStr(peerIdentity.address().toInt()) } }) } + , _packet_errors { Metrics::peer_packet_errors.Add({ { "node_id", OSUtils::nodeIDStr(peerIdentity.address().toInt()) } }) } #endif { - if (!myIdentity.agree(peerIdentity,_key)) { - throw ZT_EXCEPTION_INVALID_ARGUMENT; - } + if (! myIdentity.agree(peerIdentity, _key)) { + throw ZT_EXCEPTION_INVALID_ARGUMENT; + } - uint8_t ktmp[ZT_SYMMETRIC_KEY_SIZE]; - KBKDFHMACSHA384(_key,ZT_KBKDF_LABEL_AES_GMAC_SIV_K0,0,0,ktmp); - _aesKeys[0].init(ktmp); - KBKDFHMACSHA384(_key,ZT_KBKDF_LABEL_AES_GMAC_SIV_K1,0,0,ktmp); - _aesKeys[1].init(ktmp); - Utils::burn(ktmp,ZT_SYMMETRIC_KEY_SIZE); + uint8_t ktmp[ZT_SYMMETRIC_KEY_SIZE]; + KBKDFHMACSHA384(_key, ZT_KBKDF_LABEL_AES_GMAC_SIV_K0, 0, 0, ktmp); + _aesKeys[0].init(ktmp); + KBKDFHMACSHA384(_key, ZT_KBKDF_LABEL_AES_GMAC_SIV_K1, 0, 0, ktmp); + _aesKeys[1].init(ktmp); + Utils::burn(ktmp, ZT_SYMMETRIC_KEY_SIZE); } void Peer::received( - void *tPtr, - const SharedPtr &path, - const unsigned int hops, - const uint64_t packetId, - const unsigned int payloadLength, - const Packet::Verb verb, - const uint64_t inRePacketId, - const Packet::Verb inReVerb, - const bool trustEstablished, - const uint64_t networkId, - const int32_t flowId) + void* tPtr, + const SharedPtr& path, + const unsigned int hops, + const uint64_t packetId, + const unsigned int payloadLength, + const Packet::Verb verb, + const uint64_t inRePacketId, + const Packet::Verb inReVerb, + const bool trustEstablished, + const uint64_t networkId, + const int32_t flowId) { - const int64_t now = RR->node->now(); + const int64_t now = RR->node->now(); - _lastReceive = now; - switch (verb) { - case Packet::VERB_FRAME: - case Packet::VERB_EXT_FRAME: - case Packet::VERB_NETWORK_CONFIG_REQUEST: - case Packet::VERB_NETWORK_CONFIG: - case Packet::VERB_MULTICAST_FRAME: - _lastNontrivialReceive = now; - break; - default: - break; - } + _lastReceive = now; + switch (verb) { + case Packet::VERB_FRAME: + case Packet::VERB_EXT_FRAME: + case Packet::VERB_NETWORK_CONFIG_REQUEST: + case Packet::VERB_NETWORK_CONFIG: + case Packet::VERB_MULTICAST_FRAME: + _lastNontrivialReceive = now; + break; + default: + break; + } #ifndef ZT_NO_PEER_METRICS - _incoming_packet++; + _incoming_packet++; #endif - recordIncomingPacket(path, packetId, payloadLength, verb, flowId, now); + recordIncomingPacket(path, packetId, payloadLength, verb, flowId, now); - if (trustEstablished) { - _lastTrustEstablishedPacketReceived = now; - path->trustedPacketReceived(now); - } + if (trustEstablished) { + _lastTrustEstablishedPacketReceived = now; + path->trustedPacketReceived(now); + } - if (hops == 0) { - // If this is a direct packet (no hops), update existing paths or learn new ones - bool havePath = false; - { - Mutex::Lock _l(_paths_m); - for(unsigned int i=0;iaddress().ipsEqual(path->address()) && _paths[i].p->localSocket() == path->localSocket()) { - if (_paths[i].p->alive(now) && !_bond) { - havePath = true; - break; - } - } - } else { - break; - } - } - } + if (hops == 0) { + // If this is a direct packet (no hops), update existing paths or learn new ones + bool havePath = false; + { + Mutex::Lock _l(_paths_m); + for (unsigned int i = 0; i < ZT_MAX_PEER_NETWORK_PATHS; ++i) { + if (_paths[i].p) { + if (_paths[i].p == path) { + _paths[i].lr = now; + havePath = true; + break; + } + // If same address on same interface then don't learn unless existing path isn't alive (prevents learning loop) + if (_paths[i].p->address().ipsEqual(path->address()) && _paths[i].p->localSocket() == path->localSocket()) { + if (_paths[i].p->alive(now) && ! _bond) { + havePath = true; + break; + } + } + } + else { + break; + } + } + } - if ( (!havePath) && RR->node->shouldUsePathForZeroTierTraffic(tPtr,_id.address(),path->localSocket(),path->address()) ) { - if (verb == Packet::VERB_OK) { - Mutex::Lock _l(_paths_m); - unsigned int oldestPathIdx = ZT_MAX_PEER_NETWORK_PATHS; - unsigned int oldestPathAge = 0; - unsigned int replacePath = ZT_MAX_PEER_NETWORK_PATHS; + if ((! havePath) && RR->node->shouldUsePathForZeroTierTraffic(tPtr, _id.address(), path->localSocket(), path->address())) { + if (verb == Packet::VERB_OK) { + Mutex::Lock _l(_paths_m); + unsigned int oldestPathIdx = ZT_MAX_PEER_NETWORK_PATHS; + unsigned int oldestPathAge = 0; + unsigned int replacePath = ZT_MAX_PEER_NETWORK_PATHS; - for(unsigned int i=0;iage(now); - if (currAge > oldestPathAge) { - oldestPathAge = currAge; - oldestPathIdx = i; - } - if (_paths[i].p->address().ipsEqual(path->address())) { - if (_paths[i].p->localSocket() == path->localSocket()) { - if (!_paths[i].p->alive(now)) { - replacePath = i; - break; - } - } - } - } else { - replacePath = i; - break; - } - } + for (unsigned int i = 0; i < ZT_MAX_PEER_NETWORK_PATHS; ++i) { + if (_paths[i].p) { + // Keep track of oldest path as a last resort option + unsigned int currAge = _paths[i].p->age(now); + if (currAge > oldestPathAge) { + oldestPathAge = currAge; + oldestPathIdx = i; + } + if (_paths[i].p->address().ipsEqual(path->address())) { + if (_paths[i].p->localSocket() == path->localSocket()) { + if (! _paths[i].p->alive(now)) { + replacePath = i; + break; + } + } + } + } + else { + replacePath = i; + break; + } + } - // If we didn't find a good candidate then resort to replacing oldest path - replacePath = (replacePath == ZT_MAX_PEER_NETWORK_PATHS) ? oldestPathIdx : replacePath; - if (replacePath != ZT_MAX_PEER_NETWORK_PATHS) { - RR->t->peerLearnedNewPath(tPtr, networkId, *this, path, packetId); - _paths[replacePath].lr = now; - _paths[replacePath].p = path; - _paths[replacePath].priority = 1; - Mutex::Lock _l(_bond_m); - if(_bond) { - _bond->nominatePathToBond(_paths[replacePath].p, now); - } - } - } else { - Mutex::Lock ltl(_lastTriedPath_m); + // If we didn't find a good candidate then resort to replacing oldest path + replacePath = (replacePath == ZT_MAX_PEER_NETWORK_PATHS) ? oldestPathIdx : replacePath; + if (replacePath != ZT_MAX_PEER_NETWORK_PATHS) { + RR->t->peerLearnedNewPath(tPtr, networkId, *this, path, packetId); + _paths[replacePath].lr = now; + _paths[replacePath].p = path; + _paths[replacePath].priority = 1; + Mutex::Lock _l(_bond_m); + if (_bond) { + _bond->nominatePathToBond(_paths[replacePath].p, now); + } + } + } + else { + Mutex::Lock ltl(_lastTriedPath_m); - bool triedTooRecently = false; - for(std::list< std::pair< Path *, int64_t > >::iterator i(_lastTriedPath.begin());i!=_lastTriedPath.end();) { - if ((now - i->second) > 1000) { - _lastTriedPath.erase(i++); - } else if (i->first == path.ptr()) { - ++i; - triedTooRecently = true; - } else { - ++i; - } - } + bool triedTooRecently = false; + for (std::list >::iterator i(_lastTriedPath.begin()); i != _lastTriedPath.end();) { + if ((now - i->second) > 1000) { + _lastTriedPath.erase(i++); + } + else if (i->first == path.ptr()) { + ++i; + triedTooRecently = true; + } + else { + ++i; + } + } - if (!triedTooRecently) { - _lastTriedPath.push_back(std::pair< Path *, int64_t >(path.ptr(), now)); - attemptToContactAt(tPtr,path->localSocket(),path->address(),now,true); - path->sent(now); - RR->t->peerConfirmingUnknownPath(tPtr,networkId,*this,path,packetId,verb); - } - } - } - } + if (! triedTooRecently) { + _lastTriedPath.push_back(std::pair(path.ptr(), now)); + attemptToContactAt(tPtr, path->localSocket(), path->address(), now, true); + path->sent(now); + RR->t->peerConfirmingUnknownPath(tPtr, networkId, *this, path, packetId, verb); + } + } + } + } - // If we have a trust relationship periodically push a message enumerating - // all known external addresses for ourselves. If we already have a path this - // is done less frequently. - if (this->trustEstablished(now)) { - const int64_t sinceLastPush = now - _lastDirectPathPushSent; - bool lowBandwidth = RR->node->lowBandwidthModeEnabled(); - int timerScale = lowBandwidth ? 16 : 1; - if (sinceLastPush >= ((hops == 0) ? ZT_DIRECT_PATH_PUSH_INTERVAL_HAVEPATH * timerScale : ZT_DIRECT_PATH_PUSH_INTERVAL)) { - _lastDirectPathPushSent = now; - std::vector pathsToPush(RR->node->directPaths()); - std::vector ma = RR->sa->whoami(); - pathsToPush.insert(pathsToPush.end(), ma.begin(), ma.end()); - if (!pathsToPush.empty()) { - std::vector::const_iterator p(pathsToPush.begin()); - while (p != pathsToPush.end()) { - Packet *const outp = new Packet(_id.address(),RR->identity.address(),Packet::VERB_PUSH_DIRECT_PATHS); - outp->addSize(2); // leave room for count - unsigned int count = 0; - while ((p != pathsToPush.end())&&((outp->size() + 24) < 1200)) { - uint8_t addressType = 4; - switch(p->ss_family) { - case AF_INET: - break; - case AF_INET6: - addressType = 6; - break; - default: // we currently only push IP addresses - ++p; - continue; - } + // If we have a trust relationship periodically push a message enumerating + // all known external addresses for ourselves. If we already have a path this + // is done less frequently. + if (this->trustEstablished(now)) { + const int64_t sinceLastPush = now - _lastDirectPathPushSent; + bool lowBandwidth = RR->node->lowBandwidthModeEnabled(); + int timerScale = lowBandwidth ? 16 : 1; + if (sinceLastPush >= ((hops == 0) ? ZT_DIRECT_PATH_PUSH_INTERVAL_HAVEPATH * timerScale : ZT_DIRECT_PATH_PUSH_INTERVAL)) { + _lastDirectPathPushSent = now; + std::vector pathsToPush(RR->node->directPaths()); + std::vector ma = RR->sa->whoami(); + pathsToPush.insert(pathsToPush.end(), ma.begin(), ma.end()); + if (! pathsToPush.empty()) { + std::vector::const_iterator p(pathsToPush.begin()); + while (p != pathsToPush.end()) { + Packet* const outp = new Packet(_id.address(), RR->identity.address(), Packet::VERB_PUSH_DIRECT_PATHS); + outp->addSize(2); // leave room for count + unsigned int count = 0; + while ((p != pathsToPush.end()) && ((outp->size() + 24) < 1200)) { + uint8_t addressType = 4; + switch (p->ss_family) { + case AF_INET: + break; + case AF_INET6: + addressType = 6; + break; + default: // we currently only push IP addresses + ++p; + continue; + } - outp->append((uint8_t)0); // no flags - outp->append((uint16_t)0); // no extensions - outp->append(addressType); - outp->append((uint8_t)((addressType == 4) ? 6 : 18)); - outp->append(p->rawIpData(),((addressType == 4) ? 4 : 16)); - outp->append((uint16_t)p->port()); + outp->append((uint8_t)0); // no flags + outp->append((uint16_t)0); // no extensions + outp->append(addressType); + outp->append((uint8_t)((addressType == 4) ? 6 : 18)); + outp->append(p->rawIpData(), ((addressType == 4) ? 4 : 16)); + outp->append((uint16_t)p->port()); - ++count; - ++p; - } - if (count) { - Metrics::pkt_push_direct_paths_out++; - outp->setAt(ZT_PACKET_IDX_PAYLOAD,(uint16_t)count); - outp->compress(); - outp->armor(_key,true,aesKeysIfSupported()); - Metrics::pkt_push_direct_paths_out++; - path->send(RR,tPtr,outp->data(),outp->size(),now); - } - delete outp; - } - } - } - } + ++count; + ++p; + } + if (count) { + Metrics::pkt_push_direct_paths_out++; + outp->setAt(ZT_PACKET_IDX_PAYLOAD, (uint16_t)count); + outp->compress(); + outp->armor(_key, true, false, aesKeysIfSupported(), _id); + Metrics::pkt_push_direct_paths_out++; + path->send(RR, tPtr, outp->data(), outp->size(), now); + } + delete outp; + } + } + } + } } SharedPtr Peer::getAppropriatePath(int64_t now, bool includeExpired, int32_t flowId) { - Mutex::Lock _l(_paths_m); - Mutex::Lock _lb(_bond_m); - if(_bond && _bond->isReady()) { - return _bond->getAppropriatePath(now, flowId); - } - unsigned int bestPath = ZT_MAX_PEER_NETWORK_PATHS; - /** - * Send traffic across the highest quality path only. This algorithm will still - * use the old path quality metric from protocol version 9. - */ - long bestPathQuality = 2147483647; - for(unsigned int i=0;iquality(now) / _paths[i].priority; - if (q <= bestPathQuality) { - bestPathQuality = q; - bestPath = i; - } - } - } else { - break; - } - } - if (bestPath != ZT_MAX_PEER_NETWORK_PATHS) { - return _paths[bestPath].p; - } - return SharedPtr(); + Mutex::Lock _l(_paths_m); + Mutex::Lock _lb(_bond_m); + if (_bond && _bond->isReady()) { + return _bond->getAppropriatePath(now, flowId); + } + unsigned int bestPath = ZT_MAX_PEER_NETWORK_PATHS; + /** + * Send traffic across the highest quality path only. This algorithm will still + * use the old path quality metric from protocol version 9. + */ + long bestPathQuality = 2147483647; + for (unsigned int i = 0; i < ZT_MAX_PEER_NETWORK_PATHS; ++i) { + if (_paths[i].p) { + if ((includeExpired) || ((now - _paths[i].lr) < ZT_PEER_PATH_EXPIRATION)) { + const long q = _paths[i].p->quality(now) / _paths[i].priority; + if (q <= bestPathQuality) { + bestPathQuality = q; + bestPath = i; + } + } + } + else { + break; + } + } + if (bestPath != ZT_MAX_PEER_NETWORK_PATHS) { + return _paths[bestPath].p; + } + return SharedPtr(); } -void Peer::introduce(void *const tPtr,const int64_t now,const SharedPtr &other) const +void Peer::introduce(void* const tPtr, const int64_t now, const SharedPtr& other) const { - unsigned int myBestV4ByScope[ZT_INETADDRESS_MAX_SCOPE+1]; - unsigned int myBestV6ByScope[ZT_INETADDRESS_MAX_SCOPE+1]; - long myBestV4QualityByScope[ZT_INETADDRESS_MAX_SCOPE+1]; - long myBestV6QualityByScope[ZT_INETADDRESS_MAX_SCOPE+1]; - unsigned int theirBestV4ByScope[ZT_INETADDRESS_MAX_SCOPE+1]; - unsigned int theirBestV6ByScope[ZT_INETADDRESS_MAX_SCOPE+1]; - long theirBestV4QualityByScope[ZT_INETADDRESS_MAX_SCOPE+1]; - long theirBestV6QualityByScope[ZT_INETADDRESS_MAX_SCOPE+1]; - for(int i=0;i<=ZT_INETADDRESS_MAX_SCOPE;++i) { - myBestV4ByScope[i] = ZT_MAX_PEER_NETWORK_PATHS; - myBestV6ByScope[i] = ZT_MAX_PEER_NETWORK_PATHS; - myBestV4QualityByScope[i] = 2147483647; - myBestV6QualityByScope[i] = 2147483647; - theirBestV4ByScope[i] = ZT_MAX_PEER_NETWORK_PATHS; - theirBestV6ByScope[i] = ZT_MAX_PEER_NETWORK_PATHS; - theirBestV4QualityByScope[i] = 2147483647; - theirBestV6QualityByScope[i] = 2147483647; - } + unsigned int myBestV4ByScope[ZT_INETADDRESS_MAX_SCOPE + 1]; + unsigned int myBestV6ByScope[ZT_INETADDRESS_MAX_SCOPE + 1]; + long myBestV4QualityByScope[ZT_INETADDRESS_MAX_SCOPE + 1]; + long myBestV6QualityByScope[ZT_INETADDRESS_MAX_SCOPE + 1]; + unsigned int theirBestV4ByScope[ZT_INETADDRESS_MAX_SCOPE + 1]; + unsigned int theirBestV6ByScope[ZT_INETADDRESS_MAX_SCOPE + 1]; + long theirBestV4QualityByScope[ZT_INETADDRESS_MAX_SCOPE + 1]; + long theirBestV6QualityByScope[ZT_INETADDRESS_MAX_SCOPE + 1]; + for (int i = 0; i <= ZT_INETADDRESS_MAX_SCOPE; ++i) { + myBestV4ByScope[i] = ZT_MAX_PEER_NETWORK_PATHS; + myBestV6ByScope[i] = ZT_MAX_PEER_NETWORK_PATHS; + myBestV4QualityByScope[i] = 2147483647; + myBestV6QualityByScope[i] = 2147483647; + theirBestV4ByScope[i] = ZT_MAX_PEER_NETWORK_PATHS; + theirBestV6ByScope[i] = ZT_MAX_PEER_NETWORK_PATHS; + theirBestV4QualityByScope[i] = 2147483647; + theirBestV6QualityByScope[i] = 2147483647; + } - Mutex::Lock _l1(_paths_m); + Mutex::Lock _l1(_paths_m); - for(unsigned int i=0;iquality(now) / _paths[i].priority; - const unsigned int s = (unsigned int)_paths[i].p->ipScope(); - switch(_paths[i].p->address().ss_family) { - case AF_INET: - if (q <= myBestV4QualityByScope[s]) { - myBestV4QualityByScope[s] = q; - myBestV4ByScope[s] = i; - } - break; - case AF_INET6: - if (q <= myBestV6QualityByScope[s]) { - myBestV6QualityByScope[s] = q; - myBestV6ByScope[s] = i; - } - break; - } - } else { - break; - } - } + for (unsigned int i = 0; i < ZT_MAX_PEER_NETWORK_PATHS; ++i) { + if (_paths[i].p) { + const long q = _paths[i].p->quality(now) / _paths[i].priority; + const unsigned int s = (unsigned int)_paths[i].p->ipScope(); + switch (_paths[i].p->address().ss_family) { + case AF_INET: + if (q <= myBestV4QualityByScope[s]) { + myBestV4QualityByScope[s] = q; + myBestV4ByScope[s] = i; + } + break; + case AF_INET6: + if (q <= myBestV6QualityByScope[s]) { + myBestV6QualityByScope[s] = q; + myBestV6ByScope[s] = i; + } + break; + } + } + else { + break; + } + } - Mutex::Lock _l2(other->_paths_m); + Mutex::Lock _l2(other->_paths_m); - for(unsigned int i=0;i_paths[i].p) { - const long q = other->_paths[i].p->quality(now) / other->_paths[i].priority; - const unsigned int s = (unsigned int)other->_paths[i].p->ipScope(); - switch(other->_paths[i].p->address().ss_family) { - case AF_INET: - if (q <= theirBestV4QualityByScope[s]) { - theirBestV4QualityByScope[s] = q; - theirBestV4ByScope[s] = i; - } - break; - case AF_INET6: - if (q <= theirBestV6QualityByScope[s]) { - theirBestV6QualityByScope[s] = q; - theirBestV6ByScope[s] = i; - } - break; - } - } else { - break; - } - } + for (unsigned int i = 0; i < ZT_MAX_PEER_NETWORK_PATHS; ++i) { + if (other->_paths[i].p) { + const long q = other->_paths[i].p->quality(now) / other->_paths[i].priority; + const unsigned int s = (unsigned int)other->_paths[i].p->ipScope(); + switch (other->_paths[i].p->address().ss_family) { + case AF_INET: + if (q <= theirBestV4QualityByScope[s]) { + theirBestV4QualityByScope[s] = q; + theirBestV4ByScope[s] = i; + } + break; + case AF_INET6: + if (q <= theirBestV6QualityByScope[s]) { + theirBestV6QualityByScope[s] = q; + theirBestV6ByScope[s] = i; + } + break; + } + } + else { + break; + } + } - unsigned int mine = ZT_MAX_PEER_NETWORK_PATHS; - unsigned int theirs = ZT_MAX_PEER_NETWORK_PATHS; + unsigned int mine = ZT_MAX_PEER_NETWORK_PATHS; + unsigned int theirs = ZT_MAX_PEER_NETWORK_PATHS; - for(int s=ZT_INETADDRESS_MAX_SCOPE;s>=0;--s) { - if ((myBestV6ByScope[s] != ZT_MAX_PEER_NETWORK_PATHS)&&(theirBestV6ByScope[s] != ZT_MAX_PEER_NETWORK_PATHS)) { - mine = myBestV6ByScope[s]; - theirs = theirBestV6ByScope[s]; - break; - } - if ((myBestV4ByScope[s] != ZT_MAX_PEER_NETWORK_PATHS)&&(theirBestV4ByScope[s] != ZT_MAX_PEER_NETWORK_PATHS)) { - mine = myBestV4ByScope[s]; - theirs = theirBestV4ByScope[s]; - break; - } - } + for (int s = ZT_INETADDRESS_MAX_SCOPE; s >= 0; --s) { + if ((myBestV6ByScope[s] != ZT_MAX_PEER_NETWORK_PATHS) && (theirBestV6ByScope[s] != ZT_MAX_PEER_NETWORK_PATHS)) { + mine = myBestV6ByScope[s]; + theirs = theirBestV6ByScope[s]; + break; + } + if ((myBestV4ByScope[s] != ZT_MAX_PEER_NETWORK_PATHS) && (theirBestV4ByScope[s] != ZT_MAX_PEER_NETWORK_PATHS)) { + mine = myBestV4ByScope[s]; + theirs = theirBestV4ByScope[s]; + break; + } + } - if (mine != ZT_MAX_PEER_NETWORK_PATHS) { - unsigned int alt = (unsigned int)RR->node->prng() & 1; // randomize which hint we send first for black magickal NAT-t reasons - const unsigned int completed = alt + 2; - while (alt != completed) { - if ((alt & 1) == 0) { - Packet outp(_id.address(),RR->identity.address(),Packet::VERB_RENDEZVOUS); - outp.append((uint8_t)0); - other->_id.address().appendTo(outp); - outp.append((uint16_t)other->_paths[theirs].p->address().port()); - if (other->_paths[theirs].p->address().ss_family == AF_INET6) { - outp.append((uint8_t)16); - outp.append(other->_paths[theirs].p->address().rawIpData(),16); - } else { - outp.append((uint8_t)4); - outp.append(other->_paths[theirs].p->address().rawIpData(),4); - } - outp.armor(_key,true,aesKeysIfSupported()); - Metrics::pkt_rendezvous_out++; - _paths[mine].p->send(RR,tPtr,outp.data(),outp.size(),now); - } else { - Packet outp(other->_id.address(),RR->identity.address(),Packet::VERB_RENDEZVOUS); - outp.append((uint8_t)0); - _id.address().appendTo(outp); - outp.append((uint16_t)_paths[mine].p->address().port()); - if (_paths[mine].p->address().ss_family == AF_INET6) { - outp.append((uint8_t)16); - outp.append(_paths[mine].p->address().rawIpData(),16); - } else { - outp.append((uint8_t)4); - outp.append(_paths[mine].p->address().rawIpData(),4); - } - outp.armor(other->_key,true,other->aesKeysIfSupported()); - Metrics::pkt_rendezvous_out++; - other->_paths[theirs].p->send(RR,tPtr,outp.data(),outp.size(),now); - } - ++alt; - } - } + if (mine != ZT_MAX_PEER_NETWORK_PATHS) { + unsigned int alt = (unsigned int)RR->node->prng() & 1; // randomize which hint we send first for black magickal NAT-t reasons + const unsigned int completed = alt + 2; + while (alt != completed) { + if ((alt & 1) == 0) { + Packet outp(_id.address(), RR->identity.address(), Packet::VERB_RENDEZVOUS); + outp.append((uint8_t)0); + other->_id.address().appendTo(outp); + outp.append((uint16_t)other->_paths[theirs].p->address().port()); + if (other->_paths[theirs].p->address().ss_family == AF_INET6) { + outp.append((uint8_t)16); + outp.append(other->_paths[theirs].p->address().rawIpData(), 16); + } + else { + outp.append((uint8_t)4); + outp.append(other->_paths[theirs].p->address().rawIpData(), 4); + } + outp.armor(_key, true, false, aesKeysIfSupported(), _id); + Metrics::pkt_rendezvous_out++; + _paths[mine].p->send(RR, tPtr, outp.data(), outp.size(), now); + } + else { + Packet outp(other->_id.address(), RR->identity.address(), Packet::VERB_RENDEZVOUS); + outp.append((uint8_t)0); + _id.address().appendTo(outp); + outp.append((uint16_t)_paths[mine].p->address().port()); + if (_paths[mine].p->address().ss_family == AF_INET6) { + outp.append((uint8_t)16); + outp.append(_paths[mine].p->address().rawIpData(), 16); + } + else { + outp.append((uint8_t)4); + outp.append(_paths[mine].p->address().rawIpData(), 4); + } + outp.armor(other->_key, true, false, other->aesKeysIfSupported(), other->identity()); + Metrics::pkt_rendezvous_out++; + other->_paths[theirs].p->send(RR, tPtr, outp.data(), outp.size(), now); + } + ++alt; + } + } } -void Peer::sendHELLO(void *tPtr,const int64_t localSocket,const InetAddress &atAddress,int64_t now) +void Peer::sendHELLO(void* tPtr, const int64_t localSocket, const InetAddress& atAddress, int64_t now) { - Packet outp(_id.address(),RR->identity.address(),Packet::VERB_HELLO); + Packet outp(_id.address(), RR->identity.address(), Packet::VERB_HELLO); - outp.append((unsigned char)ZT_PROTO_VERSION); - outp.append((unsigned char)ZEROTIER_ONE_VERSION_MAJOR); - outp.append((unsigned char)ZEROTIER_ONE_VERSION_MINOR); - outp.append((uint16_t)ZEROTIER_ONE_VERSION_REVISION); - outp.append(now); - RR->identity.serialize(outp,false); - atAddress.serialize(outp); + outp.append((unsigned char)ZT_PROTO_VERSION); + outp.append((unsigned char)ZEROTIER_ONE_VERSION_MAJOR); + outp.append((unsigned char)ZEROTIER_ONE_VERSION_MINOR); + outp.append((uint16_t)ZEROTIER_ONE_VERSION_REVISION); + outp.append(now); + RR->identity.serialize(outp, false); + atAddress.serialize(outp); - outp.append((uint64_t)RR->topology->planetWorldId()); - outp.append((uint64_t)RR->topology->planetWorldTimestamp()); + outp.append((uint64_t)RR->topology->planetWorldId()); + outp.append((uint64_t)RR->topology->planetWorldTimestamp()); - const unsigned int startCryptedPortionAt = outp.size(); + const unsigned int startCryptedPortionAt = outp.size(); - std::vector moons(RR->topology->moons()); - std::vector moonsWanted(RR->topology->moonsWanted()); - outp.append((uint16_t)(moons.size() + moonsWanted.size())); - for(std::vector::const_iterator m(moons.begin());m!=moons.end();++m) { - outp.append((uint8_t)m->type()); - outp.append((uint64_t)m->id()); - outp.append((uint64_t)m->timestamp()); - } - for(std::vector::const_iterator m(moonsWanted.begin());m!=moonsWanted.end();++m) { - outp.append((uint8_t)World::TYPE_MOON); - outp.append(*m); - outp.append((uint64_t)0); - } + std::vector moons(RR->topology->moons()); + std::vector moonsWanted(RR->topology->moonsWanted()); + outp.append((uint16_t)(moons.size() + moonsWanted.size())); + for (std::vector::const_iterator m(moons.begin()); m != moons.end(); ++m) { + outp.append((uint8_t)m->type()); + outp.append((uint64_t)m->id()); + outp.append((uint64_t)m->timestamp()); + } + for (std::vector::const_iterator m(moonsWanted.begin()); m != moonsWanted.end(); ++m) { + outp.append((uint8_t)World::TYPE_MOON); + outp.append(*m); + outp.append((uint64_t)0); + } - outp.cryptField(_key,startCryptedPortionAt,outp.size() - startCryptedPortionAt); + outp.cryptField(_key, startCryptedPortionAt, outp.size() - startCryptedPortionAt); - Metrics::pkt_hello_out++; + Metrics::pkt_hello_out++; - if (atAddress) { - outp.armor(_key,false,nullptr); // false == don't encrypt full payload, but add MAC - RR->node->expectReplyTo(outp.packetId()); - RR->node->putPacket(tPtr,RR->node->lowBandwidthModeEnabled() ? localSocket : -1,atAddress,outp.data(),outp.size()); - } else { - RR->node->expectReplyTo(outp.packetId()); - RR->sw->send(tPtr,outp,false); // false == don't encrypt full payload, but add MAC - } + if (atAddress) { + outp.armor(_key, false, true, nullptr, _id); + RR->node->expectReplyTo(outp.packetId()); + RR->node->putPacket(tPtr, RR->node->lowBandwidthModeEnabled() ? localSocket : -1, atAddress, outp.data(), outp.size()); + } + else { + RR->node->expectReplyTo(outp.packetId()); + RR->sw->send(tPtr, outp, true); + } } -void Peer::attemptToContactAt(void *tPtr,const int64_t localSocket,const InetAddress &atAddress,int64_t now,bool sendFullHello) +void Peer::attemptToContactAt(void* tPtr, const int64_t localSocket, const InetAddress& atAddress, int64_t now, bool sendFullHello) { - if ( (!sendFullHello) && (_vProto >= 5) && (!((_vMajor == 1)&&(_vMinor == 1)&&(_vRevision == 0))) ) { - Packet outp(_id.address(),RR->identity.address(),Packet::VERB_ECHO); - outp.armor(_key,true,aesKeysIfSupported()); - Metrics::pkt_echo_out++; - RR->node->expectReplyTo(outp.packetId()); - RR->node->putPacket(tPtr,localSocket,atAddress,outp.data(),outp.size()); - } else { - sendHELLO(tPtr,localSocket,atAddress,now); - } + if ((! sendFullHello) && (_vProto >= 5) && (! ((_vMajor == 1) && (_vMinor == 1) && (_vRevision == 0)))) { + Packet outp(_id.address(), RR->identity.address(), Packet::VERB_ECHO); + outp.armor(_key, true, false, aesKeysIfSupported(), _id); + Metrics::pkt_echo_out++; + RR->node->expectReplyTo(outp.packetId()); + RR->node->putPacket(tPtr, localSocket, atAddress, outp.data(), outp.size()); + } + else { + sendHELLO(tPtr, localSocket, atAddress, now); + } } -void Peer::tryMemorizedPath(void *tPtr,int64_t now) +void Peer::tryMemorizedPath(void* tPtr, int64_t now) { - if ((now - _lastTriedMemorizedPath) >= ZT_TRY_MEMORIZED_PATH_INTERVAL) { - _lastTriedMemorizedPath = now; - InetAddress mp; - if (RR->node->externalPathLookup(tPtr,_id.address(),-1,mp)) { - attemptToContactAt(tPtr,-1,mp,now,true); - } - } + if ((now - _lastTriedMemorizedPath) >= ZT_TRY_MEMORIZED_PATH_INTERVAL) { + _lastTriedMemorizedPath = now; + InetAddress mp; + if (RR->node->externalPathLookup(tPtr, _id.address(), -1, mp)) { + attemptToContactAt(tPtr, -1, mp, now, true); + } + } } -void Peer::performMultipathStateCheck(void *tPtr, int64_t now) +void Peer::performMultipathStateCheck(void* tPtr, int64_t now) { - Mutex::Lock _l(_bond_m); - /** - * Check for conditions required for multipath bonding and create a bond - * if allowed. - */ - int numAlivePaths = 0; - bool atLeastOneNonExpired = false; - for(unsigned int i=0;ialive(now)) { - numAlivePaths++; - } - if ((now - _paths[i].lr) < ZT_PEER_PATH_EXPIRATION) { - atLeastOneNonExpired = true; - } - } - } - if (_bond) { - if (numAlivePaths == 0 && !atLeastOneNonExpired) { - _bond = SharedPtr(); - RR->bc->destroyBond(_id.address().toInt()); - } - return; - } - _localMultipathSupported = ((numAlivePaths >= 1) && (RR->bc->inUse()) && (ZT_PROTO_VERSION > 9)); - if (_localMultipathSupported && !_bond) { - if (RR->bc) { - _bond = RR->bc->createBond(RR, this); - /** - * Allow new bond to retroactively learn all paths known to this peer - */ - if (_bond) { - for (unsigned int i=0;inominatePathToBond(_paths[i].p, now); - } - } - } - } - } + Mutex::Lock _l(_bond_m); + /** + * Check for conditions required for multipath bonding and create a bond + * if allowed. + */ + int numAlivePaths = 0; + bool atLeastOneNonExpired = false; + for (unsigned int i = 0; i < ZT_MAX_PEER_NETWORK_PATHS; ++i) { + if (_paths[i].p) { + if (_paths[i].p->alive(now)) { + numAlivePaths++; + } + if ((now - _paths[i].lr) < ZT_PEER_PATH_EXPIRATION) { + atLeastOneNonExpired = true; + } + } + } + if (_bond) { + if (numAlivePaths == 0 && ! atLeastOneNonExpired) { + _bond = SharedPtr(); + RR->bc->destroyBond(_id.address().toInt()); + } + return; + } + _localMultipathSupported = ((numAlivePaths >= 1) && (RR->bc->inUse()) && (ZT_PROTO_VERSION > 9)); + if (_localMultipathSupported && ! _bond) { + if (RR->bc) { + _bond = RR->bc->createBond(RR, this); + /** + * Allow new bond to retroactively learn all paths known to this peer + */ + if (_bond) { + for (unsigned int i = 0; i < ZT_MAX_PEER_NETWORK_PATHS; ++i) { + if (_paths[i].p) { + _bond->nominatePathToBond(_paths[i].p, now); + } + } + } + } + } } -unsigned int Peer::doPingAndKeepalive(void *tPtr,int64_t now) +unsigned int Peer::doPingAndKeepalive(void* tPtr, int64_t now) { - unsigned int sent = 0; - { - Mutex::Lock _l(_paths_m); + unsigned int sent = 0; + { + Mutex::Lock _l(_paths_m); - performMultipathStateCheck(tPtr, now); + performMultipathStateCheck(tPtr, now); - const bool sendFullHello = ((now - _lastSentFullHello) >= ZT_PEER_PING_PERIOD); - if (sendFullHello) { - _lastSentFullHello = now; - } + const bool sendFullHello = ((now - _lastSentFullHello) >= ZT_PEER_PING_PERIOD); + if (sendFullHello) { + _lastSentFullHello = now; + } - // Right now we only keep pinging links that have the maximum priority. The - // priority is used to track cluster redirections, meaning that when a cluster - // redirects us its redirect target links override all other links and we - // let those old links expire. - long maxPriority = 0; - for(unsigned int i=0;ineedsHeartbeat(now))) { - attemptToContactAt(tPtr,_paths[i].p->localSocket(),_paths[i].p->address(),now,sendFullHello); - _paths[i].p->sent(now); - sent |= (_paths[i].p->address().ss_family == AF_INET) ? 0x1 : 0x2; - } - } else { - _paths[i] = _PeerPath(); - deletionOccurred = true; - } - } - if (!_paths[i].p || deletionOccurred) { - for(unsigned int j=i;jneedsHeartbeat(now))) { + attemptToContactAt(tPtr, _paths[i].p->localSocket(), _paths[i].p->address(), now, sendFullHello); + _paths[i].p->sent(now); + sent |= (_paths[i].p->address().ss_family == AF_INET) ? 0x1 : 0x2; + } + } + else { + _paths[i] = _PeerPath(); + deletionOccurred = true; + } + } + if (! _paths[i].p || deletionOccurred) { + for (unsigned int j = i; j < ZT_MAX_PEER_NETWORK_PATHS; ++j) { + if (_paths[j].p && i != j) { + _paths[i] = _paths[j]; + _paths[j] = _PeerPath(); + break; + } + } + deletionOccurred = false; + } + } #ifndef ZT_NO_PEER_METRICS - uint16_t alive_path_count_tmp = 0, dead_path_count_tmp = 0; - for(unsigned int i=0;ialive(now)) { - alive_path_count_tmp++; - } - else { - dead_path_count_tmp++; - } - } - } - _alive_path_count = alive_path_count_tmp; - _dead_path_count = dead_path_count_tmp; + uint16_t alive_path_count_tmp = 0, dead_path_count_tmp = 0; + for (unsigned int i = 0; i < ZT_MAX_PEER_NETWORK_PATHS; ++i) { + if (_paths[i].p) { + if (_paths[i].p->alive(now)) { + alive_path_count_tmp++; + } + else { + dead_path_count_tmp++; + } + } + } + _alive_path_count = alive_path_count_tmp; + _dead_path_count = dead_path_count_tmp; #endif - } + } #ifndef ZT_NO_PEER_METRICS - _peer_latency.Observe(latency(now)); + _peer_latency.Observe(latency(now)); #endif - return sent; + return sent; } -void Peer::clusterRedirect(void *tPtr,const SharedPtr &originatingPath,const InetAddress &remoteAddress,const int64_t now) +void Peer::clusterRedirect(void* tPtr, const SharedPtr& originatingPath, const InetAddress& remoteAddress, const int64_t now) { - SharedPtr np(RR->topology->getPath(originatingPath->localSocket(),remoteAddress)); - RR->t->peerRedirected(tPtr,0,*this,np); + SharedPtr np(RR->topology->getPath(originatingPath->localSocket(), remoteAddress)); + RR->t->peerRedirected(tPtr, 0, *this, np); - attemptToContactAt(tPtr,originatingPath->localSocket(),remoteAddress,now,true); + attemptToContactAt(tPtr, originatingPath->localSocket(), remoteAddress, now, true); - { - Mutex::Lock _l(_paths_m); + { + Mutex::Lock _l(_paths_m); - // New priority is higher than the priority of the originating path (if known) - long newPriority = 1; - for(unsigned int i=0;i= newPriority)&&(!_paths[i].p->address().ipsEqual2(remoteAddress))) { - if (i != j) { - _paths[j] = _paths[i]; - } - ++j; - } - } - } - if (j < ZT_MAX_PEER_NETWORK_PATHS) { - _paths[j].lr = now; - _paths[j].p = np; - _paths[j].priority = newPriority; - ++j; - while (j < ZT_MAX_PEER_NETWORK_PATHS) { - _paths[j].lr = 0; - _paths[j].p.zero(); - _paths[j].priority = 1; - ++j; - } - } - } + // Erase any paths with lower priority than this one or that are duplicate + // IPs and add this path. + unsigned int j = 0; + for (unsigned int i = 0; i < ZT_MAX_PEER_NETWORK_PATHS; ++i) { + if (_paths[i].p) { + if ((_paths[i].priority >= newPriority) && (! _paths[i].p->address().ipsEqual2(remoteAddress))) { + if (i != j) { + _paths[j] = _paths[i]; + } + ++j; + } + } + } + if (j < ZT_MAX_PEER_NETWORK_PATHS) { + _paths[j].lr = now; + _paths[j].p = np; + _paths[j].priority = newPriority; + ++j; + while (j < ZT_MAX_PEER_NETWORK_PATHS) { + _paths[j].lr = 0; + _paths[j].p.zero(); + _paths[j].priority = 1; + ++j; + } + } + } } -void Peer::resetWithinScope(void *tPtr,InetAddress::IpScope scope,int inetAddressFamily,int64_t now) +void Peer::resetWithinScope(void* tPtr, InetAddress::IpScope scope, int inetAddressFamily, int64_t now) { - Mutex::Lock _l(_paths_m); - for(unsigned int i=0;iaddress().ss_family == inetAddressFamily)&&(_paths[i].p->ipScope() == scope)) { - attemptToContactAt(tPtr,_paths[i].p->localSocket(),_paths[i].p->address(),now,false); - _paths[i].p->sent(now); - _paths[i].lr = 0; // path will not be used unless it speaks again - } - } else { - break; - } - } + Mutex::Lock _l(_paths_m); + for (unsigned int i = 0; i < ZT_MAX_PEER_NETWORK_PATHS; ++i) { + if (_paths[i].p) { + if ((_paths[i].p->address().ss_family == inetAddressFamily) && (_paths[i].p->ipScope() == scope)) { + attemptToContactAt(tPtr, _paths[i].p->localSocket(), _paths[i].p->address(), now, false); + _paths[i].p->sent(now); + _paths[i].lr = 0; // path will not be used unless it speaks again + } + } + else { + break; + } + } } -void Peer::recordOutgoingPacket(const SharedPtr &path, const uint64_t packetId, - uint16_t payloadLength, const Packet::Verb verb, const int32_t flowId, int64_t now) +void Peer::recordOutgoingPacket(const SharedPtr& path, const uint64_t packetId, uint16_t payloadLength, const Packet::Verb verb, const int32_t flowId, int64_t now) { #ifndef ZT_NO_PEER_METRICS - _outgoing_packet++; + _outgoing_packet++; #endif - if (_localMultipathSupported && _bond) { - _bond->recordOutgoingPacket(path, packetId, payloadLength, verb, flowId, now); - } + if (_localMultipathSupported && _bond) { + _bond->recordOutgoingPacket(path, packetId, payloadLength, verb, flowId, now); + } } void Peer::recordIncomingInvalidPacket(const SharedPtr& path) { #ifndef ZT_NO_PEER_METRICS - _packet_errors++; + _packet_errors++; #endif - if (_localMultipathSupported && _bond) { - _bond->recordIncomingInvalidPacket(path); - } + if (_localMultipathSupported && _bond) { + _bond->recordIncomingInvalidPacket(path); + } } -void Peer::recordIncomingPacket(const SharedPtr &path, const uint64_t packetId, - uint16_t payloadLength, const Packet::Verb verb, const int32_t flowId, int64_t now) +void Peer::recordIncomingPacket(const SharedPtr& path, const uint64_t packetId, uint16_t payloadLength, const Packet::Verb verb, const int32_t flowId, int64_t now) { - if (_localMultipathSupported && _bond) { - _bond->recordIncomingPacket(path, packetId, payloadLength, verb, flowId, now); - } + if (_localMultipathSupported && _bond) { + _bond->recordIncomingPacket(path, packetId, payloadLength, verb, flowId, now); + } } -} // namespace ZeroTier +} // namespace ZeroTier diff --git a/node/Peer.hpp b/node/Peer.hpp index 777a1e96..74528453 100644 --- a/node/Peer.hpp +++ b/node/Peer.hpp @@ -14,27 +14,26 @@ #ifndef ZT_PEER_HPP #define ZT_PEER_HPP -#include -#include - #include "../include/ZeroTierOne.h" - -#include "Constants.hpp" -#include "RuntimeEnvironment.hpp" -#include "Node.hpp" -#include "Path.hpp" +#include "AES.hpp" #include "Address.hpp" -#include "Utils.hpp" +#include "AtomicCounter.hpp" +#include "Bond.hpp" +#include "Constants.hpp" +#include "Hashtable.hpp" #include "Identity.hpp" #include "InetAddress.hpp" -#include "Packet.hpp" -#include "SharedPtr.hpp" -#include "AtomicCounter.hpp" -#include "Hashtable.hpp" -#include "Mutex.hpp" -#include "Bond.hpp" -#include "AES.hpp" #include "Metrics.hpp" +#include "Mutex.hpp" +#include "Node.hpp" +#include "Packet.hpp" +#include "Path.hpp" +#include "RuntimeEnvironment.hpp" +#include "SharedPtr.hpp" +#include "Utils.hpp" + +#include +#include #define ZT_PEER_MAX_SERIALIZED_STATE_SIZE (sizeof(Peer) + 32 + (sizeof(Path) * 2)) @@ -43,660 +42,711 @@ namespace ZeroTier { /** * Peer on P2P Network (virtual layer 1) */ -class Peer -{ - friend class SharedPtr; - friend class SharedPtr; - friend class Switch; - friend class Bond; - -private: - Peer() = delete; // disabled to prevent bugs -- should not be constructed uninitialized - -public: - ~Peer() { - Utils::burn(_key,sizeof(_key)); - } - - /** - * Construct a new peer - * - * @param renv Runtime environment - * @param myIdentity Identity of THIS node (for key agreement) - * @param peerIdentity Identity of peer - * @throws std::runtime_error Key agreement with peer's identity failed - */ - Peer(const RuntimeEnvironment *renv,const Identity &myIdentity,const Identity &peerIdentity); - - /** - * @return This peer's ZT address (short for identity().address()) - */ - inline const Address &address() const { return _id.address(); } - - /** - * @return This peer's identity - */ - inline const Identity &identity() const { return _id; } - - /** - * Log receipt of an authenticated packet - * - * This is called by the decode pipe when a packet is proven to be authentic - * and appears to be valid. - * - * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call - * @param path Path over which packet was received - * @param hops ZeroTier (not IP) hops - * @param packetId Packet ID - * @param verb Packet verb - * @param inRePacketId Packet ID in reply to (default: none) - * @param inReVerb Verb in reply to (for OK/ERROR, default: VERB_NOP) - * @param trustEstablished If true, some form of non-trivial trust (like allowed in network) has been established - * @param networkId Network ID if this pertains to a network, or 0 otherwise - */ - void received( - void *tPtr, - const SharedPtr &path, - const unsigned int hops, - const uint64_t packetId, - const unsigned int payloadLength, - const Packet::Verb verb, - const uint64_t inRePacketId, - const Packet::Verb inReVerb, - const bool trustEstablished, - const uint64_t networkId, - const int32_t flowId); - - /** - * Check whether we have an active path to this peer via the given address - * - * @param now Current time - * @param addr Remote address - * @return True if we have an active path to this destination - */ - inline bool hasActivePathTo(int64_t now,const InetAddress &addr) const - { - Mutex::Lock _l(_paths_m); - for(unsigned int i=0;iaddress() == addr)) { - return true; - } - } else { - break; - } - } - return false; - } - - /** - * Send via best direct path - * - * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call - * @param data Packet data - * @param len Packet length - * @param now Current time - * @param force If true, send even if path is not alive - * @return True if we actually sent something - */ - inline bool sendDirect(void *tPtr,const void *data,unsigned int len,int64_t now,bool force) - { - SharedPtr bp(getAppropriatePath(now,force)); - if (bp) { - return bp->send(RR,tPtr,data,len,now); - } - return false; - } - - /** - * Record incoming packets to - * - * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call - * @param path Path over which packet was received - * @param packetId Packet ID - * @param payloadLength Length of packet data payload - * @param verb Packet verb - * @param flowId Flow ID - * @param now Current time - */ - void recordIncomingPacket(const SharedPtr &path, const uint64_t packetId, - uint16_t payloadLength, const Packet::Verb verb, const int32_t flowId, int64_t now); - - /** - * - * @param path Path over which packet is being sent - * @param packetId Packet ID - * @param payloadLength Length of packet data payload - * @param verb Packet verb - * @param flowId Flow ID - * @param now Current time - */ - void recordOutgoingPacket(const SharedPtr &path, const uint64_t packetId, - uint16_t payloadLength, const Packet::Verb verb, const int32_t flowId, int64_t now); - - /** - * Record an invalid incoming packet. This packet failed - * MAC/compression/cipher checks and will now contribute to a - * Packet Error Ratio (PER). - * - * @param path Path over which packet was received - */ - void recordIncomingInvalidPacket(const SharedPtr& path); - - /** - * Get the most appropriate direct path based on current multipath and QoS configuration - * - * @param now Current time - * @param includeExpired If true, include even expired paths - * @return Best current path or NULL if none - */ - SharedPtr getAppropriatePath(int64_t now, bool includeExpired, int32_t flowId = -1); - - /** - * Send VERB_RENDEZVOUS to this and another peer via the best common IP scope and path - */ - void introduce(void *const tPtr,const int64_t now,const SharedPtr &other) const; - - /** - * Send a HELLO to this peer at a specified physical address - * - * No statistics or sent times are updated here. - * - * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call - * @param localSocket Local source socket - * @param atAddress Destination address - * @param now Current time - */ - void sendHELLO(void *tPtr,const int64_t localSocket,const InetAddress &atAddress,int64_t now); - - /** - * Send ECHO (or HELLO for older peers) to this peer at the given address - * - * No statistics or sent times are updated here. - * - * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call - * @param localSocket Local source socket - * @param atAddress Destination address - * @param now Current time - * @param sendFullHello If true, always send a full HELLO instead of just an ECHO - */ - void attemptToContactAt(void *tPtr,const int64_t localSocket,const InetAddress &atAddress,int64_t now,bool sendFullHello); - - /** - * Try a memorized or statically defined path if any are known - * - * Under the hood this is done periodically based on ZT_TRY_MEMORIZED_PATH_INTERVAL. - * - * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call - * @param now Current time - */ - void tryMemorizedPath(void *tPtr,int64_t now); - - /** - * A check to be performed periodically which determines whether multipath communication is - * possible with this peer. This check should be performed early in the life-cycle of the peer - * as well as during the process of learning new paths. - */ - void performMultipathStateCheck(void *tPtr, int64_t now); - - /** - * Send pings or keepalives depending on configured timeouts - * - * This also cleans up some internal data structures. It's called periodically from Node. - * - * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call - * @param now Current time - * @param inetAddressFamily Keep this address family alive, or -1 for any - * @return 0 if nothing sent or bit mask: bit 0x1 if IPv4 sent, bit 0x2 if IPv6 sent (0x3 means both sent) - */ - unsigned int doPingAndKeepalive(void *tPtr,int64_t now); - - /** - * Process a cluster redirect sent by this peer - * - * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call - * @param originatingPath Path from which redirect originated - * @param remoteAddress Remote address - * @param now Current time - */ - void clusterRedirect(void *tPtr,const SharedPtr &originatingPath,const InetAddress &remoteAddress,const int64_t now); - - /** - * Reset paths within a given IP scope and address family - * - * Resetting a path involves sending an ECHO to it and then deactivating - * it until or unless it responds. This is done when we detect a change - * to our external IP or another system change that might invalidate - * many or all current paths. - * - * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call - * @param scope IP scope - * @param inetAddressFamily Family e.g. AF_INET - * @param now Current time - */ - void resetWithinScope(void *tPtr,InetAddress::IpScope scope,int inetAddressFamily,int64_t now); - - /** - * @param now Current time - * @return All known paths to this peer - */ - inline std::vector< SharedPtr > paths(const int64_t now) const - { - std::vector< SharedPtr > pp; - Mutex::Lock _l(_paths_m); - for(unsigned int i=0;i bp(getAppropriatePath(now,false)); - if (bp) { - return (unsigned int)bp->latency(); - } - return 0xffff; - } - } - - /** - * This computes a quality score for relays and root servers - * - * If we haven't heard anything from these in ZT_PEER_ACTIVITY_TIMEOUT, they - * receive the worst possible quality (max unsigned int). Otherwise the - * quality is a product of latency and the number of potential missed - * pings. This causes roots and relays to switch over a bit faster if they - * fail. - * - * @return Relay quality score computed from latency and other factors, lower is better - */ - inline unsigned int relayQuality(const int64_t now) - { - const uint64_t tsr = now - _lastReceive; - if (tsr >= ZT_PEER_ACTIVITY_TIMEOUT) { - return (~(unsigned int)0); - } - unsigned int l = latency(now); - if (!l) { - l = 0xffff; - } - return (l * (((unsigned int)tsr / (ZT_PEER_PING_PERIOD + 1000)) + 1)); - } - - /** - * @return 256-bit secret symmetric encryption key - */ - inline const unsigned char *key() const { return _key; } - - /** - * Set the currently known remote version of this peer's client - * - * @param vproto Protocol version - * @param vmaj Major version - * @param vmin Minor version - * @param vrev Revision - */ - inline void setRemoteVersion(unsigned int vproto,unsigned int vmaj,unsigned int vmin,unsigned int vrev) - { - _vProto = (uint16_t)vproto; - _vMajor = (uint16_t)vmaj; - _vMinor = (uint16_t)vmin; - _vRevision = (uint16_t)vrev; - } - - inline unsigned int remoteVersionProtocol() const { return _vProto; } - inline unsigned int remoteVersionMajor() const { return _vMajor; } - inline unsigned int remoteVersionMinor() const { return _vMinor; } - inline unsigned int remoteVersionRevision() const { return _vRevision; } - - inline bool remoteVersionKnown() const { return ((_vMajor > 0)||(_vMinor > 0)||(_vRevision > 0)); } - - /** - * @return True if peer has received a trust established packet (e.g. common network membership) in the past ZT_TRUST_EXPIRATION ms - */ - inline bool trustEstablished(const int64_t now) const { return ((now - _lastTrustEstablishedPacketReceived) < ZT_TRUST_EXPIRATION); } - - /** - * Rate limit gate for VERB_PUSH_DIRECT_PATHS - */ - inline bool rateGatePushDirectPaths(const int64_t now) - { - if ((now - _lastDirectPathPushReceive) <= ZT_PUSH_DIRECT_PATHS_CUTOFF_TIME) { - ++_directPathPushCutoffCount; - } else { - _directPathPushCutoffCount = 0; - } - _lastDirectPathPushReceive = now; - return (_directPathPushCutoffCount < ZT_PUSH_DIRECT_PATHS_CUTOFF_LIMIT); - } - - /** - * Rate limit gate for VERB_NETWORK_CREDENTIALS - */ - inline bool rateGateCredentialsReceived(const int64_t now) - { - if ((now - _lastCredentialsReceived) >= ZT_PEER_CREDENTIALS_RATE_LIMIT) { - _lastCredentialsReceived = now; - return true; - } - return false; - } - - /** - * Rate limit gate for sending of ERROR_NEED_MEMBERSHIP_CERTIFICATE - */ - inline bool rateGateRequestCredentials(const int64_t now) - { - if ((now - _lastCredentialRequestSent) >= ZT_PEER_GENERAL_RATE_LIMIT) { - _lastCredentialRequestSent = now; - return true; - } - return false; - } - - /** - * Rate limit gate for inbound WHOIS requests - */ - inline bool rateGateInboundWhoisRequest(const int64_t now) - { - if ((now - _lastWhoisRequestReceived) >= ZT_PEER_WHOIS_RATE_LIMIT) { - _lastWhoisRequestReceived = now; - return true; - } - return false; - } - - /** - * See definition in Bond - */ - inline bool rateGateQoS(int64_t now, SharedPtr& path) - { - Mutex::Lock _l(_bond_m); - if(_bond) { - return _bond->rateGateQoS(now, path); - } - return false; // Default behavior. If there is no bond, we drop these - } - - /** - * See definition in Bond - */ - void receivedQoS(const SharedPtr& path, int64_t now, int count, uint64_t* rx_id, uint16_t* rx_ts) - { - Mutex::Lock _l(_bond_m); - if(_bond) { - _bond->receivedQoS(path, now, count, rx_id, rx_ts); - } - } - - /** - * See definition in Bond - */ - void processIncomingPathNegotiationRequest(uint64_t now, SharedPtr& path, int16_t remoteUtility) - { - Mutex::Lock _l(_bond_m); - if(_bond) { - _bond->processIncomingPathNegotiationRequest(now, path, remoteUtility); - } - } - - /** - * See definition in Bond - */ - inline bool rateGatePathNegotiation(int64_t now, SharedPtr& path) - { - Mutex::Lock _l(_bond_m); - if(_bond) { - return _bond->rateGatePathNegotiation(now, path); - } - return false; // Default behavior. If there is no bond, we drop these - } - - /** - * See definition in Bond - */ - bool flowHashingSupported() - { - Mutex::Lock _l(_bond_m); - if(_bond) { - return _bond->flowHashingSupported(); - } - return false; - } - - /** - * Serialize a peer for storage in local cache - * - * This does not serialize everything, just non-ephemeral information. - */ - template - inline void serializeForCache(Buffer &b) const - { - b.append((uint8_t)2); - - _id.serialize(b); - - b.append((uint16_t)_vProto); - b.append((uint16_t)_vMajor); - b.append((uint16_t)_vMinor); - b.append((uint16_t)_vRevision); - - { - Mutex::Lock _l(_paths_m); - unsigned int pc = 0; - for(unsigned int i=0;iaddress().serialize(b); - } - } - } - - template - inline static SharedPtr deserializeFromCache(int64_t now,void *tPtr,Buffer &b,const RuntimeEnvironment *renv) - { - try { - unsigned int ptr = 0; - if (b[ptr++] != 2) { - return SharedPtr(); - } - - Identity id; - ptr += id.deserialize(b,ptr); - if (!id) { - return SharedPtr(); - } - - SharedPtr p(new Peer(renv,renv->identity,id)); - - p->_vProto = b.template at(ptr); - ptr += 2; - p->_vMajor = b.template at(ptr); - ptr += 2; - p->_vMinor = b.template at(ptr); - ptr += 2; - p->_vRevision = b.template at(ptr); - ptr += 2; - - // When we deserialize from the cache we don't actually restore paths. We - // just try them and then re-learn them if they happen to still be up. - // Paths are fairly ephemeral in the real world in most cases. - const unsigned int tryPathCount = b.template at(ptr); - ptr += 2; - for(unsigned int i=0;iattemptToContactAt(tPtr,-1,inaddr,now,true); - } - } catch ( ... ) { - break; - } - } - - return p; - } catch ( ... ) { - return SharedPtr(); - } - } - - /** - * @return The bonding policy used to reach this peer - */ - SharedPtr bond() { return _bond; } - - /** - * @return The bonding policy used to reach this peer - */ - inline int8_t bondingPolicy() { - Mutex::Lock _l(_bond_m); - if (_bond) { - return _bond->policy(); - } - return ZT_BOND_POLICY_NONE; - } - - /** - * @return the number of links in this bond which are considered alive - */ - inline uint8_t getNumAliveLinks() { - Mutex::Lock _l(_paths_m); - if (_bond) { - return _bond->getNumAliveLinks(); - } - return 0; - } - - /** - * @return the number of links in this bond - */ - inline uint8_t getNumTotalLinks() { - Mutex::Lock _l(_paths_m); - if (_bond) { - return _bond->getNumTotalLinks(); - } - return 0; - } - - //inline const AES *aesKeysIfSupported() const - //{ return (const AES *)0; } - - inline const AES *aesKeysIfSupported() const - { return (_vProto >= 12) ? _aesKeys : (const AES *)0; } - - inline const AES *aesKeys() const - { return _aesKeys; } - -private: - struct _PeerPath - { - _PeerPath() : lr(0),p(),priority(1) {} - int64_t lr; // time of last valid ZeroTier packet - SharedPtr p; - long priority; // >= 1, higher is better - }; - - uint8_t _key[ZT_SYMMETRIC_KEY_SIZE]; - AES _aesKeys[2]; - - const RuntimeEnvironment *RR; - - int64_t _lastReceive; // direct or indirect - int64_t _lastNontrivialReceive; // frames, things like netconf, etc. - int64_t _lastTriedMemorizedPath; - int64_t _lastDirectPathPushSent; - int64_t _lastDirectPathPushReceive; - int64_t _lastCredentialRequestSent; - int64_t _lastWhoisRequestReceived; - int64_t _lastCredentialsReceived; - int64_t _lastTrustEstablishedPacketReceived; - int64_t _lastSentFullHello; - int64_t _lastEchoCheck; - - unsigned char _freeRandomByte; - - uint16_t _vProto; - uint16_t _vMajor; - uint16_t _vMinor; - uint16_t _vRevision; - - std::list< std::pair< Path *, int64_t > > _lastTriedPath; - Mutex _lastTriedPath_m; - - _PeerPath _paths[ZT_MAX_PEER_NETWORK_PATHS]; - Mutex _paths_m; - Mutex _bond_m; - - bool _isLeaf; - - Identity _id; - - unsigned int _directPathPushCutoffCount; - unsigned int _echoRequestCutoffCount; - - AtomicCounter __refCount; - - bool _localMultipathSupported; - - volatile bool _shouldCollectPathStatistics; - - int32_t _lastComputedAggregateMeanLatency; - - SharedPtr _bond; +class Peer { + friend class SharedPtr; + friend class SharedPtr; + friend class Switch; + friend class Bond; + + private: + Peer() = delete; // disabled to prevent bugs -- should not be constructed uninitialized + + public: + ~Peer() + { + Utils::burn(_key, sizeof(_key)); + } + + /** + * Construct a new peer + * + * @param renv Runtime environment + * @param myIdentity Identity of THIS node (for key agreement) + * @param peerIdentity Identity of peer + * @throws std::runtime_error Key agreement with peer's identity failed + */ + Peer(const RuntimeEnvironment* renv, const Identity& myIdentity, const Identity& peerIdentity); + + /** + * @return This peer's ZT address (short for identity().address()) + */ + inline const Address& address() const + { + return _id.address(); + } + + /** + * @return This peer's identity + */ + inline const Identity& identity() const + { + return _id; + } + + /** + * Log receipt of an authenticated packet + * + * This is called by the decode pipe when a packet is proven to be authentic + * and appears to be valid. + * + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call + * @param path Path over which packet was received + * @param hops ZeroTier (not IP) hops + * @param packetId Packet ID + * @param verb Packet verb + * @param inRePacketId Packet ID in reply to (default: none) + * @param inReVerb Verb in reply to (for OK/ERROR, default: VERB_NOP) + * @param trustEstablished If true, some form of non-trivial trust (like allowed in network) has been established + * @param networkId Network ID if this pertains to a network, or 0 otherwise + */ + void received( + void* tPtr, + const SharedPtr& path, + const unsigned int hops, + const uint64_t packetId, + const unsigned int payloadLength, + const Packet::Verb verb, + const uint64_t inRePacketId, + const Packet::Verb inReVerb, + const bool trustEstablished, + const uint64_t networkId, + const int32_t flowId); + + /** + * Check whether we have an active path to this peer via the given address + * + * @param now Current time + * @param addr Remote address + * @return True if we have an active path to this destination + */ + inline bool hasActivePathTo(int64_t now, const InetAddress& addr) const + { + Mutex::Lock _l(_paths_m); + for (unsigned int i = 0; i < ZT_MAX_PEER_NETWORK_PATHS; ++i) { + if (_paths[i].p) { + if (((now - _paths[i].lr) < ZT_PEER_PATH_EXPIRATION) && (_paths[i].p->address() == addr)) { + return true; + } + } + else { + break; + } + } + return false; + } + + /** + * Send via best direct path + * + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call + * @param data Packet data + * @param len Packet length + * @param now Current time + * @param force If true, send even if path is not alive + * @return True if we actually sent something + */ + inline bool sendDirect(void* tPtr, const void* data, unsigned int len, int64_t now, bool force) + { + SharedPtr bp(getAppropriatePath(now, force)); + if (bp) { + return bp->send(RR, tPtr, data, len, now); + } + return false; + } + + /** + * Record incoming packets to + * + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call + * @param path Path over which packet was received + * @param packetId Packet ID + * @param payloadLength Length of packet data payload + * @param verb Packet verb + * @param flowId Flow ID + * @param now Current time + */ + void recordIncomingPacket(const SharedPtr& path, const uint64_t packetId, uint16_t payloadLength, const Packet::Verb verb, const int32_t flowId, int64_t now); + + /** + * + * @param path Path over which packet is being sent + * @param packetId Packet ID + * @param payloadLength Length of packet data payload + * @param verb Packet verb + * @param flowId Flow ID + * @param now Current time + */ + void recordOutgoingPacket(const SharedPtr& path, const uint64_t packetId, uint16_t payloadLength, const Packet::Verb verb, const int32_t flowId, int64_t now); + + /** + * Record an invalid incoming packet. This packet failed + * MAC/compression/cipher checks and will now contribute to a + * Packet Error Ratio (PER). + * + * @param path Path over which packet was received + */ + void recordIncomingInvalidPacket(const SharedPtr& path); + + /** + * Get the most appropriate direct path based on current multipath and QoS configuration + * + * @param now Current time + * @param includeExpired If true, include even expired paths + * @return Best current path or NULL if none + */ + SharedPtr getAppropriatePath(int64_t now, bool includeExpired, int32_t flowId = -1); + + /** + * Send VERB_RENDEZVOUS to this and another peer via the best common IP scope and path + */ + void introduce(void* const tPtr, const int64_t now, const SharedPtr& other) const; + + /** + * Send a HELLO to this peer at a specified physical address + * + * No statistics or sent times are updated here. + * + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call + * @param localSocket Local source socket + * @param atAddress Destination address + * @param now Current time + */ + void sendHELLO(void* tPtr, const int64_t localSocket, const InetAddress& atAddress, int64_t now); + + /** + * Send ECHO (or HELLO for older peers) to this peer at the given address + * + * No statistics or sent times are updated here. + * + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call + * @param localSocket Local source socket + * @param atAddress Destination address + * @param now Current time + * @param sendFullHello If true, always send a full HELLO instead of just an ECHO + */ + void attemptToContactAt(void* tPtr, const int64_t localSocket, const InetAddress& atAddress, int64_t now, bool sendFullHello); + + /** + * Try a memorized or statically defined path if any are known + * + * Under the hood this is done periodically based on ZT_TRY_MEMORIZED_PATH_INTERVAL. + * + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call + * @param now Current time + */ + void tryMemorizedPath(void* tPtr, int64_t now); + + /** + * A check to be performed periodically which determines whether multipath communication is + * possible with this peer. This check should be performed early in the life-cycle of the peer + * as well as during the process of learning new paths. + */ + void performMultipathStateCheck(void* tPtr, int64_t now); + + /** + * Send pings or keepalives depending on configured timeouts + * + * This also cleans up some internal data structures. It's called periodically from Node. + * + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call + * @param now Current time + * @param inetAddressFamily Keep this address family alive, or -1 for any + * @return 0 if nothing sent or bit mask: bit 0x1 if IPv4 sent, bit 0x2 if IPv6 sent (0x3 means both sent) + */ + unsigned int doPingAndKeepalive(void* tPtr, int64_t now); + + /** + * Process a cluster redirect sent by this peer + * + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call + * @param originatingPath Path from which redirect originated + * @param remoteAddress Remote address + * @param now Current time + */ + void clusterRedirect(void* tPtr, const SharedPtr& originatingPath, const InetAddress& remoteAddress, const int64_t now); + + /** + * Reset paths within a given IP scope and address family + * + * Resetting a path involves sending an ECHO to it and then deactivating + * it until or unless it responds. This is done when we detect a change + * to our external IP or another system change that might invalidate + * many or all current paths. + * + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call + * @param scope IP scope + * @param inetAddressFamily Family e.g. AF_INET + * @param now Current time + */ + void resetWithinScope(void* tPtr, InetAddress::IpScope scope, int inetAddressFamily, int64_t now); + + /** + * @param now Current time + * @return All known paths to this peer + */ + inline std::vector > paths(const int64_t now) const + { + std::vector > pp; + Mutex::Lock _l(_paths_m); + for (unsigned int i = 0; i < ZT_MAX_PEER_NETWORK_PATHS; ++i) { + if (! _paths[i].p) { + break; + } + pp.push_back(_paths[i].p); + } + return pp; + } + + /** + * @return Time of last receive of anything, whether direct or relayed + */ + inline int64_t lastReceive() const + { + return _lastReceive; + } + + /** + * @return True if we've heard from this peer in less than ZT_PEER_ACTIVITY_TIMEOUT + */ + inline bool isAlive(const int64_t now) const + { + return ((now - _lastReceive) < ZT_PEER_ACTIVITY_TIMEOUT); + } + + /** + * @return True if this peer has sent us real network traffic recently + */ + inline int64_t isActive(int64_t now) const + { + return ((now - _lastNontrivialReceive) < ZT_PEER_ACTIVITY_TIMEOUT); + } + + inline int64_t lastSentFullHello() + { + return _lastSentFullHello; + } + + /** + * @return Latency in milliseconds of best/aggregate path or 0xffff if unknown / no paths + */ + inline unsigned int latency(const int64_t now) + { + if (_localMultipathSupported) { + return (int)_lastComputedAggregateMeanLatency; + } + else { + SharedPtr bp(getAppropriatePath(now, false)); + if (bp) { + return (unsigned int)bp->latency(); + } + return 0xffff; + } + } + + /** + * This computes a quality score for relays and root servers + * + * If we haven't heard anything from these in ZT_PEER_ACTIVITY_TIMEOUT, they + * receive the worst possible quality (max unsigned int). Otherwise the + * quality is a product of latency and the number of potential missed + * pings. This causes roots and relays to switch over a bit faster if they + * fail. + * + * @return Relay quality score computed from latency and other factors, lower is better + */ + inline unsigned int relayQuality(const int64_t now) + { + const uint64_t tsr = now - _lastReceive; + if (tsr >= ZT_PEER_ACTIVITY_TIMEOUT) { + return (~(unsigned int)0); + } + unsigned int l = latency(now); + if (! l) { + l = 0xffff; + } + return (l * (((unsigned int)tsr / (ZT_PEER_PING_PERIOD + 1000)) + 1)); + } + + /** + * @return 256-bit secret symmetric encryption key + */ + inline const unsigned char* key() const + { + return _key; + } + + /** + * Set the currently known remote version of this peer's client + * + * @param vproto Protocol version + * @param vmaj Major version + * @param vmin Minor version + * @param vrev Revision + */ + inline void setRemoteVersion(unsigned int vproto, unsigned int vmaj, unsigned int vmin, unsigned int vrev) + { + _vProto = (uint16_t)vproto; + _vMajor = (uint16_t)vmaj; + _vMinor = (uint16_t)vmin; + _vRevision = (uint16_t)vrev; + } + + inline unsigned int remoteVersionProtocol() const + { + return _vProto; + } + inline unsigned int remoteVersionMajor() const + { + return _vMajor; + } + inline unsigned int remoteVersionMinor() const + { + return _vMinor; + } + inline unsigned int remoteVersionRevision() const + { + return _vRevision; + } + + inline bool remoteVersionKnown() const + { + return ((_vMajor > 0) || (_vMinor > 0) || (_vRevision > 0)); + } + + /** + * @return True if peer has received a trust established packet (e.g. common network membership) in the past ZT_TRUST_EXPIRATION ms + */ + inline bool trustEstablished(const int64_t now) const + { + return ((now - _lastTrustEstablishedPacketReceived) < ZT_TRUST_EXPIRATION); + } + + /** + * Rate limit gate for VERB_PUSH_DIRECT_PATHS + */ + inline bool rateGatePushDirectPaths(const int64_t now) + { + if ((now - _lastDirectPathPushReceive) <= ZT_PUSH_DIRECT_PATHS_CUTOFF_TIME) { + ++_directPathPushCutoffCount; + } + else { + _directPathPushCutoffCount = 0; + } + _lastDirectPathPushReceive = now; + return (_directPathPushCutoffCount < ZT_PUSH_DIRECT_PATHS_CUTOFF_LIMIT); + } + + /** + * Rate limit gate for VERB_NETWORK_CREDENTIALS + */ + inline bool rateGateCredentialsReceived(const int64_t now) + { + if ((now - _lastCredentialsReceived) >= ZT_PEER_CREDENTIALS_RATE_LIMIT) { + _lastCredentialsReceived = now; + return true; + } + return false; + } + + /** + * Rate limit gate for sending of ERROR_NEED_MEMBERSHIP_CERTIFICATE + */ + inline bool rateGateRequestCredentials(const int64_t now) + { + if ((now - _lastCredentialRequestSent) >= ZT_PEER_GENERAL_RATE_LIMIT) { + _lastCredentialRequestSent = now; + return true; + } + return false; + } + + /** + * Rate limit gate for inbound WHOIS requests + */ + inline bool rateGateInboundWhoisRequest(const int64_t now) + { + if ((now - _lastWhoisRequestReceived) >= ZT_PEER_WHOIS_RATE_LIMIT) { + _lastWhoisRequestReceived = now; + return true; + } + return false; + } + + /** + * See definition in Bond + */ + inline bool rateGateQoS(int64_t now, SharedPtr& path) + { + Mutex::Lock _l(_bond_m); + if (_bond) { + return _bond->rateGateQoS(now, path); + } + return false; // Default behavior. If there is no bond, we drop these + } + + /** + * See definition in Bond + */ + void receivedQoS(const SharedPtr& path, int64_t now, int count, uint64_t* rx_id, uint16_t* rx_ts) + { + Mutex::Lock _l(_bond_m); + if (_bond) { + _bond->receivedQoS(path, now, count, rx_id, rx_ts); + } + } + + /** + * See definition in Bond + */ + void processIncomingPathNegotiationRequest(uint64_t now, SharedPtr& path, int16_t remoteUtility) + { + Mutex::Lock _l(_bond_m); + if (_bond) { + _bond->processIncomingPathNegotiationRequest(now, path, remoteUtility); + } + } + + /** + * See definition in Bond + */ + inline bool rateGatePathNegotiation(int64_t now, SharedPtr& path) + { + Mutex::Lock _l(_bond_m); + if (_bond) { + return _bond->rateGatePathNegotiation(now, path); + } + return false; // Default behavior. If there is no bond, we drop these + } + + /** + * See definition in Bond + */ + bool flowHashingSupported() + { + Mutex::Lock _l(_bond_m); + if (_bond) { + return _bond->flowHashingSupported(); + } + return false; + } + + /** + * Serialize a peer for storage in local cache + * + * This does not serialize everything, just non-ephemeral information. + */ + template inline void serializeForCache(Buffer& b) const + { + b.append((uint8_t)2); + + _id.serialize(b); + + b.append((uint16_t)_vProto); + b.append((uint16_t)_vMajor); + b.append((uint16_t)_vMinor); + b.append((uint16_t)_vRevision); + + { + Mutex::Lock _l(_paths_m); + unsigned int pc = 0; + for (unsigned int i = 0; i < ZT_MAX_PEER_NETWORK_PATHS; ++i) { + if (_paths[i].p) { + ++pc; + } + else { + break; + } + } + b.append((uint16_t)pc); + for (unsigned int i = 0; i < pc; ++i) { + _paths[i].p->address().serialize(b); + } + } + } + + template inline static SharedPtr deserializeFromCache(int64_t now, void* tPtr, Buffer& b, const RuntimeEnvironment* renv) + { + try { + unsigned int ptr = 0; + if (b[ptr++] != 2) { + return SharedPtr(); + } + + Identity id; + ptr += id.deserialize(b, ptr); + if (! id) { + return SharedPtr(); + } + + SharedPtr p(new Peer(renv, renv->identity, id)); + + p->_vProto = b.template at(ptr); + ptr += 2; + p->_vMajor = b.template at(ptr); + ptr += 2; + p->_vMinor = b.template at(ptr); + ptr += 2; + p->_vRevision = b.template at(ptr); + ptr += 2; + + // When we deserialize from the cache we don't actually restore paths. We + // just try them and then re-learn them if they happen to still be up. + // Paths are fairly ephemeral in the real world in most cases. + const unsigned int tryPathCount = b.template at(ptr); + ptr += 2; + for (unsigned int i = 0; i < tryPathCount; ++i) { + InetAddress inaddr; + try { + ptr += inaddr.deserialize(b, ptr); + if (inaddr) { + p->attemptToContactAt(tPtr, -1, inaddr, now, true); + } + } + catch (...) { + break; + } + } + + return p; + } + catch (...) { + return SharedPtr(); + } + } + + /** + * @return The bonding policy used to reach this peer + */ + SharedPtr bond() + { + return _bond; + } + + /** + * @return The bonding policy used to reach this peer + */ + inline int8_t bondingPolicy() + { + Mutex::Lock _l(_bond_m); + if (_bond) { + return _bond->policy(); + } + return ZT_BOND_POLICY_NONE; + } + + /** + * @return the number of links in this bond which are considered alive + */ + inline uint8_t getNumAliveLinks() + { + Mutex::Lock _l(_paths_m); + if (_bond) { + return _bond->getNumAliveLinks(); + } + return 0; + } + + /** + * @return the number of links in this bond + */ + inline uint8_t getNumTotalLinks() + { + Mutex::Lock _l(_paths_m); + if (_bond) { + return _bond->getNumTotalLinks(); + } + return 0; + } + + // inline const AES *aesKeysIfSupported() const + //{ return (const AES *)0; } + + inline const AES* aesKeysIfSupported() const + { + return (_vProto >= 12) ? _aesKeys : (const AES*)0; + } + + inline const AES* aesKeys() const + { + return _aesKeys; + } + + private: + struct _PeerPath { + _PeerPath() : lr(0), p(), priority(1) + { + } + int64_t lr; // time of last valid ZeroTier packet + SharedPtr p; + long priority; // >= 1, higher is better + }; + + uint8_t _key[ZT_SYMMETRIC_KEY_SIZE]; + AES _aesKeys[2]; + + const RuntimeEnvironment* RR; + + int64_t _lastReceive; // direct or indirect + int64_t _lastNontrivialReceive; // frames, things like netconf, etc. + int64_t _lastTriedMemorizedPath; + int64_t _lastDirectPathPushSent; + int64_t _lastDirectPathPushReceive; + int64_t _lastCredentialRequestSent; + int64_t _lastWhoisRequestReceived; + int64_t _lastCredentialsReceived; + int64_t _lastTrustEstablishedPacketReceived; + int64_t _lastSentFullHello; + int64_t _lastEchoCheck; + + unsigned char _freeRandomByte; + + uint16_t _vProto; + uint16_t _vMajor; + uint16_t _vMinor; + uint16_t _vRevision; + + std::list > _lastTriedPath; + Mutex _lastTriedPath_m; + + _PeerPath _paths[ZT_MAX_PEER_NETWORK_PATHS]; + Mutex _paths_m; + Mutex _bond_m; + + bool _isLeaf; + + Identity _id; + + unsigned int _directPathPushCutoffCount; + unsigned int _echoRequestCutoffCount; + + AtomicCounter __refCount; + + bool _localMultipathSupported; + + volatile bool _shouldCollectPathStatistics; + + int32_t _lastComputedAggregateMeanLatency; + + SharedPtr _bond; #ifndef ZT_NO_PEER_METRICS - prometheus::Histogram &_peer_latency; - prometheus::simpleapi::gauge_metric_t _alive_path_count; - prometheus::simpleapi::gauge_metric_t _dead_path_count; - prometheus::simpleapi::counter_metric_t _incoming_packet; - prometheus::simpleapi::counter_metric_t _outgoing_packet; - prometheus::simpleapi::counter_metric_t _packet_errors; + prometheus::Histogram& _peer_latency; + prometheus::simpleapi::gauge_metric_t _alive_path_count; + prometheus::simpleapi::gauge_metric_t _dead_path_count; + prometheus::simpleapi::counter_metric_t _incoming_packet; + prometheus::simpleapi::counter_metric_t _outgoing_packet; + prometheus::simpleapi::counter_metric_t _packet_errors; #endif }; -} // namespace ZeroTier +} // namespace ZeroTier // Add a swap() for shared ptr's to peers to speed up peer sorts namespace std { - template<> - inline void swap(ZeroTier::SharedPtr &a,ZeroTier::SharedPtr &b) - { - a.swap(b); - } +template <> inline void swap(ZeroTier::SharedPtr& a, ZeroTier::SharedPtr& b) +{ + a.swap(b); } +} // namespace std #endif diff --git a/node/Poly1305.cpp b/node/Poly1305.cpp index 38246513..9fb0e2d3 100644 --- a/node/Poly1305.cpp +++ b/node/Poly1305.cpp @@ -4,16 +4,17 @@ D. J. Bernstein Public domain. */ -#include "Constants.hpp" #include "Poly1305.hpp" -#include +#include "Constants.hpp" + #include +#include #include #include #ifdef __WINDOWS__ -#pragma warning(disable: 4146) +#pragma warning(disable : 4146) #endif namespace ZeroTier { @@ -21,8 +22,8 @@ namespace ZeroTier { namespace { typedef struct poly1305_context { - size_t aligner; - unsigned char opaque[136]; + size_t aligner; + unsigned char opaque[136]; } poly1305_context; #if (defined(_MSC_VER) || defined(__GNUC__)) && (defined(__amd64) || defined(__amd64__) || defined(__x86_64) || defined(__x86_64__) || defined(__AMD64) || defined(__AMD64__) || defined(_M_X64)) @@ -31,32 +32,42 @@ typedef struct poly1305_context { // 128-bit implementation for MSC and GCC from Poly1305-donna #if defined(_MSC_VER) - #include +#include - typedef struct uint128_t { +typedef struct uint128_t { unsigned long long lo; unsigned long long hi; - } uint128_t; +} uint128_t; - #define MUL(out, x, y) out.lo = _umul128((x), (y), &out.hi) - #define ADD(out, in) { unsigned long long t = out.lo; out.lo += in.lo; out.hi += (out.lo < t) + in.hi; } - #define ADDLO(out, in) { unsigned long long t = out.lo; out.lo += in; out.hi += (out.lo < t); } - #define SHR(in, shift) (__shiftright128(in.lo, in.hi, (shift))) - #define LO(in) (in.lo) +#define MUL(out, x, y) out.lo = _umul128((x), (y), &out.hi) +#define ADD(out, in) \ + { \ + unsigned long long t = out.lo; \ + out.lo += in.lo; \ + out.hi += (out.lo < t) + in.hi; \ + } +#define ADDLO(out, in) \ + { \ + unsigned long long t = out.lo; \ + out.lo += in; \ + out.hi += (out.lo < t); \ + } +#define SHR(in, shift) (__shiftright128(in.lo, in.hi, (shift))) +#define LO(in) (in.lo) // #define POLY1305_NOINLINE __declspec(noinline) #elif defined(__GNUC__) - #if defined(__SIZEOF_INT128__) - typedef unsigned __int128 uint128_t; - #else - typedef unsigned uint128_t __attribute__((mode(TI))); - #endif +#if defined(__SIZEOF_INT128__) +typedef unsigned __int128 uint128_t; +#else +typedef unsigned uint128_t __attribute__((mode(TI))); +#endif - #define MUL(out, x, y) out = ((uint128_t)x * y) - #define ADD(out, in) out += in - #define ADDLO(out, in) out += in - #define SHR(in, shift) (unsigned long long)(in >> (shift)) - #define LO(in) (unsigned long long)(in) +#define MUL(out, x, y) out = ((uint128_t)x * y) +#define ADD(out, in) out += in +#define ADDLO(out, in) out += in +#define SHR(in, shift) (unsigned long long)(in >> (shift)) +#define LO(in) (unsigned long long)(in) // #define POLY1305_NOINLINE __attribute__((noinline)) #endif @@ -65,192 +76,228 @@ typedef struct poly1305_context { /* 17 + sizeof(size_t) + 8*sizeof(unsigned long long) */ typedef struct poly1305_state_internal_t { - unsigned long long r[3]; - unsigned long long h[3]; - unsigned long long pad[2]; - size_t leftover; - unsigned char buffer[poly1305_block_size]; - unsigned char final; + unsigned long long r[3]; + unsigned long long h[3]; + unsigned long long pad[2]; + size_t leftover; + unsigned char buffer[poly1305_block_size]; + unsigned char final; } poly1305_state_internal_t; #if defined(ZT_NO_TYPE_PUNNING) || (__BYTE_ORDER != __LITTLE_ENDIAN) -static inline unsigned long long U8TO64(const unsigned char *p) +static inline unsigned long long U8TO64(const unsigned char* p) { - return - (((unsigned long long)(p[0] & 0xff) ) | - ((unsigned long long)(p[1] & 0xff) << 8) | - ((unsigned long long)(p[2] & 0xff) << 16) | - ((unsigned long long)(p[3] & 0xff) << 24) | - ((unsigned long long)(p[4] & 0xff) << 32) | - ((unsigned long long)(p[5] & 0xff) << 40) | - ((unsigned long long)(p[6] & 0xff) << 48) | - ((unsigned long long)(p[7] & 0xff) << 56)); + return ( + ((unsigned long long)(p[0] & 0xff)) | ((unsigned long long)(p[1] & 0xff) << 8) | ((unsigned long long)(p[2] & 0xff) << 16) | ((unsigned long long)(p[3] & 0xff) << 24) | ((unsigned long long)(p[4] & 0xff) << 32) + | ((unsigned long long)(p[5] & 0xff) << 40) | ((unsigned long long)(p[6] & 0xff) << 48) | ((unsigned long long)(p[7] & 0xff) << 56)); } #else -#define U8TO64(p) (*reinterpret_cast(p)) +#define U8TO64(p) (*reinterpret_cast(p)) #endif #if defined(ZT_NO_TYPE_PUNNING) || (__BYTE_ORDER != __LITTLE_ENDIAN) -static inline void U64TO8(unsigned char *p, unsigned long long v) +static inline void U64TO8(unsigned char* p, unsigned long long v) { - p[0] = (v ) & 0xff; - p[1] = (v >> 8) & 0xff; - p[2] = (v >> 16) & 0xff; - p[3] = (v >> 24) & 0xff; - p[4] = (v >> 32) & 0xff; - p[5] = (v >> 40) & 0xff; - p[6] = (v >> 48) & 0xff; - p[7] = (v >> 56) & 0xff; + p[0] = (v) & 0xff; + p[1] = (v >> 8) & 0xff; + p[2] = (v >> 16) & 0xff; + p[3] = (v >> 24) & 0xff; + p[4] = (v >> 32) & 0xff; + p[5] = (v >> 40) & 0xff; + p[6] = (v >> 48) & 0xff; + p[7] = (v >> 56) & 0xff; } #else -#define U64TO8(p,v) ((*reinterpret_cast(p)) = (v)) +#define U64TO8(p, v) ((*reinterpret_cast(p)) = (v)) #endif -static inline void poly1305_init(poly1305_context *ctx, const unsigned char key[32]) { - poly1305_state_internal_t *st = (poly1305_state_internal_t *)ctx; - unsigned long long t0,t1; +static inline void poly1305_init(poly1305_context* ctx, const unsigned char key[32]) +{ + poly1305_state_internal_t* st = (poly1305_state_internal_t*)ctx; + unsigned long long t0, t1; - /* r &= 0xffffffc0ffffffc0ffffffc0fffffff */ - t0 = U8TO64(&key[0]); - t1 = U8TO64(&key[8]); + /* r &= 0xffffffc0ffffffc0ffffffc0fffffff */ + t0 = U8TO64(&key[0]); + t1 = U8TO64(&key[8]); - st->r[0] = ( t0 ) & 0xffc0fffffff; - st->r[1] = ((t0 >> 44) | (t1 << 20)) & 0xfffffc0ffff; - st->r[2] = ((t1 >> 24) ) & 0x00ffffffc0f; + st->r[0] = (t0) & 0xffc0fffffff; + st->r[1] = ((t0 >> 44) | (t1 << 20)) & 0xfffffc0ffff; + st->r[2] = ((t1 >> 24)) & 0x00ffffffc0f; - /* h = 0 */ - st->h[0] = 0; - st->h[1] = 0; - st->h[2] = 0; + /* h = 0 */ + st->h[0] = 0; + st->h[1] = 0; + st->h[2] = 0; - /* save pad for later */ - st->pad[0] = U8TO64(&key[16]); - st->pad[1] = U8TO64(&key[24]); + /* save pad for later */ + st->pad[0] = U8TO64(&key[16]); + st->pad[1] = U8TO64(&key[24]); - st->leftover = 0; - st->final = 0; + st->leftover = 0; + st->final = 0; } -static inline void poly1305_blocks(poly1305_state_internal_t *st, const unsigned char *m, size_t bytes) { - const unsigned long long hibit = (st->final) ? 0 : ((unsigned long long)1 << 40); /* 1 << 128 */ - unsigned long long r0,r1,r2; - unsigned long long s1,s2; - unsigned long long h0,h1,h2; - unsigned long long c; - uint128_t d0,d1,d2,d; +static inline void poly1305_blocks(poly1305_state_internal_t* st, const unsigned char* m, size_t bytes) +{ + const unsigned long long hibit = (st->final) ? 0 : ((unsigned long long)1 << 40); /* 1 << 128 */ + unsigned long long r0, r1, r2; + unsigned long long s1, s2; + unsigned long long h0, h1, h2; + unsigned long long c; + uint128_t d0, d1, d2, d; - r0 = st->r[0]; - r1 = st->r[1]; - r2 = st->r[2]; + r0 = st->r[0]; + r1 = st->r[1]; + r2 = st->r[2]; - h0 = st->h[0]; - h1 = st->h[1]; - h2 = st->h[2]; + h0 = st->h[0]; + h1 = st->h[1]; + h2 = st->h[2]; - s1 = r1 * (5 << 2); - s2 = r2 * (5 << 2); + s1 = r1 * (5 << 2); + s2 = r2 * (5 << 2); - while (bytes >= poly1305_block_size) { - unsigned long long t0,t1; + while (bytes >= poly1305_block_size) { + unsigned long long t0, t1; - /* h += m[i] */ - t0 = U8TO64(&m[0]); - t1 = U8TO64(&m[8]); + /* h += m[i] */ + t0 = U8TO64(&m[0]); + t1 = U8TO64(&m[8]); - h0 += (( t0 ) & 0xfffffffffff); - h1 += (((t0 >> 44) | (t1 << 20)) & 0xfffffffffff); - h2 += (((t1 >> 24) ) & 0x3ffffffffff) | hibit; + h0 += ((t0) & 0xfffffffffff); + h1 += (((t0 >> 44) | (t1 << 20)) & 0xfffffffffff); + h2 += (((t1 >> 24)) & 0x3ffffffffff) | hibit; - /* h *= r */ - MUL(d0, h0, r0); MUL(d, h1, s2); ADD(d0, d); MUL(d, h2, s1); ADD(d0, d); - MUL(d1, h0, r1); MUL(d, h1, r0); ADD(d1, d); MUL(d, h2, s2); ADD(d1, d); - MUL(d2, h0, r2); MUL(d, h1, r1); ADD(d2, d); MUL(d, h2, r0); ADD(d2, d); + /* h *= r */ + MUL(d0, h0, r0); + MUL(d, h1, s2); + ADD(d0, d); + MUL(d, h2, s1); + ADD(d0, d); + MUL(d1, h0, r1); + MUL(d, h1, r0); + ADD(d1, d); + MUL(d, h2, s2); + ADD(d1, d); + MUL(d2, h0, r2); + MUL(d, h1, r1); + ADD(d2, d); + MUL(d, h2, r0); + ADD(d2, d); - /* (partial) h %= p */ - c = SHR(d0, 44); h0 = LO(d0) & 0xfffffffffff; - ADDLO(d1, c); c = SHR(d1, 44); h1 = LO(d1) & 0xfffffffffff; - ADDLO(d2, c); c = SHR(d2, 42); h2 = LO(d2) & 0x3ffffffffff; - h0 += c * 5; c = (h0 >> 44); h0 = h0 & 0xfffffffffff; - h1 += c; + /* (partial) h %= p */ + c = SHR(d0, 44); + h0 = LO(d0) & 0xfffffffffff; + ADDLO(d1, c); + c = SHR(d1, 44); + h1 = LO(d1) & 0xfffffffffff; + ADDLO(d2, c); + c = SHR(d2, 42); + h2 = LO(d2) & 0x3ffffffffff; + h0 += c * 5; + c = (h0 >> 44); + h0 = h0 & 0xfffffffffff; + h1 += c; - m += poly1305_block_size; - bytes -= poly1305_block_size; - } - - st->h[0] = h0; - st->h[1] = h1; - st->h[2] = h2; -} - -static inline void poly1305_finish(poly1305_context *ctx, unsigned char mac[16]) { - poly1305_state_internal_t *st = (poly1305_state_internal_t *)ctx; - unsigned long long h0,h1,h2,c; - unsigned long long g0,g1,g2; - unsigned long long t0,t1; - - /* process the remaining block */ - if (st->leftover) { - size_t i = st->leftover; - st->buffer[i] = 1; - for (i = i + 1; i < poly1305_block_size; i++) { - st->buffer[i] = 0; + m += poly1305_block_size; + bytes -= poly1305_block_size; } - st->final = 1; - poly1305_blocks(st, st->buffer, poly1305_block_size); - } - /* fully carry h */ - h0 = st->h[0]; - h1 = st->h[1]; - h2 = st->h[2]; + st->h[0] = h0; + st->h[1] = h1; + st->h[2] = h2; +} - c = (h1 >> 44); h1 &= 0xfffffffffff; - h2 += c; c = (h2 >> 42); h2 &= 0x3ffffffffff; - h0 += c * 5; c = (h0 >> 44); h0 &= 0xfffffffffff; - h1 += c; c = (h1 >> 44); h1 &= 0xfffffffffff; - h2 += c; c = (h2 >> 42); h2 &= 0x3ffffffffff; - h0 += c * 5; c = (h0 >> 44); h0 &= 0xfffffffffff; - h1 += c; +static inline void poly1305_finish(poly1305_context* ctx, unsigned char mac[16]) +{ + poly1305_state_internal_t* st = (poly1305_state_internal_t*)ctx; + unsigned long long h0, h1, h2, c; + unsigned long long g0, g1, g2; + unsigned long long t0, t1; - /* compute h + -p */ - g0 = h0 + 5; c = (g0 >> 44); g0 &= 0xfffffffffff; - g1 = h1 + c; c = (g1 >> 44); g1 &= 0xfffffffffff; - g2 = h2 + c - ((unsigned long long)1 << 42); + /* process the remaining block */ + if (st->leftover) { + size_t i = st->leftover; + st->buffer[i] = 1; + for (i = i + 1; i < poly1305_block_size; i++) { + st->buffer[i] = 0; + } + st->final = 1; + poly1305_blocks(st, st->buffer, poly1305_block_size); + } - /* select h if h < p, or h + -p if h >= p */ - c = (g2 >> ((sizeof(unsigned long long) * 8) - 1)) - 1; - g0 &= c; - g1 &= c; - g2 &= c; - c = ~c; - h0 = (h0 & c) | g0; - h1 = (h1 & c) | g1; - h2 = (h2 & c) | g2; + /* fully carry h */ + h0 = st->h[0]; + h1 = st->h[1]; + h2 = st->h[2]; - /* h = (h + pad) */ - t0 = st->pad[0]; - t1 = st->pad[1]; + c = (h1 >> 44); + h1 &= 0xfffffffffff; + h2 += c; + c = (h2 >> 42); + h2 &= 0x3ffffffffff; + h0 += c * 5; + c = (h0 >> 44); + h0 &= 0xfffffffffff; + h1 += c; + c = (h1 >> 44); + h1 &= 0xfffffffffff; + h2 += c; + c = (h2 >> 42); + h2 &= 0x3ffffffffff; + h0 += c * 5; + c = (h0 >> 44); + h0 &= 0xfffffffffff; + h1 += c; - h0 += (( t0 ) & 0xfffffffffff) ; c = (h0 >> 44); h0 &= 0xfffffffffff; - h1 += (((t0 >> 44) | (t1 << 20)) & 0xfffffffffff) + c; c = (h1 >> 44); h1 &= 0xfffffffffff; - h2 += (((t1 >> 24) ) & 0x3ffffffffff) + c; h2 &= 0x3ffffffffff; + /* compute h + -p */ + g0 = h0 + 5; + c = (g0 >> 44); + g0 &= 0xfffffffffff; + g1 = h1 + c; + c = (g1 >> 44); + g1 &= 0xfffffffffff; + g2 = h2 + c - ((unsigned long long)1 << 42); - /* mac = h % (2^128) */ - h0 = ((h0 ) | (h1 << 44)); - h1 = ((h1 >> 20) | (h2 << 24)); + /* select h if h < p, or h + -p if h >= p */ + c = (g2 >> ((sizeof(unsigned long long) * 8) - 1)) - 1; + g0 &= c; + g1 &= c; + g2 &= c; + c = ~c; + h0 = (h0 & c) | g0; + h1 = (h1 & c) | g1; + h2 = (h2 & c) | g2; - U64TO8(&mac[0], h0); - U64TO8(&mac[8], h1); + /* h = (h + pad) */ + t0 = st->pad[0]; + t1 = st->pad[1]; - /* zero out the state */ - st->h[0] = 0; - st->h[1] = 0; - st->h[2] = 0; - st->r[0] = 0; - st->r[1] = 0; - st->r[2] = 0; - st->pad[0] = 0; - st->pad[1] = 0; + h0 += ((t0) & 0xfffffffffff); + c = (h0 >> 44); + h0 &= 0xfffffffffff; + h1 += (((t0 >> 44) | (t1 << 20)) & 0xfffffffffff) + c; + c = (h1 >> 44); + h1 &= 0xfffffffffff; + h2 += (((t1 >> 24)) & 0x3ffffffffff) + c; + h2 &= 0x3ffffffffff; + + /* mac = h % (2^128) */ + h0 = ((h0) | (h1 << 44)); + h1 = ((h1 >> 20) | (h2 << 24)); + + U64TO8(&mac[0], h0); + U64TO8(&mac[8], h1); + + /* zero out the state */ + st->h[0] = 0; + st->h[1] = 0; + st->h[2] = 0; + st->r[0] = 0; + st->r[1] = 0; + st->r[2] = 0; + st->pad[0] = 0; + st->pad[1] = 0; } ////////////////////////////////////////////////////////////////////////////// @@ -264,262 +311,291 @@ static inline void poly1305_finish(poly1305_context *ctx, unsigned char mac[16]) /* 17 + sizeof(size_t) + 14*sizeof(unsigned long) */ typedef struct poly1305_state_internal_t { - unsigned long r[5]; - unsigned long h[5]; - unsigned long pad[4]; - size_t leftover; - unsigned char buffer[poly1305_block_size]; - unsigned char final; + unsigned long r[5]; + unsigned long h[5]; + unsigned long pad[4]; + size_t leftover; + unsigned char buffer[poly1305_block_size]; + unsigned char final; } poly1305_state_internal_t; /* interpret four 8 bit unsigned integers as a 32 bit unsigned integer in little endian */ -static unsigned long -U8TO32(const unsigned char *p) { - return - (((unsigned long)(p[0] & 0xff) ) | - ((unsigned long)(p[1] & 0xff) << 8) | - ((unsigned long)(p[2] & 0xff) << 16) | - ((unsigned long)(p[3] & 0xff) << 24)); +static unsigned long U8TO32(const unsigned char* p) +{ + return (((unsigned long)(p[0] & 0xff)) | ((unsigned long)(p[1] & 0xff) << 8) | ((unsigned long)(p[2] & 0xff) << 16) | ((unsigned long)(p[3] & 0xff) << 24)); } /* store a 32 bit unsigned integer as four 8 bit unsigned integers in little endian */ -static void -U32TO8(unsigned char *p, unsigned long v) { - p[0] = (v ) & 0xff; - p[1] = (v >> 8) & 0xff; - p[2] = (v >> 16) & 0xff; - p[3] = (v >> 24) & 0xff; +static void U32TO8(unsigned char* p, unsigned long v) +{ + p[0] = (v) & 0xff; + p[1] = (v >> 8) & 0xff; + p[2] = (v >> 16) & 0xff; + p[3] = (v >> 24) & 0xff; } -static inline void -poly1305_init(poly1305_context *ctx, const unsigned char key[32]) { - poly1305_state_internal_t *st = (poly1305_state_internal_t *)ctx; +static inline void poly1305_init(poly1305_context* ctx, const unsigned char key[32]) +{ + poly1305_state_internal_t* st = (poly1305_state_internal_t*)ctx; - /* r &= 0xffffffc0ffffffc0ffffffc0fffffff */ - st->r[0] = (U8TO32(&key[ 0]) ) & 0x3ffffff; - st->r[1] = (U8TO32(&key[ 3]) >> 2) & 0x3ffff03; - st->r[2] = (U8TO32(&key[ 6]) >> 4) & 0x3ffc0ff; - st->r[3] = (U8TO32(&key[ 9]) >> 6) & 0x3f03fff; - st->r[4] = (U8TO32(&key[12]) >> 8) & 0x00fffff; + /* r &= 0xffffffc0ffffffc0ffffffc0fffffff */ + st->r[0] = (U8TO32(&key[0])) & 0x3ffffff; + st->r[1] = (U8TO32(&key[3]) >> 2) & 0x3ffff03; + st->r[2] = (U8TO32(&key[6]) >> 4) & 0x3ffc0ff; + st->r[3] = (U8TO32(&key[9]) >> 6) & 0x3f03fff; + st->r[4] = (U8TO32(&key[12]) >> 8) & 0x00fffff; - /* h = 0 */ - st->h[0] = 0; - st->h[1] = 0; - st->h[2] = 0; - st->h[3] = 0; - st->h[4] = 0; + /* h = 0 */ + st->h[0] = 0; + st->h[1] = 0; + st->h[2] = 0; + st->h[3] = 0; + st->h[4] = 0; - /* save pad for later */ - st->pad[0] = U8TO32(&key[16]); - st->pad[1] = U8TO32(&key[20]); - st->pad[2] = U8TO32(&key[24]); - st->pad[3] = U8TO32(&key[28]); + /* save pad for later */ + st->pad[0] = U8TO32(&key[16]); + st->pad[1] = U8TO32(&key[20]); + st->pad[2] = U8TO32(&key[24]); + st->pad[3] = U8TO32(&key[28]); - st->leftover = 0; - st->final = 0; + st->leftover = 0; + st->final = 0; } -static inline void -poly1305_blocks(poly1305_state_internal_t *st, const unsigned char *m, size_t bytes) { - const unsigned long hibit = (st->final) ? 0 : (1 << 24); /* 1 << 128 */ - unsigned long r0,r1,r2,r3,r4; - unsigned long s1,s2,s3,s4; - unsigned long h0,h1,h2,h3,h4; - unsigned long long d0,d1,d2,d3,d4; - unsigned long c; +static inline void poly1305_blocks(poly1305_state_internal_t* st, const unsigned char* m, size_t bytes) +{ + const unsigned long hibit = (st->final) ? 0 : (1 << 24); /* 1 << 128 */ + unsigned long r0, r1, r2, r3, r4; + unsigned long s1, s2, s3, s4; + unsigned long h0, h1, h2, h3, h4; + unsigned long long d0, d1, d2, d3, d4; + unsigned long c; - r0 = st->r[0]; - r1 = st->r[1]; - r2 = st->r[2]; - r3 = st->r[3]; - r4 = st->r[4]; + r0 = st->r[0]; + r1 = st->r[1]; + r2 = st->r[2]; + r3 = st->r[3]; + r4 = st->r[4]; - s1 = r1 * 5; - s2 = r2 * 5; - s3 = r3 * 5; - s4 = r4 * 5; + s1 = r1 * 5; + s2 = r2 * 5; + s3 = r3 * 5; + s4 = r4 * 5; - h0 = st->h[0]; - h1 = st->h[1]; - h2 = st->h[2]; - h3 = st->h[3]; - h4 = st->h[4]; + h0 = st->h[0]; + h1 = st->h[1]; + h2 = st->h[2]; + h3 = st->h[3]; + h4 = st->h[4]; - while (bytes >= poly1305_block_size) { - /* h += m[i] */ - h0 += (U8TO32(m+ 0) ) & 0x3ffffff; - h1 += (U8TO32(m+ 3) >> 2) & 0x3ffffff; - h2 += (U8TO32(m+ 6) >> 4) & 0x3ffffff; - h3 += (U8TO32(m+ 9) >> 6) & 0x3ffffff; - h4 += (U8TO32(m+12) >> 8) | hibit; + while (bytes >= poly1305_block_size) { + /* h += m[i] */ + h0 += (U8TO32(m + 0)) & 0x3ffffff; + h1 += (U8TO32(m + 3) >> 2) & 0x3ffffff; + h2 += (U8TO32(m + 6) >> 4) & 0x3ffffff; + h3 += (U8TO32(m + 9) >> 6) & 0x3ffffff; + h4 += (U8TO32(m + 12) >> 8) | hibit; - /* h *= r */ - d0 = ((unsigned long long)h0 * r0) + ((unsigned long long)h1 * s4) + ((unsigned long long)h2 * s3) + ((unsigned long long)h3 * s2) + ((unsigned long long)h4 * s1); - d1 = ((unsigned long long)h0 * r1) + ((unsigned long long)h1 * r0) + ((unsigned long long)h2 * s4) + ((unsigned long long)h3 * s3) + ((unsigned long long)h4 * s2); - d2 = ((unsigned long long)h0 * r2) + ((unsigned long long)h1 * r1) + ((unsigned long long)h2 * r0) + ((unsigned long long)h3 * s4) + ((unsigned long long)h4 * s3); - d3 = ((unsigned long long)h0 * r3) + ((unsigned long long)h1 * r2) + ((unsigned long long)h2 * r1) + ((unsigned long long)h3 * r0) + ((unsigned long long)h4 * s4); - d4 = ((unsigned long long)h0 * r4) + ((unsigned long long)h1 * r3) + ((unsigned long long)h2 * r2) + ((unsigned long long)h3 * r1) + ((unsigned long long)h4 * r0); + /* h *= r */ + d0 = ((unsigned long long)h0 * r0) + ((unsigned long long)h1 * s4) + ((unsigned long long)h2 * s3) + ((unsigned long long)h3 * s2) + ((unsigned long long)h4 * s1); + d1 = ((unsigned long long)h0 * r1) + ((unsigned long long)h1 * r0) + ((unsigned long long)h2 * s4) + ((unsigned long long)h3 * s3) + ((unsigned long long)h4 * s2); + d2 = ((unsigned long long)h0 * r2) + ((unsigned long long)h1 * r1) + ((unsigned long long)h2 * r0) + ((unsigned long long)h3 * s4) + ((unsigned long long)h4 * s3); + d3 = ((unsigned long long)h0 * r3) + ((unsigned long long)h1 * r2) + ((unsigned long long)h2 * r1) + ((unsigned long long)h3 * r0) + ((unsigned long long)h4 * s4); + d4 = ((unsigned long long)h0 * r4) + ((unsigned long long)h1 * r3) + ((unsigned long long)h2 * r2) + ((unsigned long long)h3 * r1) + ((unsigned long long)h4 * r0); - /* (partial) h %= p */ - c = (unsigned long)(d0 >> 26); h0 = (unsigned long)d0 & 0x3ffffff; - d1 += c; c = (unsigned long)(d1 >> 26); h1 = (unsigned long)d1 & 0x3ffffff; - d2 += c; c = (unsigned long)(d2 >> 26); h2 = (unsigned long)d2 & 0x3ffffff; - d3 += c; c = (unsigned long)(d3 >> 26); h3 = (unsigned long)d3 & 0x3ffffff; - d4 += c; c = (unsigned long)(d4 >> 26); h4 = (unsigned long)d4 & 0x3ffffff; - h0 += c * 5; c = (h0 >> 26); h0 = h0 & 0x3ffffff; + /* (partial) h %= p */ + c = (unsigned long)(d0 >> 26); + h0 = (unsigned long)d0 & 0x3ffffff; + d1 += c; + c = (unsigned long)(d1 >> 26); + h1 = (unsigned long)d1 & 0x3ffffff; + d2 += c; + c = (unsigned long)(d2 >> 26); + h2 = (unsigned long)d2 & 0x3ffffff; + d3 += c; + c = (unsigned long)(d3 >> 26); + h3 = (unsigned long)d3 & 0x3ffffff; + d4 += c; + c = (unsigned long)(d4 >> 26); + h4 = (unsigned long)d4 & 0x3ffffff; + h0 += c * 5; + c = (h0 >> 26); + h0 = h0 & 0x3ffffff; + h1 += c; + + m += poly1305_block_size; + bytes -= poly1305_block_size; + } + + st->h[0] = h0; + st->h[1] = h1; + st->h[2] = h2; + st->h[3] = h3; + st->h[4] = h4; +} + +static inline void poly1305_finish(poly1305_context* ctx, unsigned char mac[16]) +{ + poly1305_state_internal_t* st = (poly1305_state_internal_t*)ctx; + unsigned long h0, h1, h2, h3, h4, c; + unsigned long g0, g1, g2, g3, g4; + unsigned long long f; + unsigned long mask; + + /* process the remaining block */ + if (st->leftover) { + size_t i = st->leftover; + st->buffer[i++] = 1; + for (; i < poly1305_block_size; i++) { + st->buffer[i] = 0; + } + st->final = 1; + poly1305_blocks(st, st->buffer, poly1305_block_size); + } + + /* fully carry h */ + h0 = st->h[0]; + h1 = st->h[1]; + h2 = st->h[2]; + h3 = st->h[3]; + h4 = st->h[4]; + + c = h1 >> 26; + h1 = h1 & 0x3ffffff; + h2 += c; + c = h2 >> 26; + h2 = h2 & 0x3ffffff; + h3 += c; + c = h3 >> 26; + h3 = h3 & 0x3ffffff; + h4 += c; + c = h4 >> 26; + h4 = h4 & 0x3ffffff; + h0 += c * 5; + c = h0 >> 26; + h0 = h0 & 0x3ffffff; h1 += c; - m += poly1305_block_size; - bytes -= poly1305_block_size; - } + /* compute h + -p */ + g0 = h0 + 5; + c = g0 >> 26; + g0 &= 0x3ffffff; + g1 = h1 + c; + c = g1 >> 26; + g1 &= 0x3ffffff; + g2 = h2 + c; + c = g2 >> 26; + g2 &= 0x3ffffff; + g3 = h3 + c; + c = g3 >> 26; + g3 &= 0x3ffffff; + g4 = h4 + c - (1 << 26); - st->h[0] = h0; - st->h[1] = h1; - st->h[2] = h2; - st->h[3] = h3; - st->h[4] = h4; -} + /* select h if h < p, or h + -p if h >= p */ + mask = (g4 >> ((sizeof(unsigned long) * 8) - 1)) - 1; + g0 &= mask; + g1 &= mask; + g2 &= mask; + g3 &= mask; + g4 &= mask; + mask = ~mask; + h0 = (h0 & mask) | g0; + h1 = (h1 & mask) | g1; + h2 = (h2 & mask) | g2; + h3 = (h3 & mask) | g3; + h4 = (h4 & mask) | g4; -static inline void -poly1305_finish(poly1305_context *ctx, unsigned char mac[16]) { - poly1305_state_internal_t *st = (poly1305_state_internal_t *)ctx; - unsigned long h0,h1,h2,h3,h4,c; - unsigned long g0,g1,g2,g3,g4; - unsigned long long f; - unsigned long mask; + /* h = h % (2^128) */ + h0 = ((h0) | (h1 << 26)) & 0xffffffff; + h1 = ((h1 >> 6) | (h2 << 20)) & 0xffffffff; + h2 = ((h2 >> 12) | (h3 << 14)) & 0xffffffff; + h3 = ((h3 >> 18) | (h4 << 8)) & 0xffffffff; - /* process the remaining block */ - if (st->leftover) { - size_t i = st->leftover; - st->buffer[i++] = 1; - for (; i < poly1305_block_size; i++) { - st->buffer[i] = 0; - } - st->final = 1; - poly1305_blocks(st, st->buffer, poly1305_block_size); - } + /* mac = (h + pad) % (2^128) */ + f = (unsigned long long)h0 + st->pad[0]; + h0 = (unsigned long)f; + f = (unsigned long long)h1 + st->pad[1] + (f >> 32); + h1 = (unsigned long)f; + f = (unsigned long long)h2 + st->pad[2] + (f >> 32); + h2 = (unsigned long)f; + f = (unsigned long long)h3 + st->pad[3] + (f >> 32); + h3 = (unsigned long)f; - /* fully carry h */ - h0 = st->h[0]; - h1 = st->h[1]; - h2 = st->h[2]; - h3 = st->h[3]; - h4 = st->h[4]; + U32TO8(mac + 0, h0); + U32TO8(mac + 4, h1); + U32TO8(mac + 8, h2); + U32TO8(mac + 12, h3); - c = h1 >> 26; h1 = h1 & 0x3ffffff; - h2 += c; c = h2 >> 26; h2 = h2 & 0x3ffffff; - h3 += c; c = h3 >> 26; h3 = h3 & 0x3ffffff; - h4 += c; c = h4 >> 26; h4 = h4 & 0x3ffffff; - h0 += c * 5; c = h0 >> 26; h0 = h0 & 0x3ffffff; - h1 += c; - - /* compute h + -p */ - g0 = h0 + 5; c = g0 >> 26; g0 &= 0x3ffffff; - g1 = h1 + c; c = g1 >> 26; g1 &= 0x3ffffff; - g2 = h2 + c; c = g2 >> 26; g2 &= 0x3ffffff; - g3 = h3 + c; c = g3 >> 26; g3 &= 0x3ffffff; - g4 = h4 + c - (1 << 26); - - /* select h if h < p, or h + -p if h >= p */ - mask = (g4 >> ((sizeof(unsigned long) * 8) - 1)) - 1; - g0 &= mask; - g1 &= mask; - g2 &= mask; - g3 &= mask; - g4 &= mask; - mask = ~mask; - h0 = (h0 & mask) | g0; - h1 = (h1 & mask) | g1; - h2 = (h2 & mask) | g2; - h3 = (h3 & mask) | g3; - h4 = (h4 & mask) | g4; - - /* h = h % (2^128) */ - h0 = ((h0 ) | (h1 << 26)) & 0xffffffff; - h1 = ((h1 >> 6) | (h2 << 20)) & 0xffffffff; - h2 = ((h2 >> 12) | (h3 << 14)) & 0xffffffff; - h3 = ((h3 >> 18) | (h4 << 8)) & 0xffffffff; - - /* mac = (h + pad) % (2^128) */ - f = (unsigned long long)h0 + st->pad[0] ; h0 = (unsigned long)f; - f = (unsigned long long)h1 + st->pad[1] + (f >> 32); h1 = (unsigned long)f; - f = (unsigned long long)h2 + st->pad[2] + (f >> 32); h2 = (unsigned long)f; - f = (unsigned long long)h3 + st->pad[3] + (f >> 32); h3 = (unsigned long)f; - - U32TO8(mac + 0, h0); - U32TO8(mac + 4, h1); - U32TO8(mac + 8, h2); - U32TO8(mac + 12, h3); - - /* zero out the state */ - st->h[0] = 0; - st->h[1] = 0; - st->h[2] = 0; - st->h[3] = 0; - st->h[4] = 0; - st->r[0] = 0; - st->r[1] = 0; - st->r[2] = 0; - st->r[3] = 0; - st->r[4] = 0; - st->pad[0] = 0; - st->pad[1] = 0; - st->pad[2] = 0; - st->pad[3] = 0; + /* zero out the state */ + st->h[0] = 0; + st->h[1] = 0; + st->h[2] = 0; + st->h[3] = 0; + st->h[4] = 0; + st->r[0] = 0; + st->r[1] = 0; + st->r[2] = 0; + st->r[3] = 0; + st->r[4] = 0; + st->pad[0] = 0; + st->pad[1] = 0; + st->pad[2] = 0; + st->pad[3] = 0; } ////////////////////////////////////////////////////////////////////////////// -#endif // MSC/GCC or not +#endif // MSC/GCC or not -static inline void poly1305_update(poly1305_context *ctx, const unsigned char *m, size_t bytes) { - poly1305_state_internal_t *st = (poly1305_state_internal_t *)ctx; - size_t i; - - /* handle leftover */ - if (st->leftover) { - size_t want = (poly1305_block_size - st->leftover); - if (want > bytes) { - want = bytes; - } - for (i = 0; i < want; i++) { - st->buffer[st->leftover + i] = m[i]; - } - bytes -= want; - m += want; - st->leftover += want; - if (st->leftover < poly1305_block_size) { - return; - } - poly1305_blocks(st, st->buffer, poly1305_block_size); - st->leftover = 0; - } - - /* process full blocks */ - if (bytes >= poly1305_block_size) { - size_t want = (bytes & ~(poly1305_block_size - 1)); - poly1305_blocks(st, m, want); - m += want; - bytes -= want; - } - - /* store leftover */ - if (bytes) { - for (i = 0; i < bytes; i++) { - st->buffer[st->leftover + i] = m[i]; - } - st->leftover += bytes; - } -} - -} // anonymous namespace - -void Poly1305::compute(void *auth,const void *data,unsigned int len,const void *key) +static inline void poly1305_update(poly1305_context* ctx, const unsigned char* m, size_t bytes) { - poly1305_context ctx; - poly1305_init(&ctx,reinterpret_cast(key)); - poly1305_update(&ctx,reinterpret_cast(data),(size_t)len); - poly1305_finish(&ctx,reinterpret_cast(auth)); + poly1305_state_internal_t* st = (poly1305_state_internal_t*)ctx; + size_t i; + + /* handle leftover */ + if (st->leftover) { + size_t want = (poly1305_block_size - st->leftover); + if (want > bytes) { + want = bytes; + } + for (i = 0; i < want; i++) { + st->buffer[st->leftover + i] = m[i]; + } + bytes -= want; + m += want; + st->leftover += want; + if (st->leftover < poly1305_block_size) { + return; + } + poly1305_blocks(st, st->buffer, poly1305_block_size); + st->leftover = 0; + } + + /* process full blocks */ + if (bytes >= poly1305_block_size) { + size_t want = (bytes & ~(poly1305_block_size - 1)); + poly1305_blocks(st, m, want); + m += want; + bytes -= want; + } + + /* store leftover */ + if (bytes) { + for (i = 0; i < bytes; i++) { + st->buffer[st->leftover + i] = m[i]; + } + st->leftover += bytes; + } } -} // namespace ZeroTier +} // anonymous namespace + +void Poly1305::compute(void* auth, const void* data, unsigned int len, const void* key) +{ + poly1305_context ctx; + poly1305_init(&ctx, reinterpret_cast(key)); + poly1305_update(&ctx, reinterpret_cast(data), (size_t)len); + poly1305_finish(&ctx, reinterpret_cast(auth)); +} + +} // namespace ZeroTier diff --git a/node/Poly1305.hpp b/node/Poly1305.hpp index 2ba57f04..4e83b5a9 100644 --- a/node/Poly1305.hpp +++ b/node/Poly1305.hpp @@ -30,20 +30,19 @@ namespace ZeroTier { * keystream as a one-time-use key. These 32 bytes are then discarded and * the packet is encrypted with the next N bytes. */ -class Poly1305 -{ -public: - /** - * Compute a one-time authentication code - * - * @param auth Buffer to receive code -- MUST be 16 bytes in length - * @param data Data to authenticate - * @param len Length of data to authenticate in bytes - * @param key 32-byte one-time use key to authenticate data (must not be reused) - */ - static void compute(void *auth,const void *data,unsigned int len,const void *key); +class Poly1305 { + public: + /** + * Compute a one-time authentication code + * + * @param auth Buffer to receive code -- MUST be 16 bytes in length + * @param data Data to authenticate + * @param len Length of data to authenticate in bytes + * @param key 32-byte one-time use key to authenticate data (must not be reused) + */ + static void compute(void* auth, const void* data, unsigned int len, const void* key); }; -} // namespace ZeroTier +} // namespace ZeroTier #endif diff --git a/node/Revocation.cpp b/node/Revocation.cpp index 44e22e36..0a1355ad 100644 --- a/node/Revocation.cpp +++ b/node/Revocation.cpp @@ -12,32 +12,34 @@ /****/ #include "Revocation.hpp" -#include "RuntimeEnvironment.hpp" + #include "Identity.hpp" -#include "Topology.hpp" -#include "Switch.hpp" #include "Network.hpp" #include "Node.hpp" +#include "RuntimeEnvironment.hpp" +#include "Switch.hpp" +#include "Topology.hpp" namespace ZeroTier { -int Revocation::verify(const RuntimeEnvironment *RR,void *tPtr) const +int Revocation::verify(const RuntimeEnvironment* RR, void* tPtr) const { - if ((!_signedBy)||(_signedBy != Network::controllerFor(_networkId))) { - return -1; - } - const Identity id(RR->topology->getIdentity(tPtr,_signedBy)); - if (!id) { - RR->sw->requestWhois(tPtr,RR->node->now(),_signedBy); - return 1; - } - try { - Buffer tmp; - this->serialize(tmp,true); - return (id.verify(tmp.data(),tmp.size(),_signature) ? 0 : -1); - } catch ( ... ) { - return -1; - } + if ((! _signedBy) || (_signedBy != Network::controllerFor(_networkId))) { + return -1; + } + const Identity id(RR->topology->getIdentity(tPtr, _signedBy)); + if (! id) { + RR->sw->requestWhois(tPtr, RR->node->now(), _signedBy); + return 1; + } + try { + Buffer tmp; + this->serialize(tmp, true); + return (id.verify(tmp.data(), tmp.size(), _signature) ? 0 : -1); + } + catch (...) { + return -1; + } } -} // namespace ZeroTier +} // namespace ZeroTier diff --git a/node/Revocation.hpp b/node/Revocation.hpp index 7c4523cd..e1b8d3af 100644 --- a/node/Revocation.hpp +++ b/node/Revocation.hpp @@ -14,19 +14,19 @@ #ifndef ZT_REVOCATION_HPP #define ZT_REVOCATION_HPP +#include "../include/ZeroTierOne.h" +#include "Address.hpp" +#include "Buffer.hpp" +#include "Constants.hpp" +#include "Credential.hpp" +#include "ECC.hpp" +#include "Identity.hpp" +#include "Utils.hpp" + +#include #include #include #include -#include - -#include "Constants.hpp" -#include "../include/ZeroTierOne.h" -#include "Credential.hpp" -#include "Address.hpp" -#include "C25519.hpp" -#include "Utils.hpp" -#include "Buffer.hpp" -#include "Identity.hpp" /** * Flag: fast propagation via rumor mill algorithm @@ -40,170 +40,188 @@ class RuntimeEnvironment; /** * Revocation certificate to instantaneously revoke a COM, capability, or tag */ -class Revocation : public Credential -{ -public: - static inline Credential::Type credentialType() { return Credential::CREDENTIAL_TYPE_REVOCATION; } +class Revocation : public Credential { + public: + static inline Credential::Type credentialType() + { + return Credential::CREDENTIAL_TYPE_REVOCATION; + } - Revocation() : - _id(0), - _credentialId(0), - _networkId(0), - _threshold(0), - _flags(0), - _target(), - _signedBy(), - _type(Credential::CREDENTIAL_TYPE_NULL) - { - memset(_signature.data,0,sizeof(_signature.data)); - } + Revocation() : _id(0), _credentialId(0), _networkId(0), _threshold(0), _flags(0), _target(), _signedBy(), _type(Credential::CREDENTIAL_TYPE_NULL) + { + memset(_signature.data, 0, sizeof(_signature.data)); + } - /** - * @param i ID (arbitrary for revocations, currently random) - * @param nwid Network ID - * @param cid Credential ID being revoked (0 for all or for COMs, which lack IDs) - * @param thr Revocation time threshold before which credentials will be revoked - * @param fl Flags - * @param tgt Target node whose credential(s) are being revoked - * @param ct Credential type being revoked - */ - Revocation(const uint32_t i,const uint64_t nwid,const uint32_t cid,const int64_t thr,const uint64_t fl,const Address &tgt,const Credential::Type ct) : - _id(i), - _credentialId(cid), - _networkId(nwid), - _threshold(thr), - _flags(fl), - _target(tgt), - _signedBy(), - _type(ct) - { - memset(_signature.data,0,sizeof(_signature.data)); - } + /** + * @param i ID (arbitrary for revocations, currently random) + * @param nwid Network ID + * @param cid Credential ID being revoked (0 for all or for COMs, which lack IDs) + * @param thr Revocation time threshold before which credentials will be revoked + * @param fl Flags + * @param tgt Target node whose credential(s) are being revoked + * @param ct Credential type being revoked + */ + Revocation(const uint32_t i, const uint64_t nwid, const uint32_t cid, const int64_t thr, const uint64_t fl, const Address& tgt, const Credential::Type ct) + : _id(i) + , _credentialId(cid) + , _networkId(nwid) + , _threshold(thr) + , _flags(fl) + , _target(tgt) + , _signedBy() + , _type(ct) + { + memset(_signature.data, 0, sizeof(_signature.data)); + } - inline uint32_t id() const { return _id; } - inline uint32_t credentialId() const { return _credentialId; } - inline uint64_t networkId() const { return _networkId; } - inline int64_t threshold() const { return _threshold; } - inline const Address &target() const { return _target; } - inline const Address &signer() const { return _signedBy; } - inline Credential::Type type() const { return _type; } + inline uint32_t id() const + { + return _id; + } + inline uint32_t credentialId() const + { + return _credentialId; + } + inline uint64_t networkId() const + { + return _networkId; + } + inline int64_t threshold() const + { + return _threshold; + } + inline const Address& target() const + { + return _target; + } + inline const Address& signer() const + { + return _signedBy; + } + inline Credential::Type type() const + { + return _type; + } - inline bool fastPropagate() const { return ((_flags & ZT_REVOCATION_FLAG_FAST_PROPAGATE) != 0); } + inline bool fastPropagate() const + { + return ((_flags & ZT_REVOCATION_FLAG_FAST_PROPAGATE) != 0); + } - /** - * @param signer Signing identity, must have private key - * @return True if signature was successful - */ - inline bool sign(const Identity &signer) - { - if (signer.hasPrivate()) { - Buffer tmp; - _signedBy = signer.address(); - this->serialize(tmp,true); - _signature = signer.sign(tmp.data(),tmp.size()); - return true; - } - return false; - } + /** + * @param signer Signing identity, must have private key + * @return True if signature was successful + */ + inline bool sign(const Identity& signer) + { + if (signer.hasPrivate()) { + Buffer tmp; + _signedBy = signer.address(); + this->serialize(tmp, true); + _signature = signer.sign(tmp.data(), tmp.size()); + return true; + } + return false; + } - /** - * Verify this revocation's signature - * - * @param RR Runtime environment to provide for peer lookup, etc. - * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call - * @return 0 == OK, 1 == waiting for WHOIS, -1 == BAD signature or chain - */ - int verify(const RuntimeEnvironment *RR,void *tPtr) const; + /** + * Verify this revocation's signature + * + * @param RR Runtime environment to provide for peer lookup, etc. + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call + * @return 0 == OK, 1 == waiting for WHOIS, -1 == BAD signature or chain + */ + int verify(const RuntimeEnvironment* RR, void* tPtr) const; - template - inline void serialize(Buffer &b,const bool forSign = false) const - { - if (forSign) { - b.append((uint64_t)0x7f7f7f7f7f7f7f7fULL); - } + template inline void serialize(Buffer& b, const bool forSign = false) const + { + if (forSign) { + b.append((uint64_t)0x7f7f7f7f7f7f7f7fULL); + } - b.append((uint32_t)0); // 4 unused bytes, currently set to 0 - b.append(_id); - b.append(_networkId); - b.append((uint32_t)0); // 4 unused bytes, currently set to 0 - b.append(_credentialId); - b.append(_threshold); - b.append(_flags); - _target.appendTo(b); - _signedBy.appendTo(b); - b.append((uint8_t)_type); + b.append((uint32_t)0); // 4 unused bytes, currently set to 0 + b.append(_id); + b.append(_networkId); + b.append((uint32_t)0); // 4 unused bytes, currently set to 0 + b.append(_credentialId); + b.append(_threshold); + b.append(_flags); + _target.appendTo(b); + _signedBy.appendTo(b); + b.append((uint8_t)_type); - if (!forSign) { - b.append((uint8_t)1); // 1 == Ed25519 signature - b.append((uint16_t)ZT_C25519_SIGNATURE_LEN); - b.append(_signature.data,ZT_C25519_SIGNATURE_LEN); - } + if (! forSign) { + b.append((uint8_t)1); // 1 == Ed25519 signature + b.append((uint16_t)ZT_ECC_SIGNATURE_LEN); + b.append(_signature.data, ZT_ECC_SIGNATURE_LEN); + } - // This is the size of any additional fields, currently 0. - b.append((uint16_t)0); + // This is the size of any additional fields, currently 0. + b.append((uint16_t)0); - if (forSign) { - b.append((uint64_t)0x7f7f7f7f7f7f7f7fULL); - } - } + if (forSign) { + b.append((uint64_t)0x7f7f7f7f7f7f7f7fULL); + } + } - template - inline unsigned int deserialize(const Buffer &b,unsigned int startAt = 0) - { - *this = Revocation(); + template inline unsigned int deserialize(const Buffer& b, unsigned int startAt = 0) + { + *this = Revocation(); - unsigned int p = startAt; + unsigned int p = startAt; - p += 4; // 4 bytes, currently unused - _id = b.template at(p); - p += 4; - _networkId = b.template at(p); - p += 8; - p += 4; // 4 bytes, currently unused - _credentialId = b.template at(p); - p += 4; - _threshold = (int64_t)b.template at(p); - p += 8; - _flags = b.template at(p); - p += 8; - _target.setTo(b.field(p,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); - p += ZT_ADDRESS_LENGTH; - _signedBy.setTo(b.field(p,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); - p += ZT_ADDRESS_LENGTH; - _type = (Credential::Type)b[p++]; + p += 4; // 4 bytes, currently unused + _id = b.template at(p); + p += 4; + _networkId = b.template at(p); + p += 8; + p += 4; // 4 bytes, currently unused + _credentialId = b.template at(p); + p += 4; + _threshold = (int64_t)b.template at(p); + p += 8; + _flags = b.template at(p); + p += 8; + _target.setTo(b.field(p, ZT_ADDRESS_LENGTH), ZT_ADDRESS_LENGTH); + p += ZT_ADDRESS_LENGTH; + _signedBy.setTo(b.field(p, ZT_ADDRESS_LENGTH), ZT_ADDRESS_LENGTH); + p += ZT_ADDRESS_LENGTH; + _type = (Credential::Type)b[p++]; - if (b[p++] == 1) { - if (b.template at(p) == ZT_C25519_SIGNATURE_LEN) { - p += 2; - memcpy(_signature.data,b.field(p,ZT_C25519_SIGNATURE_LEN),ZT_C25519_SIGNATURE_LEN); - p += ZT_C25519_SIGNATURE_LEN; - } else { - throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_INVALID_CRYPTOGRAPHIC_TOKEN; - } - } else { - p += 2 + b.template at(p); - } + if (b[p++] == 1) { + if (b.template at(p) == ZT_ECC_SIGNATURE_LEN) { + p += 2; + memcpy(_signature.data, b.field(p, ZT_ECC_SIGNATURE_LEN), ZT_ECC_SIGNATURE_LEN); + p += ZT_ECC_SIGNATURE_LEN; + } + else { + throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_INVALID_CRYPTOGRAPHIC_TOKEN; + } + } + else { + p += 2 + b.template at(p); + } - p += 2 + b.template at(p); - if (p > b.size()) { - throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_OVERFLOW; - } + p += 2 + b.template at(p); + if (p > b.size()) { + throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_OVERFLOW; + } - return (p - startAt); - } + return (p - startAt); + } -private: - uint32_t _id; - uint32_t _credentialId; - uint64_t _networkId; - int64_t _threshold; - uint64_t _flags; - Address _target; - Address _signedBy; - Credential::Type _type; - C25519::Signature _signature; + private: + uint32_t _id; + uint32_t _credentialId; + uint64_t _networkId; + int64_t _threshold; + uint64_t _flags; + Address _target; + Address _signedBy; + Credential::Type _type; + ECC::Signature _signature; }; -} // namespace ZeroTier +} // namespace ZeroTier #endif diff --git a/node/RingBuffer.hpp b/node/RingBuffer.hpp index ac4cb2c0..4d723631 100644 --- a/node/RingBuffer.hpp +++ b/node/RingBuffer.hpp @@ -14,12 +14,12 @@ #ifndef ZT_RINGBUFFER_H #define ZT_RINGBUFFER_H -#include -#include -#include -#include #include +#include #include +#include +#include +#include namespace ZeroTier { @@ -34,301 +34,310 @@ namespace ZeroTier { * to reduce the complexity of code needed to interact with this type of buffer. */ -template -class RingBuffer -{ -private: - T buf[S]; - size_t begin; - size_t end; - bool wrap; +template class RingBuffer { + private: + T buf[S]; + size_t begin; + size_t end; + bool wrap; -public: - RingBuffer() : - begin(0), - end(0), - wrap(false) - { - memset(buf,0,sizeof(T)*S); - } + public: + RingBuffer() : begin(0), end(0), wrap(false) + { + memset(buf, 0, sizeof(T) * S); + } - /** - * @return A pointer to the underlying buffer - */ - inline T *get_buf() - { - return buf + begin; - } + /** + * @return A pointer to the underlying buffer + */ + inline T* get_buf() + { + return buf + begin; + } - /** - * Adjust buffer index pointer as if we copied data in - * @param n Number of elements to copy in - * @return Number of elements we copied in - */ - inline size_t produce(size_t n) - { - n = std::min(n, getFree()); - if (n == 0) { - return n; - } - const size_t first_chunk = std::min(n, S - end); - end = (end + first_chunk) % S; - if (first_chunk < n) { - const size_t second_chunk = n - first_chunk; - end = (end + second_chunk) % S; - } - if (begin == end) { - wrap = true; - } - return n; - } + /** + * Adjust buffer index pointer as if we copied data in + * @param n Number of elements to copy in + * @return Number of elements we copied in + */ + inline size_t produce(size_t n) + { + n = std::min(n, getFree()); + if (n == 0) { + return n; + } + const size_t first_chunk = std::min(n, S - end); + end = (end + first_chunk) % S; + if (first_chunk < n) { + const size_t second_chunk = n - first_chunk; + end = (end + second_chunk) % S; + } + if (begin == end) { + wrap = true; + } + return n; + } - /** - * Fast erase, O(1). - * Merely reset the buffer pointer, doesn't erase contents - */ - inline void reset() { consume(count()); } + /** + * Fast erase, O(1). + * Merely reset the buffer pointer, doesn't erase contents + */ + inline void reset() + { + consume(count()); + } - /** - * adjust buffer index pointer as if we copied data out - * @param n Number of elements we copied from the buffer - * @return Number of elements actually available from the buffer - */ - inline size_t consume(size_t n) - { - n = std::min(n, count()); - if (n == 0) { - return n; - } - if (wrap) { - wrap = false; - } - const size_t first_chunk = std::min(n, S - begin); - begin = (begin + first_chunk) % S; - if (first_chunk < n) { - const size_t second_chunk = n - first_chunk; - begin = (begin + second_chunk) % S; - } - return n; - } + /** + * adjust buffer index pointer as if we copied data out + * @param n Number of elements we copied from the buffer + * @return Number of elements actually available from the buffer + */ + inline size_t consume(size_t n) + { + n = std::min(n, count()); + if (n == 0) { + return n; + } + if (wrap) { + wrap = false; + } + const size_t first_chunk = std::min(n, S - begin); + begin = (begin + first_chunk) % S; + if (first_chunk < n) { + const size_t second_chunk = n - first_chunk; + begin = (begin + second_chunk) % S; + } + return n; + } - /** - * @param data Buffer that is to be written to the ring - * @param n Number of elements to write to the buffer - */ - inline size_t write(const T * data, size_t n) - { - n = std::min(n, getFree()); - if (n == 0) { - return n; - } - const size_t first_chunk = std::min(n, S - end); - memcpy(buf + end, data, first_chunk * sizeof(T)); - end = (end + first_chunk) % S; - if (first_chunk < n) { - const size_t second_chunk = n - first_chunk; - memcpy(buf + end, data + first_chunk, second_chunk * sizeof(T)); - end = (end + second_chunk) % S; - } - if (begin == end) { - wrap = true; - } - return n; - } + /** + * @param data Buffer that is to be written to the ring + * @param n Number of elements to write to the buffer + */ + inline size_t write(const T* data, size_t n) + { + n = std::min(n, getFree()); + if (n == 0) { + return n; + } + const size_t first_chunk = std::min(n, S - end); + memcpy(buf + end, data, first_chunk * sizeof(T)); + end = (end + first_chunk) % S; + if (first_chunk < n) { + const size_t second_chunk = n - first_chunk; + memcpy(buf + end, data + first_chunk, second_chunk * sizeof(T)); + end = (end + second_chunk) % S; + } + if (begin == end) { + wrap = true; + } + return n; + } - /** - * Place a single value on the buffer. If the buffer is full, consume a value first. - * - * @param value A single value to be placed in the buffer - */ - inline void push(const T value) - { - if (count() == S) { - consume(1); - } - const size_t first_chunk = std::min((size_t)1, S - end); - *(buf + end) = value; - end = (end + first_chunk) % S; - if (begin == end) { - wrap = true; - } - } + /** + * Place a single value on the buffer. If the buffer is full, consume a value first. + * + * @param value A single value to be placed in the buffer + */ + inline void push(const T value) + { + if (count() == S) { + consume(1); + } + const size_t first_chunk = std::min((size_t)1, S - end); + *(buf + end) = value; + end = (end + first_chunk) % S; + if (begin == end) { + wrap = true; + } + } - /** - * @return The most recently pushed element on the buffer - */ - inline T get_most_recent() { return *(buf + end); } + /** + * @return The most recently pushed element on the buffer + */ + inline T get_most_recent() + { + return *(buf + end); + } - /** - * @param dest Destination buffer - * @param n Size (in terms of number of elements) of the destination buffer - * @return Number of elements read from the buffer - */ - inline size_t read(T *dest,size_t n) - { - n = std::min(n, count()); - if (n == 0) { - return n; - } - if (wrap) { - wrap = false; - } - const size_t first_chunk = std::min(n, S - begin); - memcpy(dest, buf + begin, first_chunk * sizeof(T)); - begin = (begin + first_chunk) % S; - if (first_chunk < n) { - const size_t second_chunk = n - first_chunk; - memcpy(dest + first_chunk, buf + begin, second_chunk * sizeof(T)); - begin = (begin + second_chunk) % S; - } - return n; - } + /** + * @param dest Destination buffer + * @param n Size (in terms of number of elements) of the destination buffer + * @return Number of elements read from the buffer + */ + inline size_t read(T* dest, size_t n) + { + n = std::min(n, count()); + if (n == 0) { + return n; + } + if (wrap) { + wrap = false; + } + const size_t first_chunk = std::min(n, S - begin); + memcpy(dest, buf + begin, first_chunk * sizeof(T)); + begin = (begin + first_chunk) % S; + if (first_chunk < n) { + const size_t second_chunk = n - first_chunk; + memcpy(dest + first_chunk, buf + begin, second_chunk * sizeof(T)); + begin = (begin + second_chunk) % S; + } + return n; + } - /** - * Return how many elements are in the buffer, O(1). - * - * @return The number of elements in the buffer - */ - inline size_t count() - { - if (end == begin) { - return wrap ? S : 0; - } else if (end > begin) { - return end - begin; - } else { - return S + end - begin; - } - } + /** + * Return how many elements are in the buffer, O(1). + * + * @return The number of elements in the buffer + */ + inline size_t count() + { + if (end == begin) { + return wrap ? S : 0; + } + else if (end > begin) { + return end - begin; + } + else { + return S + end - begin; + } + } - /** - * @return The number of slots that are unused in the buffer - */ - inline size_t getFree() { return S - count(); } + /** + * @return The number of slots that are unused in the buffer + */ + inline size_t getFree() + { + return S - count(); + } - /** - * @return The arithmetic mean of the contents of the buffer - */ - inline float mean() - { - size_t iterator = begin; - float subtotal = 0; - size_t curr_cnt = count(); - for (size_t i=0; i - #include "Constants.hpp" -#include "Utils.hpp" #include "Identity.hpp" +#include "Utils.hpp" + +#include namespace ZeroTier { @@ -36,56 +36,48 @@ class PacketMultiplexer; /** * Holds global state for an instance of ZeroTier::Node */ -class RuntimeEnvironment -{ -public: - RuntimeEnvironment(Node *n) : - node(n) - ,localNetworkController((NetworkController *)0) - ,rtmem((void *)0) - ,sw((Switch *)0) - ,mc((Multicaster *)0) - ,topology((Topology *)0) - ,sa((SelfAwareness *)0) - { - publicIdentityStr[0] = (char)0; - secretIdentityStr[0] = (char)0; - } +class RuntimeEnvironment { + public: + RuntimeEnvironment(Node* n) : node(n), localNetworkController((NetworkController*)0), rtmem((void*)0), sw((Switch*)0), mc((Multicaster*)0), topology((Topology*)0), sa((SelfAwareness*)0) + { + publicIdentityStr[0] = (char)0; + secretIdentityStr[0] = (char)0; + } - ~RuntimeEnvironment() - { - Utils::burn(secretIdentityStr,sizeof(secretIdentityStr)); - } + ~RuntimeEnvironment() + { + Utils::burn(secretIdentityStr, sizeof(secretIdentityStr)); + } - // Node instance that owns this RuntimeEnvironment - Node *const node; + // Node instance that owns this RuntimeEnvironment + Node* const node; - // This is set externally to an instance of this base class - NetworkController *localNetworkController; + // This is set externally to an instance of this base class + NetworkController* localNetworkController; - // Memory actually occupied by Trace, Switch, etc. - void *rtmem; + // Memory actually occupied by Trace, Switch, etc. + void* rtmem; - /* Order matters a bit here. These are constructed in this order - * and then deleted in the opposite order on Node exit. The order ensures - * that things that are needed are there before they're needed. - * - * These are constant and never null after startup unless indicated. */ + /* Order matters a bit here. These are constructed in this order + * and then deleted in the opposite order on Node exit. The order ensures + * that things that are needed are there before they're needed. + * + * These are constant and never null after startup unless indicated. */ - Trace *t; - Switch *sw; - Multicaster *mc; - Topology *topology; - SelfAwareness *sa; - Bond *bc; - PacketMultiplexer *pm; + Trace* t; + Switch* sw; + Multicaster* mc; + Topology* topology; + SelfAwareness* sa; + Bond* bc; + PacketMultiplexer* pm; - // This node's identity and string representations thereof - Identity identity; - char publicIdentityStr[ZT_IDENTITY_STRING_BUFFER_LENGTH]; - char secretIdentityStr[ZT_IDENTITY_STRING_BUFFER_LENGTH]; + // This node's identity and string representations thereof + Identity identity; + char publicIdentityStr[ZT_IDENTITY_STRING_BUFFER_LENGTH]; + char secretIdentityStr[ZT_IDENTITY_STRING_BUFFER_LENGTH]; }; -} // namespace ZeroTier +} // namespace ZeroTier #endif diff --git a/node/SHA512.cpp b/node/SHA512.cpp index bd81647d..cba2cf31 100644 --- a/node/SHA512.cpp +++ b/node/SHA512.cpp @@ -1,10 +1,11 @@ // This code is public domain, taken from a PD crypto source file on GitHub. -#include - #include "SHA512.hpp" + #include "Utils.hpp" +#include + namespace ZeroTier { #ifndef ZT_HAVE_NATIVE_SHA512 @@ -12,274 +13,264 @@ namespace ZeroTier { namespace { struct sha512_state { - uint64_t length,state[8]; - unsigned long curlen; - uint8_t buf[128]; + uint64_t length, state[8]; + unsigned long curlen; + uint8_t buf[128]; }; -static const uint64_t K[80] = { - 0x428a2f98d728ae22ULL,0x7137449123ef65cdULL,0xb5c0fbcfec4d3b2fULL,0xe9b5dba58189dbbcULL, - 0x3956c25bf348b538ULL,0x59f111f1b605d019ULL,0x923f82a4af194f9bULL,0xab1c5ed5da6d8118ULL, - 0xd807aa98a3030242ULL,0x12835b0145706fbeULL,0x243185be4ee4b28cULL,0x550c7dc3d5ffb4e2ULL, - 0x72be5d74f27b896fULL,0x80deb1fe3b1696b1ULL,0x9bdc06a725c71235ULL,0xc19bf174cf692694ULL, - 0xe49b69c19ef14ad2ULL,0xefbe4786384f25e3ULL,0x0fc19dc68b8cd5b5ULL,0x240ca1cc77ac9c65ULL, - 0x2de92c6f592b0275ULL,0x4a7484aa6ea6e483ULL,0x5cb0a9dcbd41fbd4ULL,0x76f988da831153b5ULL, - 0x983e5152ee66dfabULL,0xa831c66d2db43210ULL,0xb00327c898fb213fULL,0xbf597fc7beef0ee4ULL, - 0xc6e00bf33da88fc2ULL,0xd5a79147930aa725ULL,0x06ca6351e003826fULL,0x142929670a0e6e70ULL, - 0x27b70a8546d22ffcULL,0x2e1b21385c26c926ULL,0x4d2c6dfc5ac42aedULL,0x53380d139d95b3dfULL, - 0x650a73548baf63deULL,0x766a0abb3c77b2a8ULL,0x81c2c92e47edaee6ULL,0x92722c851482353bULL, - 0xa2bfe8a14cf10364ULL,0xa81a664bbc423001ULL,0xc24b8b70d0f89791ULL,0xc76c51a30654be30ULL, - 0xd192e819d6ef5218ULL,0xd69906245565a910ULL,0xf40e35855771202aULL,0x106aa07032bbd1b8ULL, - 0x19a4c116b8d2d0c8ULL,0x1e376c085141ab53ULL,0x2748774cdf8eeb99ULL,0x34b0bcb5e19b48a8ULL, - 0x391c0cb3c5c95a63ULL,0x4ed8aa4ae3418acbULL,0x5b9cca4f7763e373ULL,0x682e6ff3d6b2b8a3ULL, - 0x748f82ee5defb2fcULL,0x78a5636f43172f60ULL,0x84c87814a1f0ab72ULL,0x8cc702081a6439ecULL, - 0x90befffa23631e28ULL,0xa4506cebde82bde9ULL,0xbef9a3f7b2c67915ULL,0xc67178f2e372532bULL, - 0xca273eceea26619cULL,0xd186b8c721c0c207ULL,0xeada7dd6cde0eb1eULL,0xf57d4f7fee6ed178ULL, - 0x06f067aa72176fbaULL,0x0a637dc5a2c898a6ULL,0x113f9804bef90daeULL,0x1b710b35131c471bULL, - 0x28db77f523047d84ULL,0x32caab7b40c72493ULL,0x3c9ebe0a15c9bebcULL,0x431d67c49c100d4cULL, - 0x4cc5d4becb3e42b6ULL,0x597f299cfc657e2aULL,0x5fcb6fab3ad6faecULL,0x6c44198c4a475817ULL -}; +static const uint64_t K[80] = { 0x428a2f98d728ae22ULL, 0x7137449123ef65cdULL, 0xb5c0fbcfec4d3b2fULL, 0xe9b5dba58189dbbcULL, 0x3956c25bf348b538ULL, 0x59f111f1b605d019ULL, 0x923f82a4af194f9bULL, 0xab1c5ed5da6d8118ULL, 0xd807aa98a3030242ULL, + 0x12835b0145706fbeULL, 0x243185be4ee4b28cULL, 0x550c7dc3d5ffb4e2ULL, 0x72be5d74f27b896fULL, 0x80deb1fe3b1696b1ULL, 0x9bdc06a725c71235ULL, 0xc19bf174cf692694ULL, 0xe49b69c19ef14ad2ULL, 0xefbe4786384f25e3ULL, + 0x0fc19dc68b8cd5b5ULL, 0x240ca1cc77ac9c65ULL, 0x2de92c6f592b0275ULL, 0x4a7484aa6ea6e483ULL, 0x5cb0a9dcbd41fbd4ULL, 0x76f988da831153b5ULL, 0x983e5152ee66dfabULL, 0xa831c66d2db43210ULL, 0xb00327c898fb213fULL, + 0xbf597fc7beef0ee4ULL, 0xc6e00bf33da88fc2ULL, 0xd5a79147930aa725ULL, 0x06ca6351e003826fULL, 0x142929670a0e6e70ULL, 0x27b70a8546d22ffcULL, 0x2e1b21385c26c926ULL, 0x4d2c6dfc5ac42aedULL, 0x53380d139d95b3dfULL, + 0x650a73548baf63deULL, 0x766a0abb3c77b2a8ULL, 0x81c2c92e47edaee6ULL, 0x92722c851482353bULL, 0xa2bfe8a14cf10364ULL, 0xa81a664bbc423001ULL, 0xc24b8b70d0f89791ULL, 0xc76c51a30654be30ULL, 0xd192e819d6ef5218ULL, + 0xd69906245565a910ULL, 0xf40e35855771202aULL, 0x106aa07032bbd1b8ULL, 0x19a4c116b8d2d0c8ULL, 0x1e376c085141ab53ULL, 0x2748774cdf8eeb99ULL, 0x34b0bcb5e19b48a8ULL, 0x391c0cb3c5c95a63ULL, 0x4ed8aa4ae3418acbULL, + 0x5b9cca4f7763e373ULL, 0x682e6ff3d6b2b8a3ULL, 0x748f82ee5defb2fcULL, 0x78a5636f43172f60ULL, 0x84c87814a1f0ab72ULL, 0x8cc702081a6439ecULL, 0x90befffa23631e28ULL, 0xa4506cebde82bde9ULL, 0xbef9a3f7b2c67915ULL, + 0xc67178f2e372532bULL, 0xca273eceea26619cULL, 0xd186b8c721c0c207ULL, 0xeada7dd6cde0eb1eULL, 0xf57d4f7fee6ed178ULL, 0x06f067aa72176fbaULL, 0x0a637dc5a2c898a6ULL, 0x113f9804bef90daeULL, 0x1b710b35131c471bULL, + 0x28db77f523047d84ULL, 0x32caab7b40c72493ULL, 0x3c9ebe0a15c9bebcULL, 0x431d67c49c100d4cULL, 0x4cc5d4becb3e42b6ULL, 0x597f299cfc657e2aULL, 0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL }; -#define STORE64H(x, y) Utils::storeBigEndian(y,x) -#define LOAD64H(x, y) x = Utils::loadBigEndian(y) -#define ROL64c(x,y) (((x)<<(y)) | ((x)>>(64-(y)))) -#define ROR64c(x,y) (((x)>>(y)) | ((x)<<(64-(y)))) -#define Ch(x,y,z) (z ^ (x & (y ^ z))) -#define Maj(x,y,z) (((x | y) & z) | (x & y)) -#define S(x, n) ROR64c(x, n) -#define R(x, n) ((x)>>(n)) -#define Sigma0(x) (S(x, 28) ^ S(x, 34) ^ S(x, 39)) -#define Sigma1(x) (S(x, 14) ^ S(x, 18) ^ S(x, 41)) -#define Gamma0(x) (S(x, 1) ^ S(x, 8) ^ R(x, 7)) -#define Gamma1(x) (S(x, 19) ^ S(x, 61) ^ R(x, 6)) +#define STORE64H(x, y) Utils::storeBigEndian(y, x) +#define LOAD64H(x, y) x = Utils::loadBigEndian(y) +#define ROL64c(x, y) (((x) << (y)) | ((x) >> (64 - (y)))) +#define ROR64c(x, y) (((x) >> (y)) | ((x) << (64 - (y)))) +#define Ch(x, y, z) (z ^ (x & (y ^ z))) +#define Maj(x, y, z) (((x | y) & z) | (x & y)) +#define S(x, n) ROR64c(x, n) +#define R(x, n) ((x) >> (n)) +#define Sigma0(x) (S(x, 28) ^ S(x, 34) ^ S(x, 39)) +#define Sigma1(x) (S(x, 14) ^ S(x, 18) ^ S(x, 41)) +#define Gamma0(x) (S(x, 1) ^ S(x, 8) ^ R(x, 7)) +#define Gamma1(x) (S(x, 19) ^ S(x, 61) ^ R(x, 6)) -static ZT_INLINE void sha512_compress(sha512_state *const md,uint8_t *const buf) +static ZT_INLINE void sha512_compress(sha512_state* const md, uint8_t* const buf) { - uint64_t S[8], W[80], t0, t1; - int i; + uint64_t S[8], W[80], t0, t1; + int i; - for (i = 0; i < 8; i++) { - S[i] = md->state[i]; - } - for (i = 0; i < 16; i++) { - LOAD64H(W[i], buf + (8*i)); - } - for (i = 16; i < 80; i++) { - W[i] = Gamma1(W[i - 2]) + W[i - 7] + Gamma0(W[i - 15]) + W[i - 16]; - } + for (i = 0; i < 8; i++) { + S[i] = md->state[i]; + } + for (i = 0; i < 16; i++) { + LOAD64H(W[i], buf + (8 * i)); + } + for (i = 16; i < 80; i++) { + W[i] = Gamma1(W[i - 2]) + W[i - 7] + Gamma0(W[i - 15]) + W[i - 16]; + } -#define RND(a,b,c,d,e,f,g,h,i) \ - t0 = h + Sigma1(e) + Ch(e, f, g) + K[i] + W[i]; \ - t1 = Sigma0(a) + Maj(a, b, c); \ - d += t0; \ - h = t0 + t1; +#define RND(a, b, c, d, e, f, g, h, i) \ + t0 = h + Sigma1(e) + Ch(e, f, g) + K[i] + W[i]; \ + t1 = Sigma0(a) + Maj(a, b, c); \ + d += t0; \ + h = t0 + t1; - for (i = 0; i < 80; i += 8) { - RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],i+0); - RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],i+1); - RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],i+2); - RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],i+3); - RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],i+4); - RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],i+5); - RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],i+6); - RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],i+7); - } + for (i = 0; i < 80; i += 8) { + RND(S[0], S[1], S[2], S[3], S[4], S[5], S[6], S[7], i + 0); + RND(S[7], S[0], S[1], S[2], S[3], S[4], S[5], S[6], i + 1); + RND(S[6], S[7], S[0], S[1], S[2], S[3], S[4], S[5], i + 2); + RND(S[5], S[6], S[7], S[0], S[1], S[2], S[3], S[4], i + 3); + RND(S[4], S[5], S[6], S[7], S[0], S[1], S[2], S[3], i + 4); + RND(S[3], S[4], S[5], S[6], S[7], S[0], S[1], S[2], i + 5); + RND(S[2], S[3], S[4], S[5], S[6], S[7], S[0], S[1], i + 6); + RND(S[1], S[2], S[3], S[4], S[5], S[6], S[7], S[0], i + 7); + } - for (i = 0; i < 8; i++) { - md->state[i] = md->state[i] + S[i]; - } + for (i = 0; i < 8; i++) { + md->state[i] = md->state[i] + S[i]; + } } -static ZT_INLINE void sha384_init(sha512_state *const md) +static ZT_INLINE void sha384_init(sha512_state* const md) { - md->curlen = 0; - md->length = 0; - md->state[0] = 0xcbbb9d5dc1059ed8ULL; - md->state[1] = 0x629a292a367cd507ULL; - md->state[2] = 0x9159015a3070dd17ULL; - md->state[3] = 0x152fecd8f70e5939ULL; - md->state[4] = 0x67332667ffc00b31ULL; - md->state[5] = 0x8eb44a8768581511ULL; - md->state[6] = 0xdb0c2e0d64f98fa7ULL; - md->state[7] = 0x47b5481dbefa4fa4ULL; + md->curlen = 0; + md->length = 0; + md->state[0] = 0xcbbb9d5dc1059ed8ULL; + md->state[1] = 0x629a292a367cd507ULL; + md->state[2] = 0x9159015a3070dd17ULL; + md->state[3] = 0x152fecd8f70e5939ULL; + md->state[4] = 0x67332667ffc00b31ULL; + md->state[5] = 0x8eb44a8768581511ULL; + md->state[6] = 0xdb0c2e0d64f98fa7ULL; + md->state[7] = 0x47b5481dbefa4fa4ULL; } -static ZT_INLINE void sha512_init(sha512_state *const md) +static ZT_INLINE void sha512_init(sha512_state* const md) { - md->curlen = 0; - md->length = 0; - md->state[0] = 0x6a09e667f3bcc908ULL; - md->state[1] = 0xbb67ae8584caa73bULL; - md->state[2] = 0x3c6ef372fe94f82bULL; - md->state[3] = 0xa54ff53a5f1d36f1ULL; - md->state[4] = 0x510e527fade682d1ULL; - md->state[5] = 0x9b05688c2b3e6c1fULL; - md->state[6] = 0x1f83d9abfb41bd6bULL; - md->state[7] = 0x5be0cd19137e2179ULL; + md->curlen = 0; + md->length = 0; + md->state[0] = 0x6a09e667f3bcc908ULL; + md->state[1] = 0xbb67ae8584caa73bULL; + md->state[2] = 0x3c6ef372fe94f82bULL; + md->state[3] = 0xa54ff53a5f1d36f1ULL; + md->state[4] = 0x510e527fade682d1ULL; + md->state[5] = 0x9b05688c2b3e6c1fULL; + md->state[6] = 0x1f83d9abfb41bd6bULL; + md->state[7] = 0x5be0cd19137e2179ULL; } -static void sha512_process(sha512_state *const md,const uint8_t *in,unsigned long inlen) +static void sha512_process(sha512_state* const md, const uint8_t* in, unsigned long inlen) { - while (inlen > 0) { - if (md->curlen == 0 && inlen >= 128) { - sha512_compress(md,(uint8_t *)in); - md->length += 128 * 8; - in += 128; - inlen -= 128; - } else { - unsigned long n = std::min(inlen,(128 - md->curlen)); - Utils::copy(md->buf + md->curlen,in,n); - md->curlen += n; - in += n; - inlen -= n; - if (md->curlen == 128) { - sha512_compress(md,md->buf); - md->length += 8*128; - md->curlen = 0; - } - } - } + while (inlen > 0) { + if (md->curlen == 0 && inlen >= 128) { + sha512_compress(md, (uint8_t*)in); + md->length += 128 * 8; + in += 128; + inlen -= 128; + } + else { + unsigned long n = std::min(inlen, (128 - md->curlen)); + Utils::copy(md->buf + md->curlen, in, n); + md->curlen += n; + in += n; + inlen -= n; + if (md->curlen == 128) { + sha512_compress(md, md->buf); + md->length += 8 * 128; + md->curlen = 0; + } + } + } } -static ZT_INLINE void sha512_done(sha512_state *const md,uint8_t *out) +static ZT_INLINE void sha512_done(sha512_state* const md, uint8_t* out) { - int i; + int i; - md->length += md->curlen * 8ULL; - md->buf[md->curlen++] = (uint8_t)0x80; + md->length += md->curlen * 8ULL; + md->buf[md->curlen++] = (uint8_t)0x80; - if (md->curlen > 112) { - while (md->curlen < 128) { - md->buf[md->curlen++] = (uint8_t)0; - } - sha512_compress(md, md->buf); - md->curlen = 0; - } + if (md->curlen > 112) { + while (md->curlen < 128) { + md->buf[md->curlen++] = (uint8_t)0; + } + sha512_compress(md, md->buf); + md->curlen = 0; + } - while (md->curlen < 120) { - md->buf[md->curlen++] = (uint8_t)0; - } + while (md->curlen < 120) { + md->buf[md->curlen++] = (uint8_t)0; + } - STORE64H(md->length, md->buf+120); - sha512_compress(md, md->buf); + STORE64H(md->length, md->buf + 120); + sha512_compress(md, md->buf); - for (i = 0; i < 8; i++) { - STORE64H(md->state[i], out+(8*i)); - } + for (i = 0; i < 8; i++) { + STORE64H(md->state[i], out + (8 * i)); + } } -} // anonymous namespace +} // anonymous namespace -void SHA512(void *digest,const void *data,unsigned int len) +void SHA512(void* digest, const void* data, unsigned int len) { - sha512_state state; - sha512_init(&state); - sha512_process(&state,(uint8_t *)data,(unsigned long)len); - sha512_done(&state,(uint8_t *)digest); + sha512_state state; + sha512_init(&state); + sha512_process(&state, (uint8_t*)data, (unsigned long)len); + sha512_done(&state, (uint8_t*)digest); } -void SHA384(void *digest,const void *data,unsigned int len) +void SHA384(void* digest, const void* data, unsigned int len) { - uint8_t tmp[64]; - sha512_state state; - sha384_init(&state); - sha512_process(&state,(uint8_t *)data,(unsigned long)len); - sha512_done(&state,tmp); - Utils::copy<48>(digest,tmp); + uint8_t tmp[64]; + sha512_state state; + sha384_init(&state); + sha512_process(&state, (uint8_t*)data, (unsigned long)len); + sha512_done(&state, tmp); + Utils::copy<48>(digest, tmp); } -void SHA384(void *digest,const void *data0,unsigned int len0,const void *data1,unsigned int len1) +void SHA384(void* digest, const void* data0, unsigned int len0, const void* data1, unsigned int len1) { - uint8_t tmp[64]; - sha512_state state; - sha384_init(&state); - sha512_process(&state,(uint8_t *)data0,(unsigned long)len0); - sha512_process(&state,(uint8_t *)data1,(unsigned long)len1); - sha512_done(&state,tmp); - Utils::copy<48>(digest,tmp); + uint8_t tmp[64]; + sha512_state state; + sha384_init(&state); + sha512_process(&state, (uint8_t*)data0, (unsigned long)len0); + sha512_process(&state, (uint8_t*)data1, (unsigned long)len1); + sha512_done(&state, tmp); + Utils::copy<48>(digest, tmp); } -#endif // !ZT_HAVE_NATIVE_SHA512 +#endif // !ZT_HAVE_NATIVE_SHA512 -void HMACSHA384(const uint8_t key[ZT_SYMMETRIC_KEY_SIZE],const void *msg,const unsigned int msglen,uint8_t mac[48]) +void HMACSHA384(const uint8_t key[ZT_SYMMETRIC_KEY_SIZE], const void* msg, const unsigned int msglen, uint8_t mac[48]) { - uint64_t kInPadded[16]; // input padded key - uint64_t outer[22]; // output padded key | H(input padded key | msg) + uint64_t kInPadded[16]; // input padded key + uint64_t outer[22]; // output padded key | H(input padded key | msg) - const uint64_t k0 = Utils::loadMachineEndian< uint64_t >(key); - const uint64_t k1 = Utils::loadMachineEndian< uint64_t >(key + 8); - const uint64_t k2 = Utils::loadMachineEndian< uint64_t >(key + 16); - const uint64_t k3 = Utils::loadMachineEndian< uint64_t >(key + 24); - const uint64_t k4 = Utils::loadMachineEndian< uint64_t >(key + 32); - const uint64_t k5 = Utils::loadMachineEndian< uint64_t >(key + 40); + const uint64_t k0 = Utils::loadMachineEndian(key); + const uint64_t k1 = Utils::loadMachineEndian(key + 8); + const uint64_t k2 = Utils::loadMachineEndian(key + 16); + const uint64_t k3 = Utils::loadMachineEndian(key + 24); + const uint64_t k4 = Utils::loadMachineEndian(key + 32); + const uint64_t k5 = Utils::loadMachineEndian(key + 40); - const uint64_t ipad = 0x3636363636363636ULL; - kInPadded[0] = k0 ^ ipad; - kInPadded[1] = k1 ^ ipad; - kInPadded[2] = k2 ^ ipad; - kInPadded[3] = k3 ^ ipad; - kInPadded[4] = k4 ^ ipad; - kInPadded[5] = k5 ^ ipad; - kInPadded[6] = ipad; - kInPadded[7] = ipad; - kInPadded[8] = ipad; - kInPadded[9] = ipad; - kInPadded[10] = ipad; - kInPadded[11] = ipad; - kInPadded[12] = ipad; - kInPadded[13] = ipad; - kInPadded[14] = ipad; - kInPadded[15] = ipad; + const uint64_t ipad = 0x3636363636363636ULL; + kInPadded[0] = k0 ^ ipad; + kInPadded[1] = k1 ^ ipad; + kInPadded[2] = k2 ^ ipad; + kInPadded[3] = k3 ^ ipad; + kInPadded[4] = k4 ^ ipad; + kInPadded[5] = k5 ^ ipad; + kInPadded[6] = ipad; + kInPadded[7] = ipad; + kInPadded[8] = ipad; + kInPadded[9] = ipad; + kInPadded[10] = ipad; + kInPadded[11] = ipad; + kInPadded[12] = ipad; + kInPadded[13] = ipad; + kInPadded[14] = ipad; + kInPadded[15] = ipad; - const uint64_t opad = 0x5c5c5c5c5c5c5c5cULL; - outer[0] = k0 ^ opad; - outer[1] = k1 ^ opad; - outer[2] = k2 ^ opad; - outer[3] = k3 ^ opad; - outer[4] = k4 ^ opad; - outer[5] = k5 ^ opad; - outer[6] = opad; - outer[7] = opad; - outer[8] = opad; - outer[9] = opad; - outer[10] = opad; - outer[11] = opad; - outer[12] = opad; - outer[13] = opad; - outer[14] = opad; - outer[15] = opad; + const uint64_t opad = 0x5c5c5c5c5c5c5c5cULL; + outer[0] = k0 ^ opad; + outer[1] = k1 ^ opad; + outer[2] = k2 ^ opad; + outer[3] = k3 ^ opad; + outer[4] = k4 ^ opad; + outer[5] = k5 ^ opad; + outer[6] = opad; + outer[7] = opad; + outer[8] = opad; + outer[9] = opad; + outer[10] = opad; + outer[11] = opad; + outer[12] = opad; + outer[13] = opad; + outer[14] = opad; + outer[15] = opad; - // H(output padded key | H(input padded key | msg)) - SHA384(reinterpret_cast(outer) + 128,kInPadded,128,msg,msglen); - SHA384(mac,outer,176); + // H(output padded key | H(input padded key | msg)) + SHA384(reinterpret_cast(outer) + 128, kInPadded, 128, msg, msglen); + SHA384(mac, outer, 176); } -void KBKDFHMACSHA384(const uint8_t key[ZT_SYMMETRIC_KEY_SIZE],const char label,const char context,const uint32_t iter,uint8_t out[ZT_SYMMETRIC_KEY_SIZE]) +void KBKDFHMACSHA384(const uint8_t key[ZT_SYMMETRIC_KEY_SIZE], const char label, const char context, const uint32_t iter, uint8_t out[ZT_SYMMETRIC_KEY_SIZE]) { - uint8_t kbkdfMsg[13]; + uint8_t kbkdfMsg[13]; - Utils::storeBigEndian(kbkdfMsg,(uint32_t)iter); + Utils::storeBigEndian(kbkdfMsg, (uint32_t)iter); - kbkdfMsg[4] = (uint8_t)'Z'; - kbkdfMsg[5] = (uint8_t)'T'; // preface our labels with something ZT-specific - kbkdfMsg[6] = (uint8_t)label; - kbkdfMsg[7] = 0; + kbkdfMsg[4] = (uint8_t)'Z'; + kbkdfMsg[5] = (uint8_t)'T'; // preface our labels with something ZT-specific + kbkdfMsg[6] = (uint8_t)label; + kbkdfMsg[7] = 0; - kbkdfMsg[8] = (uint8_t)context; + kbkdfMsg[8] = (uint8_t)context; - // Output key length: 384 bits (as 32-bit big-endian value) - kbkdfMsg[9] = 0; - kbkdfMsg[10] = 0; - kbkdfMsg[11] = 0x01; - kbkdfMsg[12] = 0x80; + // Output key length: 384 bits (as 32-bit big-endian value) + kbkdfMsg[9] = 0; + kbkdfMsg[10] = 0; + kbkdfMsg[11] = 0x01; + kbkdfMsg[12] = 0x80; - static_assert(ZT_SYMMETRIC_KEY_SIZE == ZT_SHA384_DIGEST_SIZE,"sizeof(out) != ZT_SHA384_DIGEST_SIZE"); - HMACSHA384(key,&kbkdfMsg,sizeof(kbkdfMsg),out); + static_assert(ZT_SYMMETRIC_KEY_SIZE == ZT_SHA384_DIGEST_SIZE, "sizeof(out) != ZT_SHA384_DIGEST_SIZE"); + HMACSHA384(key, &kbkdfMsg, sizeof(kbkdfMsg), out); } -} // namespace ZeroTier +} // namespace ZeroTier // Internally re-export to included C code, which includes some fast crypto code ported in on some platforms. // This eliminates the need to link against a third party SHA512() from this code -extern "C" void ZT_sha512internal(void *digest,const void *data,unsigned int len) -{ ZeroTier::SHA512(digest,data,len); } +extern "C" void ZT_sha512internal(void* digest, const void* data, unsigned int len) +{ + ZeroTier::SHA512(digest, data, len); +} diff --git a/node/SHA512.hpp b/node/SHA512.hpp index 93236a85..d5178429 100644 --- a/node/SHA512.hpp +++ b/node/SHA512.hpp @@ -22,8 +22,8 @@ #define ZT_SHA512_DIGEST_SIZE 64 #define ZT_SHA384_DIGEST_SIZE 48 -#define ZT_SHA512_BLOCK_SIZE 128 -#define ZT_SHA384_BLOCK_SIZE 128 +#define ZT_SHA512_BLOCK_SIZE 128 +#define ZT_SHA384_BLOCK_SIZE 128 #define ZT_HMACSHA384_LEN 48 @@ -32,34 +32,34 @@ namespace ZeroTier { // SHA384 and SHA512 are actually in the standard libraries on MacOS and iOS #ifdef __APPLE__ #define ZT_HAVE_NATIVE_SHA512 1 -static ZT_INLINE void SHA512(void *digest,const void *data,unsigned int len) +static ZT_INLINE void SHA512(void* digest, const void* data, unsigned int len) { - CC_SHA512_CTX ctx; - CC_SHA512_Init(&ctx); - CC_SHA512_Update(&ctx,data,len); - CC_SHA512_Final(reinterpret_cast(digest),&ctx); + CC_SHA512_CTX ctx; + CC_SHA512_Init(&ctx); + CC_SHA512_Update(&ctx, data, len); + CC_SHA512_Final(reinterpret_cast(digest), &ctx); } -static ZT_INLINE void SHA384(void *digest,const void *data,unsigned int len) +static ZT_INLINE void SHA384(void* digest, const void* data, unsigned int len) { - CC_SHA512_CTX ctx; - CC_SHA384_Init(&ctx); - CC_SHA384_Update(&ctx,data,len); - CC_SHA384_Final(reinterpret_cast(digest),&ctx); + CC_SHA512_CTX ctx; + CC_SHA384_Init(&ctx); + CC_SHA384_Update(&ctx, data, len); + CC_SHA384_Final(reinterpret_cast(digest), &ctx); } -static ZT_INLINE void SHA384(void *digest,const void *data0,unsigned int len0,const void *data1,unsigned int len1) +static ZT_INLINE void SHA384(void* digest, const void* data0, unsigned int len0, const void* data1, unsigned int len1) { - CC_SHA512_CTX ctx; - CC_SHA384_Init(&ctx); - CC_SHA384_Update(&ctx,data0,len0); - CC_SHA384_Update(&ctx,data1,len1); - CC_SHA384_Final(reinterpret_cast(digest),&ctx); + CC_SHA512_CTX ctx; + CC_SHA384_Init(&ctx); + CC_SHA384_Update(&ctx, data0, len0); + CC_SHA384_Update(&ctx, data1, len1); + CC_SHA384_Final(reinterpret_cast(digest), &ctx); } #endif #ifndef ZT_HAVE_NATIVE_SHA512 -void SHA512(void *digest,const void *data,unsigned int len); -void SHA384(void *digest,const void *data,unsigned int len); -void SHA384(void *digest,const void *data0,unsigned int len0,const void *data1,unsigned int len1); +void SHA512(void* digest, const void* data, unsigned int len); +void SHA384(void* digest, const void* data, unsigned int len); +void SHA384(void* digest, const void* data0, unsigned int len0, const void* data1, unsigned int len1); #endif /** @@ -70,7 +70,7 @@ void SHA384(void *digest,const void *data0,unsigned int len0,const void *data1,u * @param msglen Length of message * @param mac Buffer to fill with result */ -void HMACSHA384(const uint8_t key[ZT_SYMMETRIC_KEY_SIZE],const void *msg,unsigned int msglen,uint8_t mac[48]); +void HMACSHA384(const uint8_t key[ZT_SYMMETRIC_KEY_SIZE], const void* msg, unsigned int msglen, uint8_t mac[48]); /** * Compute KBKDF (key-based key derivation function) using HMAC-SHA-384 as a PRF @@ -81,8 +81,8 @@ void HMACSHA384(const uint8_t key[ZT_SYMMETRIC_KEY_SIZE],const void *msg,unsigne * @param iter Key iteration for generation of multiple keys for the same label/context * @param out Output to receive derived key */ -void KBKDFHMACSHA384(const uint8_t key[ZT_SYMMETRIC_KEY_SIZE],char label,char context,uint32_t iter,uint8_t out[ZT_SYMMETRIC_KEY_SIZE]); +void KBKDFHMACSHA384(const uint8_t key[ZT_SYMMETRIC_KEY_SIZE], char label, char context, uint32_t iter, uint8_t out[ZT_SYMMETRIC_KEY_SIZE]); -} // namespace ZeroTier +} // namespace ZeroTier #endif diff --git a/node/Salsa20.cpp b/node/Salsa20.cpp index 63573546..7ff415e4 100644 --- a/node/Salsa20.cpp +++ b/node/Salsa20.cpp @@ -7,12 +7,13 @@ * Since the original was public domain, this is too. */ -#include "Constants.hpp" #include "Salsa20.hpp" -#define ROTATE(v,c) (((v) << (c)) | ((v) >> (32 - (c)))) -#define XOR(v,w) ((v) ^ (w)) -#define PLUS(v,w) ((uint32_t)((v) + (w))) +#include "Constants.hpp" + +#define ROTATE(v, c) (((v) << (c)) | ((v) >> (32 - (c)))) +#define XOR(v, w) ((v) ^ (w)) +#define PLUS(v, w) ((uint32_t)((v) + (w))) // Set up load/store macros with appropriate endianness (we don't use these in SSE mode) #ifndef ZT_SALSA20_SSE @@ -21,1327 +22,1338 @@ #ifdef ZT_NO_TYPE_PUNNING // Slower version that does not use type punning -#define U8TO32_LITTLE(p) ( ((uint32_t)(p)[0]) | ((uint32_t)(p)[1] << 8) | ((uint32_t)(p)[2] << 16) | ((uint32_t)(p)[3] << 24) ) -static inline void U32TO8_LITTLE(uint8_t *const c,const uint32_t v) { c[0] = (uint8_t)v; c[1] = (uint8_t)(v >> 8); c[2] = (uint8_t)(v >> 16); c[3] = (uint8_t)(v >> 24); } +#define U8TO32_LITTLE(p) (((uint32_t)(p)[0]) | ((uint32_t)(p)[1] << 8) | ((uint32_t)(p)[2] << 16) | ((uint32_t)(p)[3] << 24)) +static inline void U32TO8_LITTLE(uint8_t* const c, const uint32_t v) +{ + c[0] = (uint8_t)v; + c[1] = (uint8_t)(v >> 8); + c[2] = (uint8_t)(v >> 16); + c[3] = (uint8_t)(v >> 24); +} #else // Fast version that just does 32-bit load/store -#define U8TO32_LITTLE(p) (*((const uint32_t *)((const void *)(p)))) -#define U32TO8_LITTLE(c,v) *((uint32_t *)((void *)(c))) = (v) -#endif // ZT_NO_TYPE_PUNNING +#define U8TO32_LITTLE(p) (*((const uint32_t*)((const void*)(p)))) +#define U32TO8_LITTLE(c, v) *((uint32_t*)((void*)(c))) = (v) +#endif // ZT_NO_TYPE_PUNNING -#else // __BYTE_ORDER == __BIG_ENDIAN (we don't support anything else... does MIDDLE_ENDIAN even still exist?) +#else // __BYTE_ORDER == __BIG_ENDIAN (we don't support anything else... does MIDDLE_ENDIAN even still exist?) #ifdef __GNUC__ // Use GNUC builtin bswap macros on big-endian machines if available -#define U8TO32_LITTLE(p) __builtin_bswap32(*((const uint32_t *)((const void *)(p)))) -#define U32TO8_LITTLE(c,v) *((uint32_t *)((void *)(c))) = __builtin_bswap32((v)) +#define U8TO32_LITTLE(p) __builtin_bswap32(*((const uint32_t*)((const void*)(p)))) +#define U32TO8_LITTLE(c, v) *((uint32_t*)((void*)(c))) = __builtin_bswap32((v)) -#else // no __GNUC__ +#else // no __GNUC__ // Otherwise do it the slow, manual way on BE machines -#define U8TO32_LITTLE(p) ( ((uint32_t)(p)[0]) | ((uint32_t)(p)[1] << 8) | ((uint32_t)(p)[2] << 16) | ((uint32_t)(p)[3] << 24) ) -static inline void U32TO8_LITTLE(uint8_t *const c,const uint32_t v) { c[0] = (uint8_t)v; c[1] = (uint8_t)(v >> 8); c[2] = (uint8_t)(v >> 16); c[3] = (uint8_t)(v >> 24); } +#define U8TO32_LITTLE(p) (((uint32_t)(p)[0]) | ((uint32_t)(p)[1] << 8) | ((uint32_t)(p)[2] << 16) | ((uint32_t)(p)[3] << 24)) +static inline void U32TO8_LITTLE(uint8_t* const c, const uint32_t v) +{ + c[0] = (uint8_t)v; + c[1] = (uint8_t)(v >> 8); + c[2] = (uint8_t)(v >> 16); + c[3] = (uint8_t)(v >> 24); +} -#endif // __GNUC__ or not +#endif // __GNUC__ or not -#endif // __BYTE_ORDER little or big? +#endif // __BYTE_ORDER little or big? -#endif // !ZT_SALSA20_SSE +#endif // !ZT_SALSA20_SSE // Statically compute and define SSE constants #ifdef ZT_SALSA20_SSE -class _s20sseconsts -{ -public: - _s20sseconsts() - { - maskLo32 = _mm_shuffle_epi32(_mm_cvtsi32_si128(-1), _MM_SHUFFLE(1, 0, 1, 0)); - maskHi32 = _mm_slli_epi64(maskLo32, 32); - } - __m128i maskLo32,maskHi32; +class _s20sseconsts { + public: + _s20sseconsts() + { + maskLo32 = _mm_shuffle_epi32(_mm_cvtsi32_si128(-1), _MM_SHUFFLE(1, 0, 1, 0)); + maskHi32 = _mm_slli_epi64(maskLo32, 32); + } + __m128i maskLo32, maskHi32; }; static const _s20sseconsts _S20SSECONSTANTS; #endif namespace ZeroTier { -void Salsa20::init(const void *key,const void *iv) +void Salsa20::init(const void* key, const void* iv) { #ifdef ZT_SALSA20_SSE - const uint32_t *const k = (const uint32_t *)key; - _state.i[0] = 0x61707865; - _state.i[1] = 0x3320646e; - _state.i[2] = 0x79622d32; - _state.i[3] = 0x6b206574; - _state.i[4] = k[3]; - _state.i[5] = 0; - _state.i[6] = k[7]; - _state.i[7] = k[2]; - _state.i[8] = 0; - _state.i[9] = k[6]; - _state.i[10] = k[1]; - _state.i[11] = ((const uint32_t *)iv)[1]; - _state.i[12] = k[5]; - _state.i[13] = k[0]; - _state.i[14] = ((const uint32_t *)iv)[0]; - _state.i[15] = k[4]; + const uint32_t* const k = (const uint32_t*)key; + _state.i[0] = 0x61707865; + _state.i[1] = 0x3320646e; + _state.i[2] = 0x79622d32; + _state.i[3] = 0x6b206574; + _state.i[4] = k[3]; + _state.i[5] = 0; + _state.i[6] = k[7]; + _state.i[7] = k[2]; + _state.i[8] = 0; + _state.i[9] = k[6]; + _state.i[10] = k[1]; + _state.i[11] = ((const uint32_t*)iv)[1]; + _state.i[12] = k[5]; + _state.i[13] = k[0]; + _state.i[14] = ((const uint32_t*)iv)[0]; + _state.i[15] = k[4]; #else - const char *const constants = "expand 32-byte k"; - const uint8_t *const k = (const uint8_t *)key; - _state.i[0] = U8TO32_LITTLE(constants + 0); - _state.i[1] = U8TO32_LITTLE(k + 0); - _state.i[2] = U8TO32_LITTLE(k + 4); - _state.i[3] = U8TO32_LITTLE(k + 8); - _state.i[4] = U8TO32_LITTLE(k + 12); - _state.i[5] = U8TO32_LITTLE(constants + 4); - _state.i[6] = U8TO32_LITTLE(((const uint8_t *)iv) + 0); - _state.i[7] = U8TO32_LITTLE(((const uint8_t *)iv) + 4); - _state.i[8] = 0; - _state.i[9] = 0; - _state.i[10] = U8TO32_LITTLE(constants + 8); - _state.i[11] = U8TO32_LITTLE(k + 16); - _state.i[12] = U8TO32_LITTLE(k + 20); - _state.i[13] = U8TO32_LITTLE(k + 24); - _state.i[14] = U8TO32_LITTLE(k + 28); - _state.i[15] = U8TO32_LITTLE(constants + 12); + const char* const constants = "expand 32-byte k"; + const uint8_t* const k = (const uint8_t*)key; + _state.i[0] = U8TO32_LITTLE(constants + 0); + _state.i[1] = U8TO32_LITTLE(k + 0); + _state.i[2] = U8TO32_LITTLE(k + 4); + _state.i[3] = U8TO32_LITTLE(k + 8); + _state.i[4] = U8TO32_LITTLE(k + 12); + _state.i[5] = U8TO32_LITTLE(constants + 4); + _state.i[6] = U8TO32_LITTLE(((const uint8_t*)iv) + 0); + _state.i[7] = U8TO32_LITTLE(((const uint8_t*)iv) + 4); + _state.i[8] = 0; + _state.i[9] = 0; + _state.i[10] = U8TO32_LITTLE(constants + 8); + _state.i[11] = U8TO32_LITTLE(k + 16); + _state.i[12] = U8TO32_LITTLE(k + 20); + _state.i[13] = U8TO32_LITTLE(k + 24); + _state.i[14] = U8TO32_LITTLE(k + 28); + _state.i[15] = U8TO32_LITTLE(constants + 12); #endif } -void Salsa20::crypt12(const void *in,void *out,unsigned int bytes) +void Salsa20::crypt12(const void* in, void* out, unsigned int bytes) { - uint8_t tmp[64]; - const uint8_t *m = (const uint8_t *)in; - uint8_t *c = (uint8_t *)out; - uint8_t *ctarget = c; - unsigned int i; + uint8_t tmp[64]; + const uint8_t* m = (const uint8_t*)in; + uint8_t* c = (uint8_t*)out; + uint8_t* ctarget = c; + unsigned int i; #ifndef ZT_SALSA20_SSE - uint32_t x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15; - uint32_t j0, j1, j2, j3, j4, j5, j6, j7, j8, j9, j10, j11, j12, j13, j14, j15; + uint32_t x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15; + uint32_t j0, j1, j2, j3, j4, j5, j6, j7, j8, j9, j10, j11, j12, j13, j14, j15; #endif - if (!bytes) { - return; - } + if (! bytes) { + return; + } #ifndef ZT_SALSA20_SSE - j0 = _state.i[0]; - j1 = _state.i[1]; - j2 = _state.i[2]; - j3 = _state.i[3]; - j4 = _state.i[4]; - j5 = _state.i[5]; - j6 = _state.i[6]; - j7 = _state.i[7]; - j8 = _state.i[8]; - j9 = _state.i[9]; - j10 = _state.i[10]; - j11 = _state.i[11]; - j12 = _state.i[12]; - j13 = _state.i[13]; - j14 = _state.i[14]; - j15 = _state.i[15]; + j0 = _state.i[0]; + j1 = _state.i[1]; + j2 = _state.i[2]; + j3 = _state.i[3]; + j4 = _state.i[4]; + j5 = _state.i[5]; + j6 = _state.i[6]; + j7 = _state.i[7]; + j8 = _state.i[8]; + j9 = _state.i[9]; + j10 = _state.i[10]; + j11 = _state.i[11]; + j12 = _state.i[12]; + j13 = _state.i[13]; + j14 = _state.i[14]; + j15 = _state.i[15]; #endif - for (;;) { - if (bytes < 64) { - for (i = 0;i < bytes;++i) { - tmp[i] = m[i]; - } - m = tmp; - ctarget = c; - c = tmp; - } + for (;;) { + if (bytes < 64) { + for (i = 0; i < bytes; ++i) { + tmp[i] = m[i]; + } + m = tmp; + ctarget = c; + c = tmp; + } #ifdef ZT_SALSA20_SSE - __m128i X0 = _mm_loadu_si128((const __m128i *)&(_state.v[0])); - __m128i X1 = _mm_loadu_si128((const __m128i *)&(_state.v[1])); - __m128i X2 = _mm_loadu_si128((const __m128i *)&(_state.v[2])); - __m128i X3 = _mm_loadu_si128((const __m128i *)&(_state.v[3])); - __m128i T; - __m128i X0s = X0; - __m128i X1s = X1; - __m128i X2s = X2; - __m128i X3s = X3; + __m128i X0 = _mm_loadu_si128((const __m128i*)&(_state.v[0])); + __m128i X1 = _mm_loadu_si128((const __m128i*)&(_state.v[1])); + __m128i X2 = _mm_loadu_si128((const __m128i*)&(_state.v[2])); + __m128i X3 = _mm_loadu_si128((const __m128i*)&(_state.v[3])); + __m128i T; + __m128i X0s = X0; + __m128i X1s = X1; + __m128i X2s = X2; + __m128i X3s = X3; - // 2X round ------------------------------------------------------------- - T = _mm_add_epi32(X0, X3); - X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25)); - T = _mm_add_epi32(X1, X0); - X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23)); - T = _mm_add_epi32(X2, X1); - X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19)); - T = _mm_add_epi32(X3, X2); - X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14)); - X1 = _mm_shuffle_epi32(X1, 0x93); - X2 = _mm_shuffle_epi32(X2, 0x4E); - X3 = _mm_shuffle_epi32(X3, 0x39); - T = _mm_add_epi32(X0, X1); - X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25)); - T = _mm_add_epi32(X3, X0); - X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23)); - T = _mm_add_epi32(X2, X3); - X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19)); - T = _mm_add_epi32(X1, X2); - X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14)); - X1 = _mm_shuffle_epi32(X1, 0x39); - X2 = _mm_shuffle_epi32(X2, 0x4E); - X3 = _mm_shuffle_epi32(X3, 0x93); + // 2X round ------------------------------------------------------------- + T = _mm_add_epi32(X0, X3); + X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25)); + T = _mm_add_epi32(X1, X0); + X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23)); + T = _mm_add_epi32(X2, X1); + X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19)); + T = _mm_add_epi32(X3, X2); + X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14)); + X1 = _mm_shuffle_epi32(X1, 0x93); + X2 = _mm_shuffle_epi32(X2, 0x4E); + X3 = _mm_shuffle_epi32(X3, 0x39); + T = _mm_add_epi32(X0, X1); + X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25)); + T = _mm_add_epi32(X3, X0); + X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23)); + T = _mm_add_epi32(X2, X3); + X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19)); + T = _mm_add_epi32(X1, X2); + X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14)); + X1 = _mm_shuffle_epi32(X1, 0x39); + X2 = _mm_shuffle_epi32(X2, 0x4E); + X3 = _mm_shuffle_epi32(X3, 0x93); - // 2X round ------------------------------------------------------------- - T = _mm_add_epi32(X0, X3); - X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25)); - T = _mm_add_epi32(X1, X0); - X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23)); - T = _mm_add_epi32(X2, X1); - X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19)); - T = _mm_add_epi32(X3, X2); - X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14)); - X1 = _mm_shuffle_epi32(X1, 0x93); - X2 = _mm_shuffle_epi32(X2, 0x4E); - X3 = _mm_shuffle_epi32(X3, 0x39); - T = _mm_add_epi32(X0, X1); - X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25)); - T = _mm_add_epi32(X3, X0); - X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23)); - T = _mm_add_epi32(X2, X3); - X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19)); - T = _mm_add_epi32(X1, X2); - X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14)); - X1 = _mm_shuffle_epi32(X1, 0x39); - X2 = _mm_shuffle_epi32(X2, 0x4E); - X3 = _mm_shuffle_epi32(X3, 0x93); + // 2X round ------------------------------------------------------------- + T = _mm_add_epi32(X0, X3); + X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25)); + T = _mm_add_epi32(X1, X0); + X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23)); + T = _mm_add_epi32(X2, X1); + X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19)); + T = _mm_add_epi32(X3, X2); + X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14)); + X1 = _mm_shuffle_epi32(X1, 0x93); + X2 = _mm_shuffle_epi32(X2, 0x4E); + X3 = _mm_shuffle_epi32(X3, 0x39); + T = _mm_add_epi32(X0, X1); + X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25)); + T = _mm_add_epi32(X3, X0); + X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23)); + T = _mm_add_epi32(X2, X3); + X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19)); + T = _mm_add_epi32(X1, X2); + X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14)); + X1 = _mm_shuffle_epi32(X1, 0x39); + X2 = _mm_shuffle_epi32(X2, 0x4E); + X3 = _mm_shuffle_epi32(X3, 0x93); - // 2X round ------------------------------------------------------------- - T = _mm_add_epi32(X0, X3); - X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25)); - T = _mm_add_epi32(X1, X0); - X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23)); - T = _mm_add_epi32(X2, X1); - X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19)); - T = _mm_add_epi32(X3, X2); - X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14)); - X1 = _mm_shuffle_epi32(X1, 0x93); - X2 = _mm_shuffle_epi32(X2, 0x4E); - X3 = _mm_shuffle_epi32(X3, 0x39); - T = _mm_add_epi32(X0, X1); - X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25)); - T = _mm_add_epi32(X3, X0); - X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23)); - T = _mm_add_epi32(X2, X3); - X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19)); - T = _mm_add_epi32(X1, X2); - X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14)); - X1 = _mm_shuffle_epi32(X1, 0x39); - X2 = _mm_shuffle_epi32(X2, 0x4E); - X3 = _mm_shuffle_epi32(X3, 0x93); + // 2X round ------------------------------------------------------------- + T = _mm_add_epi32(X0, X3); + X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25)); + T = _mm_add_epi32(X1, X0); + X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23)); + T = _mm_add_epi32(X2, X1); + X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19)); + T = _mm_add_epi32(X3, X2); + X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14)); + X1 = _mm_shuffle_epi32(X1, 0x93); + X2 = _mm_shuffle_epi32(X2, 0x4E); + X3 = _mm_shuffle_epi32(X3, 0x39); + T = _mm_add_epi32(X0, X1); + X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25)); + T = _mm_add_epi32(X3, X0); + X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23)); + T = _mm_add_epi32(X2, X3); + X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19)); + T = _mm_add_epi32(X1, X2); + X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14)); + X1 = _mm_shuffle_epi32(X1, 0x39); + X2 = _mm_shuffle_epi32(X2, 0x4E); + X3 = _mm_shuffle_epi32(X3, 0x93); - // 2X round ------------------------------------------------------------- - T = _mm_add_epi32(X0, X3); - X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25)); - T = _mm_add_epi32(X1, X0); - X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23)); - T = _mm_add_epi32(X2, X1); - X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19)); - T = _mm_add_epi32(X3, X2); - X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14)); - X1 = _mm_shuffle_epi32(X1, 0x93); - X2 = _mm_shuffle_epi32(X2, 0x4E); - X3 = _mm_shuffle_epi32(X3, 0x39); - T = _mm_add_epi32(X0, X1); - X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25)); - T = _mm_add_epi32(X3, X0); - X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23)); - T = _mm_add_epi32(X2, X3); - X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19)); - T = _mm_add_epi32(X1, X2); - X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14)); - X1 = _mm_shuffle_epi32(X1, 0x39); - X2 = _mm_shuffle_epi32(X2, 0x4E); - X3 = _mm_shuffle_epi32(X3, 0x93); + // 2X round ------------------------------------------------------------- + T = _mm_add_epi32(X0, X3); + X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25)); + T = _mm_add_epi32(X1, X0); + X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23)); + T = _mm_add_epi32(X2, X1); + X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19)); + T = _mm_add_epi32(X3, X2); + X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14)); + X1 = _mm_shuffle_epi32(X1, 0x93); + X2 = _mm_shuffle_epi32(X2, 0x4E); + X3 = _mm_shuffle_epi32(X3, 0x39); + T = _mm_add_epi32(X0, X1); + X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25)); + T = _mm_add_epi32(X3, X0); + X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23)); + T = _mm_add_epi32(X2, X3); + X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19)); + T = _mm_add_epi32(X1, X2); + X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14)); + X1 = _mm_shuffle_epi32(X1, 0x39); + X2 = _mm_shuffle_epi32(X2, 0x4E); + X3 = _mm_shuffle_epi32(X3, 0x93); - // 2X round ------------------------------------------------------------- - T = _mm_add_epi32(X0, X3); - X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25)); - T = _mm_add_epi32(X1, X0); - X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23)); - T = _mm_add_epi32(X2, X1); - X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19)); - T = _mm_add_epi32(X3, X2); - X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14)); - X1 = _mm_shuffle_epi32(X1, 0x93); - X2 = _mm_shuffle_epi32(X2, 0x4E); - X3 = _mm_shuffle_epi32(X3, 0x39); - T = _mm_add_epi32(X0, X1); - X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25)); - T = _mm_add_epi32(X3, X0); - X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23)); - T = _mm_add_epi32(X2, X3); - X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19)); - T = _mm_add_epi32(X1, X2); - X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14)); - X1 = _mm_shuffle_epi32(X1, 0x39); - X2 = _mm_shuffle_epi32(X2, 0x4E); - X3 = _mm_shuffle_epi32(X3, 0x93); + // 2X round ------------------------------------------------------------- + T = _mm_add_epi32(X0, X3); + X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25)); + T = _mm_add_epi32(X1, X0); + X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23)); + T = _mm_add_epi32(X2, X1); + X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19)); + T = _mm_add_epi32(X3, X2); + X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14)); + X1 = _mm_shuffle_epi32(X1, 0x93); + X2 = _mm_shuffle_epi32(X2, 0x4E); + X3 = _mm_shuffle_epi32(X3, 0x39); + T = _mm_add_epi32(X0, X1); + X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25)); + T = _mm_add_epi32(X3, X0); + X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23)); + T = _mm_add_epi32(X2, X3); + X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19)); + T = _mm_add_epi32(X1, X2); + X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14)); + X1 = _mm_shuffle_epi32(X1, 0x39); + X2 = _mm_shuffle_epi32(X2, 0x4E); + X3 = _mm_shuffle_epi32(X3, 0x93); - // 2X round ------------------------------------------------------------- - T = _mm_add_epi32(X0, X3); - X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25)); - T = _mm_add_epi32(X1, X0); - X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23)); - T = _mm_add_epi32(X2, X1); - X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19)); - T = _mm_add_epi32(X3, X2); - X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14)); - X1 = _mm_shuffle_epi32(X1, 0x93); - X2 = _mm_shuffle_epi32(X2, 0x4E); - X3 = _mm_shuffle_epi32(X3, 0x39); - T = _mm_add_epi32(X0, X1); - X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25)); - T = _mm_add_epi32(X3, X0); - X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23)); - T = _mm_add_epi32(X2, X3); - X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19)); - T = _mm_add_epi32(X1, X2); - X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14)); - X1 = _mm_shuffle_epi32(X1, 0x39); - X2 = _mm_shuffle_epi32(X2, 0x4E); - X3 = _mm_shuffle_epi32(X3, 0x93); + // 2X round ------------------------------------------------------------- + T = _mm_add_epi32(X0, X3); + X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25)); + T = _mm_add_epi32(X1, X0); + X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23)); + T = _mm_add_epi32(X2, X1); + X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19)); + T = _mm_add_epi32(X3, X2); + X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14)); + X1 = _mm_shuffle_epi32(X1, 0x93); + X2 = _mm_shuffle_epi32(X2, 0x4E); + X3 = _mm_shuffle_epi32(X3, 0x39); + T = _mm_add_epi32(X0, X1); + X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25)); + T = _mm_add_epi32(X3, X0); + X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23)); + T = _mm_add_epi32(X2, X3); + X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19)); + T = _mm_add_epi32(X1, X2); + X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14)); + X1 = _mm_shuffle_epi32(X1, 0x39); + X2 = _mm_shuffle_epi32(X2, 0x4E); + X3 = _mm_shuffle_epi32(X3, 0x93); - X0 = _mm_add_epi32(X0s,X0); - X1 = _mm_add_epi32(X1s,X1); - X2 = _mm_add_epi32(X2s,X2); - X3 = _mm_add_epi32(X3s,X3); + X0 = _mm_add_epi32(X0s, X0); + X1 = _mm_add_epi32(X1s, X1); + X2 = _mm_add_epi32(X2s, X2); + X3 = _mm_add_epi32(X3s, X3); - __m128i k02 = _mm_shuffle_epi32(_mm_or_si128(_mm_slli_epi64(X0, 32), _mm_srli_epi64(X3, 32)), _MM_SHUFFLE(0, 1, 2, 3)); - __m128i k13 = _mm_shuffle_epi32(_mm_or_si128(_mm_slli_epi64(X1, 32), _mm_srli_epi64(X0, 32)), _MM_SHUFFLE(0, 1, 2, 3)); - __m128i k20 = _mm_or_si128(_mm_and_si128(X2, _S20SSECONSTANTS.maskLo32), _mm_and_si128(X1, _S20SSECONSTANTS.maskHi32)); - __m128i k31 = _mm_or_si128(_mm_and_si128(X3, _S20SSECONSTANTS.maskLo32), _mm_and_si128(X2, _S20SSECONSTANTS.maskHi32)); - _mm_storeu_ps(reinterpret_cast(c),_mm_castsi128_ps(_mm_xor_si128(_mm_unpackhi_epi64(k02,k20),_mm_castps_si128(_mm_loadu_ps(reinterpret_cast(m)))))); - _mm_storeu_ps(reinterpret_cast(c) + 4,_mm_castsi128_ps(_mm_xor_si128(_mm_unpackhi_epi64(k13,k31),_mm_castps_si128(_mm_loadu_ps(reinterpret_cast(m) + 4))))); - _mm_storeu_ps(reinterpret_cast(c) + 8,_mm_castsi128_ps(_mm_xor_si128(_mm_unpacklo_epi64(k20,k02),_mm_castps_si128(_mm_loadu_ps(reinterpret_cast(m) + 8))))); - _mm_storeu_ps(reinterpret_cast(c) + 12,_mm_castsi128_ps(_mm_xor_si128(_mm_unpacklo_epi64(k31,k13),_mm_castps_si128(_mm_loadu_ps(reinterpret_cast(m) + 12))))); + __m128i k02 = _mm_shuffle_epi32(_mm_or_si128(_mm_slli_epi64(X0, 32), _mm_srli_epi64(X3, 32)), _MM_SHUFFLE(0, 1, 2, 3)); + __m128i k13 = _mm_shuffle_epi32(_mm_or_si128(_mm_slli_epi64(X1, 32), _mm_srli_epi64(X0, 32)), _MM_SHUFFLE(0, 1, 2, 3)); + __m128i k20 = _mm_or_si128(_mm_and_si128(X2, _S20SSECONSTANTS.maskLo32), _mm_and_si128(X1, _S20SSECONSTANTS.maskHi32)); + __m128i k31 = _mm_or_si128(_mm_and_si128(X3, _S20SSECONSTANTS.maskLo32), _mm_and_si128(X2, _S20SSECONSTANTS.maskHi32)); + _mm_storeu_ps(reinterpret_cast(c), _mm_castsi128_ps(_mm_xor_si128(_mm_unpackhi_epi64(k02, k20), _mm_castps_si128(_mm_loadu_ps(reinterpret_cast(m)))))); + _mm_storeu_ps(reinterpret_cast(c) + 4, _mm_castsi128_ps(_mm_xor_si128(_mm_unpackhi_epi64(k13, k31), _mm_castps_si128(_mm_loadu_ps(reinterpret_cast(m) + 4))))); + _mm_storeu_ps(reinterpret_cast(c) + 8, _mm_castsi128_ps(_mm_xor_si128(_mm_unpacklo_epi64(k20, k02), _mm_castps_si128(_mm_loadu_ps(reinterpret_cast(m) + 8))))); + _mm_storeu_ps(reinterpret_cast(c) + 12, _mm_castsi128_ps(_mm_xor_si128(_mm_unpacklo_epi64(k31, k13), _mm_castps_si128(_mm_loadu_ps(reinterpret_cast(m) + 12))))); - if (!(++_state.i[8])) { - ++_state.i[5]; // state reordered for SSE - /* stopping at 2^70 bytes per nonce is user's responsibility */ - } + if (! (++_state.i[8])) { + ++_state.i[5]; // state reordered for SSE + /* stopping at 2^70 bytes per nonce is user's responsibility */ + } #else - x0 = j0; - x1 = j1; - x2 = j2; - x3 = j3; - x4 = j4; - x5 = j5; - x6 = j6; - x7 = j7; - x8 = j8; - x9 = j9; - x10 = j10; - x11 = j11; - x12 = j12; - x13 = j13; - x14 = j14; - x15 = j15; + x0 = j0; + x1 = j1; + x2 = j2; + x3 = j3; + x4 = j4; + x5 = j5; + x6 = j6; + x7 = j7; + x8 = j8; + x9 = j9; + x10 = j10; + x11 = j11; + x12 = j12; + x13 = j13; + x14 = j14; + x15 = j15; - // 2X round ------------------------------------------------------------- - x4 = XOR( x4,ROTATE(PLUS( x0,x12), 7)); - x8 = XOR( x8,ROTATE(PLUS( x4, x0), 9)); - x12 = XOR(x12,ROTATE(PLUS( x8, x4),13)); - x0 = XOR( x0,ROTATE(PLUS(x12, x8),18)); - x9 = XOR( x9,ROTATE(PLUS( x5, x1), 7)); - x13 = XOR(x13,ROTATE(PLUS( x9, x5), 9)); - x1 = XOR( x1,ROTATE(PLUS(x13, x9),13)); - x5 = XOR( x5,ROTATE(PLUS( x1,x13),18)); - x14 = XOR(x14,ROTATE(PLUS(x10, x6), 7)); - x2 = XOR( x2,ROTATE(PLUS(x14,x10), 9)); - x6 = XOR( x6,ROTATE(PLUS( x2,x14),13)); - x10 = XOR(x10,ROTATE(PLUS( x6, x2),18)); - x3 = XOR( x3,ROTATE(PLUS(x15,x11), 7)); - x7 = XOR( x7,ROTATE(PLUS( x3,x15), 9)); - x11 = XOR(x11,ROTATE(PLUS( x7, x3),13)); - x15 = XOR(x15,ROTATE(PLUS(x11, x7),18)); - x1 = XOR( x1,ROTATE(PLUS( x0, x3), 7)); - x2 = XOR( x2,ROTATE(PLUS( x1, x0), 9)); - x3 = XOR( x3,ROTATE(PLUS( x2, x1),13)); - x0 = XOR( x0,ROTATE(PLUS( x3, x2),18)); - x6 = XOR( x6,ROTATE(PLUS( x5, x4), 7)); - x7 = XOR( x7,ROTATE(PLUS( x6, x5), 9)); - x4 = XOR( x4,ROTATE(PLUS( x7, x6),13)); - x5 = XOR( x5,ROTATE(PLUS( x4, x7),18)); - x11 = XOR(x11,ROTATE(PLUS(x10, x9), 7)); - x8 = XOR( x8,ROTATE(PLUS(x11,x10), 9)); - x9 = XOR( x9,ROTATE(PLUS( x8,x11),13)); - x10 = XOR(x10,ROTATE(PLUS( x9, x8),18)); - x12 = XOR(x12,ROTATE(PLUS(x15,x14), 7)); - x13 = XOR(x13,ROTATE(PLUS(x12,x15), 9)); - x14 = XOR(x14,ROTATE(PLUS(x13,x12),13)); - x15 = XOR(x15,ROTATE(PLUS(x14,x13),18)); + // 2X round ------------------------------------------------------------- + x4 = XOR(x4, ROTATE(PLUS(x0, x12), 7)); + x8 = XOR(x8, ROTATE(PLUS(x4, x0), 9)); + x12 = XOR(x12, ROTATE(PLUS(x8, x4), 13)); + x0 = XOR(x0, ROTATE(PLUS(x12, x8), 18)); + x9 = XOR(x9, ROTATE(PLUS(x5, x1), 7)); + x13 = XOR(x13, ROTATE(PLUS(x9, x5), 9)); + x1 = XOR(x1, ROTATE(PLUS(x13, x9), 13)); + x5 = XOR(x5, ROTATE(PLUS(x1, x13), 18)); + x14 = XOR(x14, ROTATE(PLUS(x10, x6), 7)); + x2 = XOR(x2, ROTATE(PLUS(x14, x10), 9)); + x6 = XOR(x6, ROTATE(PLUS(x2, x14), 13)); + x10 = XOR(x10, ROTATE(PLUS(x6, x2), 18)); + x3 = XOR(x3, ROTATE(PLUS(x15, x11), 7)); + x7 = XOR(x7, ROTATE(PLUS(x3, x15), 9)); + x11 = XOR(x11, ROTATE(PLUS(x7, x3), 13)); + x15 = XOR(x15, ROTATE(PLUS(x11, x7), 18)); + x1 = XOR(x1, ROTATE(PLUS(x0, x3), 7)); + x2 = XOR(x2, ROTATE(PLUS(x1, x0), 9)); + x3 = XOR(x3, ROTATE(PLUS(x2, x1), 13)); + x0 = XOR(x0, ROTATE(PLUS(x3, x2), 18)); + x6 = XOR(x6, ROTATE(PLUS(x5, x4), 7)); + x7 = XOR(x7, ROTATE(PLUS(x6, x5), 9)); + x4 = XOR(x4, ROTATE(PLUS(x7, x6), 13)); + x5 = XOR(x5, ROTATE(PLUS(x4, x7), 18)); + x11 = XOR(x11, ROTATE(PLUS(x10, x9), 7)); + x8 = XOR(x8, ROTATE(PLUS(x11, x10), 9)); + x9 = XOR(x9, ROTATE(PLUS(x8, x11), 13)); + x10 = XOR(x10, ROTATE(PLUS(x9, x8), 18)); + x12 = XOR(x12, ROTATE(PLUS(x15, x14), 7)); + x13 = XOR(x13, ROTATE(PLUS(x12, x15), 9)); + x14 = XOR(x14, ROTATE(PLUS(x13, x12), 13)); + x15 = XOR(x15, ROTATE(PLUS(x14, x13), 18)); - // 2X round ------------------------------------------------------------- - x4 = XOR( x4,ROTATE(PLUS( x0,x12), 7)); - x8 = XOR( x8,ROTATE(PLUS( x4, x0), 9)); - x12 = XOR(x12,ROTATE(PLUS( x8, x4),13)); - x0 = XOR( x0,ROTATE(PLUS(x12, x8),18)); - x9 = XOR( x9,ROTATE(PLUS( x5, x1), 7)); - x13 = XOR(x13,ROTATE(PLUS( x9, x5), 9)); - x1 = XOR( x1,ROTATE(PLUS(x13, x9),13)); - x5 = XOR( x5,ROTATE(PLUS( x1,x13),18)); - x14 = XOR(x14,ROTATE(PLUS(x10, x6), 7)); - x2 = XOR( x2,ROTATE(PLUS(x14,x10), 9)); - x6 = XOR( x6,ROTATE(PLUS( x2,x14),13)); - x10 = XOR(x10,ROTATE(PLUS( x6, x2),18)); - x3 = XOR( x3,ROTATE(PLUS(x15,x11), 7)); - x7 = XOR( x7,ROTATE(PLUS( x3,x15), 9)); - x11 = XOR(x11,ROTATE(PLUS( x7, x3),13)); - x15 = XOR(x15,ROTATE(PLUS(x11, x7),18)); - x1 = XOR( x1,ROTATE(PLUS( x0, x3), 7)); - x2 = XOR( x2,ROTATE(PLUS( x1, x0), 9)); - x3 = XOR( x3,ROTATE(PLUS( x2, x1),13)); - x0 = XOR( x0,ROTATE(PLUS( x3, x2),18)); - x6 = XOR( x6,ROTATE(PLUS( x5, x4), 7)); - x7 = XOR( x7,ROTATE(PLUS( x6, x5), 9)); - x4 = XOR( x4,ROTATE(PLUS( x7, x6),13)); - x5 = XOR( x5,ROTATE(PLUS( x4, x7),18)); - x11 = XOR(x11,ROTATE(PLUS(x10, x9), 7)); - x8 = XOR( x8,ROTATE(PLUS(x11,x10), 9)); - x9 = XOR( x9,ROTATE(PLUS( x8,x11),13)); - x10 = XOR(x10,ROTATE(PLUS( x9, x8),18)); - x12 = XOR(x12,ROTATE(PLUS(x15,x14), 7)); - x13 = XOR(x13,ROTATE(PLUS(x12,x15), 9)); - x14 = XOR(x14,ROTATE(PLUS(x13,x12),13)); - x15 = XOR(x15,ROTATE(PLUS(x14,x13),18)); + // 2X round ------------------------------------------------------------- + x4 = XOR(x4, ROTATE(PLUS(x0, x12), 7)); + x8 = XOR(x8, ROTATE(PLUS(x4, x0), 9)); + x12 = XOR(x12, ROTATE(PLUS(x8, x4), 13)); + x0 = XOR(x0, ROTATE(PLUS(x12, x8), 18)); + x9 = XOR(x9, ROTATE(PLUS(x5, x1), 7)); + x13 = XOR(x13, ROTATE(PLUS(x9, x5), 9)); + x1 = XOR(x1, ROTATE(PLUS(x13, x9), 13)); + x5 = XOR(x5, ROTATE(PLUS(x1, x13), 18)); + x14 = XOR(x14, ROTATE(PLUS(x10, x6), 7)); + x2 = XOR(x2, ROTATE(PLUS(x14, x10), 9)); + x6 = XOR(x6, ROTATE(PLUS(x2, x14), 13)); + x10 = XOR(x10, ROTATE(PLUS(x6, x2), 18)); + x3 = XOR(x3, ROTATE(PLUS(x15, x11), 7)); + x7 = XOR(x7, ROTATE(PLUS(x3, x15), 9)); + x11 = XOR(x11, ROTATE(PLUS(x7, x3), 13)); + x15 = XOR(x15, ROTATE(PLUS(x11, x7), 18)); + x1 = XOR(x1, ROTATE(PLUS(x0, x3), 7)); + x2 = XOR(x2, ROTATE(PLUS(x1, x0), 9)); + x3 = XOR(x3, ROTATE(PLUS(x2, x1), 13)); + x0 = XOR(x0, ROTATE(PLUS(x3, x2), 18)); + x6 = XOR(x6, ROTATE(PLUS(x5, x4), 7)); + x7 = XOR(x7, ROTATE(PLUS(x6, x5), 9)); + x4 = XOR(x4, ROTATE(PLUS(x7, x6), 13)); + x5 = XOR(x5, ROTATE(PLUS(x4, x7), 18)); + x11 = XOR(x11, ROTATE(PLUS(x10, x9), 7)); + x8 = XOR(x8, ROTATE(PLUS(x11, x10), 9)); + x9 = XOR(x9, ROTATE(PLUS(x8, x11), 13)); + x10 = XOR(x10, ROTATE(PLUS(x9, x8), 18)); + x12 = XOR(x12, ROTATE(PLUS(x15, x14), 7)); + x13 = XOR(x13, ROTATE(PLUS(x12, x15), 9)); + x14 = XOR(x14, ROTATE(PLUS(x13, x12), 13)); + x15 = XOR(x15, ROTATE(PLUS(x14, x13), 18)); - // 2X round ------------------------------------------------------------- - x4 = XOR( x4,ROTATE(PLUS( x0,x12), 7)); - x8 = XOR( x8,ROTATE(PLUS( x4, x0), 9)); - x12 = XOR(x12,ROTATE(PLUS( x8, x4),13)); - x0 = XOR( x0,ROTATE(PLUS(x12, x8),18)); - x9 = XOR( x9,ROTATE(PLUS( x5, x1), 7)); - x13 = XOR(x13,ROTATE(PLUS( x9, x5), 9)); - x1 = XOR( x1,ROTATE(PLUS(x13, x9),13)); - x5 = XOR( x5,ROTATE(PLUS( x1,x13),18)); - x14 = XOR(x14,ROTATE(PLUS(x10, x6), 7)); - x2 = XOR( x2,ROTATE(PLUS(x14,x10), 9)); - x6 = XOR( x6,ROTATE(PLUS( x2,x14),13)); - x10 = XOR(x10,ROTATE(PLUS( x6, x2),18)); - x3 = XOR( x3,ROTATE(PLUS(x15,x11), 7)); - x7 = XOR( x7,ROTATE(PLUS( x3,x15), 9)); - x11 = XOR(x11,ROTATE(PLUS( x7, x3),13)); - x15 = XOR(x15,ROTATE(PLUS(x11, x7),18)); - x1 = XOR( x1,ROTATE(PLUS( x0, x3), 7)); - x2 = XOR( x2,ROTATE(PLUS( x1, x0), 9)); - x3 = XOR( x3,ROTATE(PLUS( x2, x1),13)); - x0 = XOR( x0,ROTATE(PLUS( x3, x2),18)); - x6 = XOR( x6,ROTATE(PLUS( x5, x4), 7)); - x7 = XOR( x7,ROTATE(PLUS( x6, x5), 9)); - x4 = XOR( x4,ROTATE(PLUS( x7, x6),13)); - x5 = XOR( x5,ROTATE(PLUS( x4, x7),18)); - x11 = XOR(x11,ROTATE(PLUS(x10, x9), 7)); - x8 = XOR( x8,ROTATE(PLUS(x11,x10), 9)); - x9 = XOR( x9,ROTATE(PLUS( x8,x11),13)); - x10 = XOR(x10,ROTATE(PLUS( x9, x8),18)); - x12 = XOR(x12,ROTATE(PLUS(x15,x14), 7)); - x13 = XOR(x13,ROTATE(PLUS(x12,x15), 9)); - x14 = XOR(x14,ROTATE(PLUS(x13,x12),13)); - x15 = XOR(x15,ROTATE(PLUS(x14,x13),18)); + // 2X round ------------------------------------------------------------- + x4 = XOR(x4, ROTATE(PLUS(x0, x12), 7)); + x8 = XOR(x8, ROTATE(PLUS(x4, x0), 9)); + x12 = XOR(x12, ROTATE(PLUS(x8, x4), 13)); + x0 = XOR(x0, ROTATE(PLUS(x12, x8), 18)); + x9 = XOR(x9, ROTATE(PLUS(x5, x1), 7)); + x13 = XOR(x13, ROTATE(PLUS(x9, x5), 9)); + x1 = XOR(x1, ROTATE(PLUS(x13, x9), 13)); + x5 = XOR(x5, ROTATE(PLUS(x1, x13), 18)); + x14 = XOR(x14, ROTATE(PLUS(x10, x6), 7)); + x2 = XOR(x2, ROTATE(PLUS(x14, x10), 9)); + x6 = XOR(x6, ROTATE(PLUS(x2, x14), 13)); + x10 = XOR(x10, ROTATE(PLUS(x6, x2), 18)); + x3 = XOR(x3, ROTATE(PLUS(x15, x11), 7)); + x7 = XOR(x7, ROTATE(PLUS(x3, x15), 9)); + x11 = XOR(x11, ROTATE(PLUS(x7, x3), 13)); + x15 = XOR(x15, ROTATE(PLUS(x11, x7), 18)); + x1 = XOR(x1, ROTATE(PLUS(x0, x3), 7)); + x2 = XOR(x2, ROTATE(PLUS(x1, x0), 9)); + x3 = XOR(x3, ROTATE(PLUS(x2, x1), 13)); + x0 = XOR(x0, ROTATE(PLUS(x3, x2), 18)); + x6 = XOR(x6, ROTATE(PLUS(x5, x4), 7)); + x7 = XOR(x7, ROTATE(PLUS(x6, x5), 9)); + x4 = XOR(x4, ROTATE(PLUS(x7, x6), 13)); + x5 = XOR(x5, ROTATE(PLUS(x4, x7), 18)); + x11 = XOR(x11, ROTATE(PLUS(x10, x9), 7)); + x8 = XOR(x8, ROTATE(PLUS(x11, x10), 9)); + x9 = XOR(x9, ROTATE(PLUS(x8, x11), 13)); + x10 = XOR(x10, ROTATE(PLUS(x9, x8), 18)); + x12 = XOR(x12, ROTATE(PLUS(x15, x14), 7)); + x13 = XOR(x13, ROTATE(PLUS(x12, x15), 9)); + x14 = XOR(x14, ROTATE(PLUS(x13, x12), 13)); + x15 = XOR(x15, ROTATE(PLUS(x14, x13), 18)); - // 2X round ------------------------------------------------------------- - x4 = XOR( x4,ROTATE(PLUS( x0,x12), 7)); - x8 = XOR( x8,ROTATE(PLUS( x4, x0), 9)); - x12 = XOR(x12,ROTATE(PLUS( x8, x4),13)); - x0 = XOR( x0,ROTATE(PLUS(x12, x8),18)); - x9 = XOR( x9,ROTATE(PLUS( x5, x1), 7)); - x13 = XOR(x13,ROTATE(PLUS( x9, x5), 9)); - x1 = XOR( x1,ROTATE(PLUS(x13, x9),13)); - x5 = XOR( x5,ROTATE(PLUS( x1,x13),18)); - x14 = XOR(x14,ROTATE(PLUS(x10, x6), 7)); - x2 = XOR( x2,ROTATE(PLUS(x14,x10), 9)); - x6 = XOR( x6,ROTATE(PLUS( x2,x14),13)); - x10 = XOR(x10,ROTATE(PLUS( x6, x2),18)); - x3 = XOR( x3,ROTATE(PLUS(x15,x11), 7)); - x7 = XOR( x7,ROTATE(PLUS( x3,x15), 9)); - x11 = XOR(x11,ROTATE(PLUS( x7, x3),13)); - x15 = XOR(x15,ROTATE(PLUS(x11, x7),18)); - x1 = XOR( x1,ROTATE(PLUS( x0, x3), 7)); - x2 = XOR( x2,ROTATE(PLUS( x1, x0), 9)); - x3 = XOR( x3,ROTATE(PLUS( x2, x1),13)); - x0 = XOR( x0,ROTATE(PLUS( x3, x2),18)); - x6 = XOR( x6,ROTATE(PLUS( x5, x4), 7)); - x7 = XOR( x7,ROTATE(PLUS( x6, x5), 9)); - x4 = XOR( x4,ROTATE(PLUS( x7, x6),13)); - x5 = XOR( x5,ROTATE(PLUS( x4, x7),18)); - x11 = XOR(x11,ROTATE(PLUS(x10, x9), 7)); - x8 = XOR( x8,ROTATE(PLUS(x11,x10), 9)); - x9 = XOR( x9,ROTATE(PLUS( x8,x11),13)); - x10 = XOR(x10,ROTATE(PLUS( x9, x8),18)); - x12 = XOR(x12,ROTATE(PLUS(x15,x14), 7)); - x13 = XOR(x13,ROTATE(PLUS(x12,x15), 9)); - x14 = XOR(x14,ROTATE(PLUS(x13,x12),13)); - x15 = XOR(x15,ROTATE(PLUS(x14,x13),18)); + // 2X round ------------------------------------------------------------- + x4 = XOR(x4, ROTATE(PLUS(x0, x12), 7)); + x8 = XOR(x8, ROTATE(PLUS(x4, x0), 9)); + x12 = XOR(x12, ROTATE(PLUS(x8, x4), 13)); + x0 = XOR(x0, ROTATE(PLUS(x12, x8), 18)); + x9 = XOR(x9, ROTATE(PLUS(x5, x1), 7)); + x13 = XOR(x13, ROTATE(PLUS(x9, x5), 9)); + x1 = XOR(x1, ROTATE(PLUS(x13, x9), 13)); + x5 = XOR(x5, ROTATE(PLUS(x1, x13), 18)); + x14 = XOR(x14, ROTATE(PLUS(x10, x6), 7)); + x2 = XOR(x2, ROTATE(PLUS(x14, x10), 9)); + x6 = XOR(x6, ROTATE(PLUS(x2, x14), 13)); + x10 = XOR(x10, ROTATE(PLUS(x6, x2), 18)); + x3 = XOR(x3, ROTATE(PLUS(x15, x11), 7)); + x7 = XOR(x7, ROTATE(PLUS(x3, x15), 9)); + x11 = XOR(x11, ROTATE(PLUS(x7, x3), 13)); + x15 = XOR(x15, ROTATE(PLUS(x11, x7), 18)); + x1 = XOR(x1, ROTATE(PLUS(x0, x3), 7)); + x2 = XOR(x2, ROTATE(PLUS(x1, x0), 9)); + x3 = XOR(x3, ROTATE(PLUS(x2, x1), 13)); + x0 = XOR(x0, ROTATE(PLUS(x3, x2), 18)); + x6 = XOR(x6, ROTATE(PLUS(x5, x4), 7)); + x7 = XOR(x7, ROTATE(PLUS(x6, x5), 9)); + x4 = XOR(x4, ROTATE(PLUS(x7, x6), 13)); + x5 = XOR(x5, ROTATE(PLUS(x4, x7), 18)); + x11 = XOR(x11, ROTATE(PLUS(x10, x9), 7)); + x8 = XOR(x8, ROTATE(PLUS(x11, x10), 9)); + x9 = XOR(x9, ROTATE(PLUS(x8, x11), 13)); + x10 = XOR(x10, ROTATE(PLUS(x9, x8), 18)); + x12 = XOR(x12, ROTATE(PLUS(x15, x14), 7)); + x13 = XOR(x13, ROTATE(PLUS(x12, x15), 9)); + x14 = XOR(x14, ROTATE(PLUS(x13, x12), 13)); + x15 = XOR(x15, ROTATE(PLUS(x14, x13), 18)); - // 2X round ------------------------------------------------------------- - x4 = XOR( x4,ROTATE(PLUS( x0,x12), 7)); - x8 = XOR( x8,ROTATE(PLUS( x4, x0), 9)); - x12 = XOR(x12,ROTATE(PLUS( x8, x4),13)); - x0 = XOR( x0,ROTATE(PLUS(x12, x8),18)); - x9 = XOR( x9,ROTATE(PLUS( x5, x1), 7)); - x13 = XOR(x13,ROTATE(PLUS( x9, x5), 9)); - x1 = XOR( x1,ROTATE(PLUS(x13, x9),13)); - x5 = XOR( x5,ROTATE(PLUS( x1,x13),18)); - x14 = XOR(x14,ROTATE(PLUS(x10, x6), 7)); - x2 = XOR( x2,ROTATE(PLUS(x14,x10), 9)); - x6 = XOR( x6,ROTATE(PLUS( x2,x14),13)); - x10 = XOR(x10,ROTATE(PLUS( x6, x2),18)); - x3 = XOR( x3,ROTATE(PLUS(x15,x11), 7)); - x7 = XOR( x7,ROTATE(PLUS( x3,x15), 9)); - x11 = XOR(x11,ROTATE(PLUS( x7, x3),13)); - x15 = XOR(x15,ROTATE(PLUS(x11, x7),18)); - x1 = XOR( x1,ROTATE(PLUS( x0, x3), 7)); - x2 = XOR( x2,ROTATE(PLUS( x1, x0), 9)); - x3 = XOR( x3,ROTATE(PLUS( x2, x1),13)); - x0 = XOR( x0,ROTATE(PLUS( x3, x2),18)); - x6 = XOR( x6,ROTATE(PLUS( x5, x4), 7)); - x7 = XOR( x7,ROTATE(PLUS( x6, x5), 9)); - x4 = XOR( x4,ROTATE(PLUS( x7, x6),13)); - x5 = XOR( x5,ROTATE(PLUS( x4, x7),18)); - x11 = XOR(x11,ROTATE(PLUS(x10, x9), 7)); - x8 = XOR( x8,ROTATE(PLUS(x11,x10), 9)); - x9 = XOR( x9,ROTATE(PLUS( x8,x11),13)); - x10 = XOR(x10,ROTATE(PLUS( x9, x8),18)); - x12 = XOR(x12,ROTATE(PLUS(x15,x14), 7)); - x13 = XOR(x13,ROTATE(PLUS(x12,x15), 9)); - x14 = XOR(x14,ROTATE(PLUS(x13,x12),13)); - x15 = XOR(x15,ROTATE(PLUS(x14,x13),18)); + // 2X round ------------------------------------------------------------- + x4 = XOR(x4, ROTATE(PLUS(x0, x12), 7)); + x8 = XOR(x8, ROTATE(PLUS(x4, x0), 9)); + x12 = XOR(x12, ROTATE(PLUS(x8, x4), 13)); + x0 = XOR(x0, ROTATE(PLUS(x12, x8), 18)); + x9 = XOR(x9, ROTATE(PLUS(x5, x1), 7)); + x13 = XOR(x13, ROTATE(PLUS(x9, x5), 9)); + x1 = XOR(x1, ROTATE(PLUS(x13, x9), 13)); + x5 = XOR(x5, ROTATE(PLUS(x1, x13), 18)); + x14 = XOR(x14, ROTATE(PLUS(x10, x6), 7)); + x2 = XOR(x2, ROTATE(PLUS(x14, x10), 9)); + x6 = XOR(x6, ROTATE(PLUS(x2, x14), 13)); + x10 = XOR(x10, ROTATE(PLUS(x6, x2), 18)); + x3 = XOR(x3, ROTATE(PLUS(x15, x11), 7)); + x7 = XOR(x7, ROTATE(PLUS(x3, x15), 9)); + x11 = XOR(x11, ROTATE(PLUS(x7, x3), 13)); + x15 = XOR(x15, ROTATE(PLUS(x11, x7), 18)); + x1 = XOR(x1, ROTATE(PLUS(x0, x3), 7)); + x2 = XOR(x2, ROTATE(PLUS(x1, x0), 9)); + x3 = XOR(x3, ROTATE(PLUS(x2, x1), 13)); + x0 = XOR(x0, ROTATE(PLUS(x3, x2), 18)); + x6 = XOR(x6, ROTATE(PLUS(x5, x4), 7)); + x7 = XOR(x7, ROTATE(PLUS(x6, x5), 9)); + x4 = XOR(x4, ROTATE(PLUS(x7, x6), 13)); + x5 = XOR(x5, ROTATE(PLUS(x4, x7), 18)); + x11 = XOR(x11, ROTATE(PLUS(x10, x9), 7)); + x8 = XOR(x8, ROTATE(PLUS(x11, x10), 9)); + x9 = XOR(x9, ROTATE(PLUS(x8, x11), 13)); + x10 = XOR(x10, ROTATE(PLUS(x9, x8), 18)); + x12 = XOR(x12, ROTATE(PLUS(x15, x14), 7)); + x13 = XOR(x13, ROTATE(PLUS(x12, x15), 9)); + x14 = XOR(x14, ROTATE(PLUS(x13, x12), 13)); + x15 = XOR(x15, ROTATE(PLUS(x14, x13), 18)); - // 2X round ------------------------------------------------------------- - x4 = XOR( x4,ROTATE(PLUS( x0,x12), 7)); - x8 = XOR( x8,ROTATE(PLUS( x4, x0), 9)); - x12 = XOR(x12,ROTATE(PLUS( x8, x4),13)); - x0 = XOR( x0,ROTATE(PLUS(x12, x8),18)); - x9 = XOR( x9,ROTATE(PLUS( x5, x1), 7)); - x13 = XOR(x13,ROTATE(PLUS( x9, x5), 9)); - x1 = XOR( x1,ROTATE(PLUS(x13, x9),13)); - x5 = XOR( x5,ROTATE(PLUS( x1,x13),18)); - x14 = XOR(x14,ROTATE(PLUS(x10, x6), 7)); - x2 = XOR( x2,ROTATE(PLUS(x14,x10), 9)); - x6 = XOR( x6,ROTATE(PLUS( x2,x14),13)); - x10 = XOR(x10,ROTATE(PLUS( x6, x2),18)); - x3 = XOR( x3,ROTATE(PLUS(x15,x11), 7)); - x7 = XOR( x7,ROTATE(PLUS( x3,x15), 9)); - x11 = XOR(x11,ROTATE(PLUS( x7, x3),13)); - x15 = XOR(x15,ROTATE(PLUS(x11, x7),18)); - x1 = XOR( x1,ROTATE(PLUS( x0, x3), 7)); - x2 = XOR( x2,ROTATE(PLUS( x1, x0), 9)); - x3 = XOR( x3,ROTATE(PLUS( x2, x1),13)); - x0 = XOR( x0,ROTATE(PLUS( x3, x2),18)); - x6 = XOR( x6,ROTATE(PLUS( x5, x4), 7)); - x7 = XOR( x7,ROTATE(PLUS( x6, x5), 9)); - x4 = XOR( x4,ROTATE(PLUS( x7, x6),13)); - x5 = XOR( x5,ROTATE(PLUS( x4, x7),18)); - x11 = XOR(x11,ROTATE(PLUS(x10, x9), 7)); - x8 = XOR( x8,ROTATE(PLUS(x11,x10), 9)); - x9 = XOR( x9,ROTATE(PLUS( x8,x11),13)); - x10 = XOR(x10,ROTATE(PLUS( x9, x8),18)); - x12 = XOR(x12,ROTATE(PLUS(x15,x14), 7)); - x13 = XOR(x13,ROTATE(PLUS(x12,x15), 9)); - x14 = XOR(x14,ROTATE(PLUS(x13,x12),13)); - x15 = XOR(x15,ROTATE(PLUS(x14,x13),18)); + // 2X round ------------------------------------------------------------- + x4 = XOR(x4, ROTATE(PLUS(x0, x12), 7)); + x8 = XOR(x8, ROTATE(PLUS(x4, x0), 9)); + x12 = XOR(x12, ROTATE(PLUS(x8, x4), 13)); + x0 = XOR(x0, ROTATE(PLUS(x12, x8), 18)); + x9 = XOR(x9, ROTATE(PLUS(x5, x1), 7)); + x13 = XOR(x13, ROTATE(PLUS(x9, x5), 9)); + x1 = XOR(x1, ROTATE(PLUS(x13, x9), 13)); + x5 = XOR(x5, ROTATE(PLUS(x1, x13), 18)); + x14 = XOR(x14, ROTATE(PLUS(x10, x6), 7)); + x2 = XOR(x2, ROTATE(PLUS(x14, x10), 9)); + x6 = XOR(x6, ROTATE(PLUS(x2, x14), 13)); + x10 = XOR(x10, ROTATE(PLUS(x6, x2), 18)); + x3 = XOR(x3, ROTATE(PLUS(x15, x11), 7)); + x7 = XOR(x7, ROTATE(PLUS(x3, x15), 9)); + x11 = XOR(x11, ROTATE(PLUS(x7, x3), 13)); + x15 = XOR(x15, ROTATE(PLUS(x11, x7), 18)); + x1 = XOR(x1, ROTATE(PLUS(x0, x3), 7)); + x2 = XOR(x2, ROTATE(PLUS(x1, x0), 9)); + x3 = XOR(x3, ROTATE(PLUS(x2, x1), 13)); + x0 = XOR(x0, ROTATE(PLUS(x3, x2), 18)); + x6 = XOR(x6, ROTATE(PLUS(x5, x4), 7)); + x7 = XOR(x7, ROTATE(PLUS(x6, x5), 9)); + x4 = XOR(x4, ROTATE(PLUS(x7, x6), 13)); + x5 = XOR(x5, ROTATE(PLUS(x4, x7), 18)); + x11 = XOR(x11, ROTATE(PLUS(x10, x9), 7)); + x8 = XOR(x8, ROTATE(PLUS(x11, x10), 9)); + x9 = XOR(x9, ROTATE(PLUS(x8, x11), 13)); + x10 = XOR(x10, ROTATE(PLUS(x9, x8), 18)); + x12 = XOR(x12, ROTATE(PLUS(x15, x14), 7)); + x13 = XOR(x13, ROTATE(PLUS(x12, x15), 9)); + x14 = XOR(x14, ROTATE(PLUS(x13, x12), 13)); + x15 = XOR(x15, ROTATE(PLUS(x14, x13), 18)); - x0 = PLUS(x0,j0); - x1 = PLUS(x1,j1); - x2 = PLUS(x2,j2); - x3 = PLUS(x3,j3); - x4 = PLUS(x4,j4); - x5 = PLUS(x5,j5); - x6 = PLUS(x6,j6); - x7 = PLUS(x7,j7); - x8 = PLUS(x8,j8); - x9 = PLUS(x9,j9); - x10 = PLUS(x10,j10); - x11 = PLUS(x11,j11); - x12 = PLUS(x12,j12); - x13 = PLUS(x13,j13); - x14 = PLUS(x14,j14); - x15 = PLUS(x15,j15); + x0 = PLUS(x0, j0); + x1 = PLUS(x1, j1); + x2 = PLUS(x2, j2); + x3 = PLUS(x3, j3); + x4 = PLUS(x4, j4); + x5 = PLUS(x5, j5); + x6 = PLUS(x6, j6); + x7 = PLUS(x7, j7); + x8 = PLUS(x8, j8); + x9 = PLUS(x9, j9); + x10 = PLUS(x10, j10); + x11 = PLUS(x11, j11); + x12 = PLUS(x12, j12); + x13 = PLUS(x13, j13); + x14 = PLUS(x14, j14); + x15 = PLUS(x15, j15); - U32TO8_LITTLE(c + 0,XOR(x0,U8TO32_LITTLE(m + 0))); - U32TO8_LITTLE(c + 4,XOR(x1,U8TO32_LITTLE(m + 4))); - U32TO8_LITTLE(c + 8,XOR(x2,U8TO32_LITTLE(m + 8))); - U32TO8_LITTLE(c + 12,XOR(x3,U8TO32_LITTLE(m + 12))); - U32TO8_LITTLE(c + 16,XOR(x4,U8TO32_LITTLE(m + 16))); - U32TO8_LITTLE(c + 20,XOR(x5,U8TO32_LITTLE(m + 20))); - U32TO8_LITTLE(c + 24,XOR(x6,U8TO32_LITTLE(m + 24))); - U32TO8_LITTLE(c + 28,XOR(x7,U8TO32_LITTLE(m + 28))); - U32TO8_LITTLE(c + 32,XOR(x8,U8TO32_LITTLE(m + 32))); - U32TO8_LITTLE(c + 36,XOR(x9,U8TO32_LITTLE(m + 36))); - U32TO8_LITTLE(c + 40,XOR(x10,U8TO32_LITTLE(m + 40))); - U32TO8_LITTLE(c + 44,XOR(x11,U8TO32_LITTLE(m + 44))); - U32TO8_LITTLE(c + 48,XOR(x12,U8TO32_LITTLE(m + 48))); - U32TO8_LITTLE(c + 52,XOR(x13,U8TO32_LITTLE(m + 52))); - U32TO8_LITTLE(c + 56,XOR(x14,U8TO32_LITTLE(m + 56))); - U32TO8_LITTLE(c + 60,XOR(x15,U8TO32_LITTLE(m + 60))); + U32TO8_LITTLE(c + 0, XOR(x0, U8TO32_LITTLE(m + 0))); + U32TO8_LITTLE(c + 4, XOR(x1, U8TO32_LITTLE(m + 4))); + U32TO8_LITTLE(c + 8, XOR(x2, U8TO32_LITTLE(m + 8))); + U32TO8_LITTLE(c + 12, XOR(x3, U8TO32_LITTLE(m + 12))); + U32TO8_LITTLE(c + 16, XOR(x4, U8TO32_LITTLE(m + 16))); + U32TO8_LITTLE(c + 20, XOR(x5, U8TO32_LITTLE(m + 20))); + U32TO8_LITTLE(c + 24, XOR(x6, U8TO32_LITTLE(m + 24))); + U32TO8_LITTLE(c + 28, XOR(x7, U8TO32_LITTLE(m + 28))); + U32TO8_LITTLE(c + 32, XOR(x8, U8TO32_LITTLE(m + 32))); + U32TO8_LITTLE(c + 36, XOR(x9, U8TO32_LITTLE(m + 36))); + U32TO8_LITTLE(c + 40, XOR(x10, U8TO32_LITTLE(m + 40))); + U32TO8_LITTLE(c + 44, XOR(x11, U8TO32_LITTLE(m + 44))); + U32TO8_LITTLE(c + 48, XOR(x12, U8TO32_LITTLE(m + 48))); + U32TO8_LITTLE(c + 52, XOR(x13, U8TO32_LITTLE(m + 52))); + U32TO8_LITTLE(c + 56, XOR(x14, U8TO32_LITTLE(m + 56))); + U32TO8_LITTLE(c + 60, XOR(x15, U8TO32_LITTLE(m + 60))); - if (!(++j8)) { - ++j9; - /* stopping at 2^70 bytes per nonce is user's responsibility */ - } + if (! (++j8)) { + ++j9; + /* stopping at 2^70 bytes per nonce is user's responsibility */ + } #endif - if (bytes <= 64) { - if (bytes < 64) { - for (i = 0;i < bytes;++i) { - ctarget[i] = c[i]; - } - } + if (bytes <= 64) { + if (bytes < 64) { + for (i = 0; i < bytes; ++i) { + ctarget[i] = c[i]; + } + } #ifndef ZT_SALSA20_SSE - _state.i[8] = j8; - _state.i[9] = j9; + _state.i[8] = j8; + _state.i[9] = j9; #endif - return; - } + return; + } - bytes -= 64; - c += 64; - m += 64; - } + bytes -= 64; + c += 64; + m += 64; + } } -void Salsa20::crypt20(const void *in,void *out,unsigned int bytes) +void Salsa20::crypt20(const void* in, void* out, unsigned int bytes) { - uint8_t tmp[64]; - const uint8_t *m = (const uint8_t *)in; - uint8_t *c = (uint8_t *)out; - uint8_t *ctarget = c; - unsigned int i; + uint8_t tmp[64]; + const uint8_t* m = (const uint8_t*)in; + uint8_t* c = (uint8_t*)out; + uint8_t* ctarget = c; + unsigned int i; #ifndef ZT_SALSA20_SSE - uint32_t x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15; - uint32_t j0, j1, j2, j3, j4, j5, j6, j7, j8, j9, j10, j11, j12, j13, j14, j15; + uint32_t x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15; + uint32_t j0, j1, j2, j3, j4, j5, j6, j7, j8, j9, j10, j11, j12, j13, j14, j15; #endif - if (!bytes) { - return; - } + if (! bytes) { + return; + } #ifndef ZT_SALSA20_SSE - j0 = _state.i[0]; - j1 = _state.i[1]; - j2 = _state.i[2]; - j3 = _state.i[3]; - j4 = _state.i[4]; - j5 = _state.i[5]; - j6 = _state.i[6]; - j7 = _state.i[7]; - j8 = _state.i[8]; - j9 = _state.i[9]; - j10 = _state.i[10]; - j11 = _state.i[11]; - j12 = _state.i[12]; - j13 = _state.i[13]; - j14 = _state.i[14]; - j15 = _state.i[15]; + j0 = _state.i[0]; + j1 = _state.i[1]; + j2 = _state.i[2]; + j3 = _state.i[3]; + j4 = _state.i[4]; + j5 = _state.i[5]; + j6 = _state.i[6]; + j7 = _state.i[7]; + j8 = _state.i[8]; + j9 = _state.i[9]; + j10 = _state.i[10]; + j11 = _state.i[11]; + j12 = _state.i[12]; + j13 = _state.i[13]; + j14 = _state.i[14]; + j15 = _state.i[15]; #endif - for (;;) { - if (bytes < 64) { - for (i = 0;i < bytes;++i) { - tmp[i] = m[i]; - } - m = tmp; - ctarget = c; - c = tmp; - } + for (;;) { + if (bytes < 64) { + for (i = 0; i < bytes; ++i) { + tmp[i] = m[i]; + } + m = tmp; + ctarget = c; + c = tmp; + } #ifdef ZT_SALSA20_SSE - __m128i X0 = _mm_loadu_si128((const __m128i *)&(_state.v[0])); - __m128i X1 = _mm_loadu_si128((const __m128i *)&(_state.v[1])); - __m128i X2 = _mm_loadu_si128((const __m128i *)&(_state.v[2])); - __m128i X3 = _mm_loadu_si128((const __m128i *)&(_state.v[3])); - __m128i T; - __m128i X0s = X0; - __m128i X1s = X1; - __m128i X2s = X2; - __m128i X3s = X3; + __m128i X0 = _mm_loadu_si128((const __m128i*)&(_state.v[0])); + __m128i X1 = _mm_loadu_si128((const __m128i*)&(_state.v[1])); + __m128i X2 = _mm_loadu_si128((const __m128i*)&(_state.v[2])); + __m128i X3 = _mm_loadu_si128((const __m128i*)&(_state.v[3])); + __m128i T; + __m128i X0s = X0; + __m128i X1s = X1; + __m128i X2s = X2; + __m128i X3s = X3; - // 2X round ------------------------------------------------------------- - T = _mm_add_epi32(X0, X3); - X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25)); - T = _mm_add_epi32(X1, X0); - X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23)); - T = _mm_add_epi32(X2, X1); - X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19)); - T = _mm_add_epi32(X3, X2); - X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14)); - X1 = _mm_shuffle_epi32(X1, 0x93); - X2 = _mm_shuffle_epi32(X2, 0x4E); - X3 = _mm_shuffle_epi32(X3, 0x39); - T = _mm_add_epi32(X0, X1); - X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25)); - T = _mm_add_epi32(X3, X0); - X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23)); - T = _mm_add_epi32(X2, X3); - X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19)); - T = _mm_add_epi32(X1, X2); - X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14)); - X1 = _mm_shuffle_epi32(X1, 0x39); - X2 = _mm_shuffle_epi32(X2, 0x4E); - X3 = _mm_shuffle_epi32(X3, 0x93); + // 2X round ------------------------------------------------------------- + T = _mm_add_epi32(X0, X3); + X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25)); + T = _mm_add_epi32(X1, X0); + X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23)); + T = _mm_add_epi32(X2, X1); + X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19)); + T = _mm_add_epi32(X3, X2); + X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14)); + X1 = _mm_shuffle_epi32(X1, 0x93); + X2 = _mm_shuffle_epi32(X2, 0x4E); + X3 = _mm_shuffle_epi32(X3, 0x39); + T = _mm_add_epi32(X0, X1); + X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25)); + T = _mm_add_epi32(X3, X0); + X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23)); + T = _mm_add_epi32(X2, X3); + X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19)); + T = _mm_add_epi32(X1, X2); + X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14)); + X1 = _mm_shuffle_epi32(X1, 0x39); + X2 = _mm_shuffle_epi32(X2, 0x4E); + X3 = _mm_shuffle_epi32(X3, 0x93); - // 2X round ------------------------------------------------------------- - T = _mm_add_epi32(X0, X3); - X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25)); - T = _mm_add_epi32(X1, X0); - X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23)); - T = _mm_add_epi32(X2, X1); - X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19)); - T = _mm_add_epi32(X3, X2); - X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14)); - X1 = _mm_shuffle_epi32(X1, 0x93); - X2 = _mm_shuffle_epi32(X2, 0x4E); - X3 = _mm_shuffle_epi32(X3, 0x39); - T = _mm_add_epi32(X0, X1); - X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25)); - T = _mm_add_epi32(X3, X0); - X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23)); - T = _mm_add_epi32(X2, X3); - X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19)); - T = _mm_add_epi32(X1, X2); - X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14)); - X1 = _mm_shuffle_epi32(X1, 0x39); - X2 = _mm_shuffle_epi32(X2, 0x4E); - X3 = _mm_shuffle_epi32(X3, 0x93); + // 2X round ------------------------------------------------------------- + T = _mm_add_epi32(X0, X3); + X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25)); + T = _mm_add_epi32(X1, X0); + X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23)); + T = _mm_add_epi32(X2, X1); + X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19)); + T = _mm_add_epi32(X3, X2); + X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14)); + X1 = _mm_shuffle_epi32(X1, 0x93); + X2 = _mm_shuffle_epi32(X2, 0x4E); + X3 = _mm_shuffle_epi32(X3, 0x39); + T = _mm_add_epi32(X0, X1); + X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25)); + T = _mm_add_epi32(X3, X0); + X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23)); + T = _mm_add_epi32(X2, X3); + X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19)); + T = _mm_add_epi32(X1, X2); + X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14)); + X1 = _mm_shuffle_epi32(X1, 0x39); + X2 = _mm_shuffle_epi32(X2, 0x4E); + X3 = _mm_shuffle_epi32(X3, 0x93); - // 2X round ------------------------------------------------------------- - T = _mm_add_epi32(X0, X3); - X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25)); - T = _mm_add_epi32(X1, X0); - X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23)); - T = _mm_add_epi32(X2, X1); - X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19)); - T = _mm_add_epi32(X3, X2); - X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14)); - X1 = _mm_shuffle_epi32(X1, 0x93); - X2 = _mm_shuffle_epi32(X2, 0x4E); - X3 = _mm_shuffle_epi32(X3, 0x39); - T = _mm_add_epi32(X0, X1); - X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25)); - T = _mm_add_epi32(X3, X0); - X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23)); - T = _mm_add_epi32(X2, X3); - X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19)); - T = _mm_add_epi32(X1, X2); - X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14)); - X1 = _mm_shuffle_epi32(X1, 0x39); - X2 = _mm_shuffle_epi32(X2, 0x4E); - X3 = _mm_shuffle_epi32(X3, 0x93); + // 2X round ------------------------------------------------------------- + T = _mm_add_epi32(X0, X3); + X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25)); + T = _mm_add_epi32(X1, X0); + X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23)); + T = _mm_add_epi32(X2, X1); + X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19)); + T = _mm_add_epi32(X3, X2); + X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14)); + X1 = _mm_shuffle_epi32(X1, 0x93); + X2 = _mm_shuffle_epi32(X2, 0x4E); + X3 = _mm_shuffle_epi32(X3, 0x39); + T = _mm_add_epi32(X0, X1); + X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25)); + T = _mm_add_epi32(X3, X0); + X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23)); + T = _mm_add_epi32(X2, X3); + X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19)); + T = _mm_add_epi32(X1, X2); + X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14)); + X1 = _mm_shuffle_epi32(X1, 0x39); + X2 = _mm_shuffle_epi32(X2, 0x4E); + X3 = _mm_shuffle_epi32(X3, 0x93); - // 2X round ------------------------------------------------------------- - T = _mm_add_epi32(X0, X3); - X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25)); - T = _mm_add_epi32(X1, X0); - X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23)); - T = _mm_add_epi32(X2, X1); - X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19)); - T = _mm_add_epi32(X3, X2); - X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14)); - X1 = _mm_shuffle_epi32(X1, 0x93); - X2 = _mm_shuffle_epi32(X2, 0x4E); - X3 = _mm_shuffle_epi32(X3, 0x39); - T = _mm_add_epi32(X0, X1); - X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25)); - T = _mm_add_epi32(X3, X0); - X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23)); - T = _mm_add_epi32(X2, X3); - X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19)); - T = _mm_add_epi32(X1, X2); - X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14)); - X1 = _mm_shuffle_epi32(X1, 0x39); - X2 = _mm_shuffle_epi32(X2, 0x4E); - X3 = _mm_shuffle_epi32(X3, 0x93); + // 2X round ------------------------------------------------------------- + T = _mm_add_epi32(X0, X3); + X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25)); + T = _mm_add_epi32(X1, X0); + X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23)); + T = _mm_add_epi32(X2, X1); + X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19)); + T = _mm_add_epi32(X3, X2); + X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14)); + X1 = _mm_shuffle_epi32(X1, 0x93); + X2 = _mm_shuffle_epi32(X2, 0x4E); + X3 = _mm_shuffle_epi32(X3, 0x39); + T = _mm_add_epi32(X0, X1); + X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25)); + T = _mm_add_epi32(X3, X0); + X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23)); + T = _mm_add_epi32(X2, X3); + X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19)); + T = _mm_add_epi32(X1, X2); + X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14)); + X1 = _mm_shuffle_epi32(X1, 0x39); + X2 = _mm_shuffle_epi32(X2, 0x4E); + X3 = _mm_shuffle_epi32(X3, 0x93); - // 2X round ------------------------------------------------------------- - T = _mm_add_epi32(X0, X3); - X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25)); - T = _mm_add_epi32(X1, X0); - X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23)); - T = _mm_add_epi32(X2, X1); - X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19)); - T = _mm_add_epi32(X3, X2); - X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14)); - X1 = _mm_shuffle_epi32(X1, 0x93); - X2 = _mm_shuffle_epi32(X2, 0x4E); - X3 = _mm_shuffle_epi32(X3, 0x39); - T = _mm_add_epi32(X0, X1); - X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25)); - T = _mm_add_epi32(X3, X0); - X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23)); - T = _mm_add_epi32(X2, X3); - X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19)); - T = _mm_add_epi32(X1, X2); - X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14)); - X1 = _mm_shuffle_epi32(X1, 0x39); - X2 = _mm_shuffle_epi32(X2, 0x4E); - X3 = _mm_shuffle_epi32(X3, 0x93); + // 2X round ------------------------------------------------------------- + T = _mm_add_epi32(X0, X3); + X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25)); + T = _mm_add_epi32(X1, X0); + X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23)); + T = _mm_add_epi32(X2, X1); + X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19)); + T = _mm_add_epi32(X3, X2); + X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14)); + X1 = _mm_shuffle_epi32(X1, 0x93); + X2 = _mm_shuffle_epi32(X2, 0x4E); + X3 = _mm_shuffle_epi32(X3, 0x39); + T = _mm_add_epi32(X0, X1); + X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25)); + T = _mm_add_epi32(X3, X0); + X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23)); + T = _mm_add_epi32(X2, X3); + X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19)); + T = _mm_add_epi32(X1, X2); + X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14)); + X1 = _mm_shuffle_epi32(X1, 0x39); + X2 = _mm_shuffle_epi32(X2, 0x4E); + X3 = _mm_shuffle_epi32(X3, 0x93); - // 2X round ------------------------------------------------------------- - T = _mm_add_epi32(X0, X3); - X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25)); - T = _mm_add_epi32(X1, X0); - X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23)); - T = _mm_add_epi32(X2, X1); - X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19)); - T = _mm_add_epi32(X3, X2); - X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14)); - X1 = _mm_shuffle_epi32(X1, 0x93); - X2 = _mm_shuffle_epi32(X2, 0x4E); - X3 = _mm_shuffle_epi32(X3, 0x39); - T = _mm_add_epi32(X0, X1); - X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25)); - T = _mm_add_epi32(X3, X0); - X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23)); - T = _mm_add_epi32(X2, X3); - X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19)); - T = _mm_add_epi32(X1, X2); - X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14)); - X1 = _mm_shuffle_epi32(X1, 0x39); - X2 = _mm_shuffle_epi32(X2, 0x4E); - X3 = _mm_shuffle_epi32(X3, 0x93); + // 2X round ------------------------------------------------------------- + T = _mm_add_epi32(X0, X3); + X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25)); + T = _mm_add_epi32(X1, X0); + X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23)); + T = _mm_add_epi32(X2, X1); + X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19)); + T = _mm_add_epi32(X3, X2); + X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14)); + X1 = _mm_shuffle_epi32(X1, 0x93); + X2 = _mm_shuffle_epi32(X2, 0x4E); + X3 = _mm_shuffle_epi32(X3, 0x39); + T = _mm_add_epi32(X0, X1); + X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25)); + T = _mm_add_epi32(X3, X0); + X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23)); + T = _mm_add_epi32(X2, X3); + X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19)); + T = _mm_add_epi32(X1, X2); + X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14)); + X1 = _mm_shuffle_epi32(X1, 0x39); + X2 = _mm_shuffle_epi32(X2, 0x4E); + X3 = _mm_shuffle_epi32(X3, 0x93); - // 2X round ------------------------------------------------------------- - T = _mm_add_epi32(X0, X3); - X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25)); - T = _mm_add_epi32(X1, X0); - X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23)); - T = _mm_add_epi32(X2, X1); - X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19)); - T = _mm_add_epi32(X3, X2); - X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14)); - X1 = _mm_shuffle_epi32(X1, 0x93); - X2 = _mm_shuffle_epi32(X2, 0x4E); - X3 = _mm_shuffle_epi32(X3, 0x39); - T = _mm_add_epi32(X0, X1); - X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25)); - T = _mm_add_epi32(X3, X0); - X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23)); - T = _mm_add_epi32(X2, X3); - X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19)); - T = _mm_add_epi32(X1, X2); - X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14)); - X1 = _mm_shuffle_epi32(X1, 0x39); - X2 = _mm_shuffle_epi32(X2, 0x4E); - X3 = _mm_shuffle_epi32(X3, 0x93); + // 2X round ------------------------------------------------------------- + T = _mm_add_epi32(X0, X3); + X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25)); + T = _mm_add_epi32(X1, X0); + X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23)); + T = _mm_add_epi32(X2, X1); + X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19)); + T = _mm_add_epi32(X3, X2); + X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14)); + X1 = _mm_shuffle_epi32(X1, 0x93); + X2 = _mm_shuffle_epi32(X2, 0x4E); + X3 = _mm_shuffle_epi32(X3, 0x39); + T = _mm_add_epi32(X0, X1); + X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25)); + T = _mm_add_epi32(X3, X0); + X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23)); + T = _mm_add_epi32(X2, X3); + X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19)); + T = _mm_add_epi32(X1, X2); + X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14)); + X1 = _mm_shuffle_epi32(X1, 0x39); + X2 = _mm_shuffle_epi32(X2, 0x4E); + X3 = _mm_shuffle_epi32(X3, 0x93); - // 2X round ------------------------------------------------------------- - T = _mm_add_epi32(X0, X3); - X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25)); - T = _mm_add_epi32(X1, X0); - X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23)); - T = _mm_add_epi32(X2, X1); - X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19)); - T = _mm_add_epi32(X3, X2); - X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14)); - X1 = _mm_shuffle_epi32(X1, 0x93); - X2 = _mm_shuffle_epi32(X2, 0x4E); - X3 = _mm_shuffle_epi32(X3, 0x39); - T = _mm_add_epi32(X0, X1); - X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25)); - T = _mm_add_epi32(X3, X0); - X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23)); - T = _mm_add_epi32(X2, X3); - X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19)); - T = _mm_add_epi32(X1, X2); - X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14)); - X1 = _mm_shuffle_epi32(X1, 0x39); - X2 = _mm_shuffle_epi32(X2, 0x4E); - X3 = _mm_shuffle_epi32(X3, 0x93); + // 2X round ------------------------------------------------------------- + T = _mm_add_epi32(X0, X3); + X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25)); + T = _mm_add_epi32(X1, X0); + X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23)); + T = _mm_add_epi32(X2, X1); + X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19)); + T = _mm_add_epi32(X3, X2); + X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14)); + X1 = _mm_shuffle_epi32(X1, 0x93); + X2 = _mm_shuffle_epi32(X2, 0x4E); + X3 = _mm_shuffle_epi32(X3, 0x39); + T = _mm_add_epi32(X0, X1); + X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25)); + T = _mm_add_epi32(X3, X0); + X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23)); + T = _mm_add_epi32(X2, X3); + X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19)); + T = _mm_add_epi32(X1, X2); + X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14)); + X1 = _mm_shuffle_epi32(X1, 0x39); + X2 = _mm_shuffle_epi32(X2, 0x4E); + X3 = _mm_shuffle_epi32(X3, 0x93); - // 2X round ------------------------------------------------------------- - T = _mm_add_epi32(X0, X3); - X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25)); - T = _mm_add_epi32(X1, X0); - X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23)); - T = _mm_add_epi32(X2, X1); - X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19)); - T = _mm_add_epi32(X3, X2); - X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14)); - X1 = _mm_shuffle_epi32(X1, 0x93); - X2 = _mm_shuffle_epi32(X2, 0x4E); - X3 = _mm_shuffle_epi32(X3, 0x39); - T = _mm_add_epi32(X0, X1); - X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25)); - T = _mm_add_epi32(X3, X0); - X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23)); - T = _mm_add_epi32(X2, X3); - X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19)); - T = _mm_add_epi32(X1, X2); - X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14)); - X1 = _mm_shuffle_epi32(X1, 0x39); - X2 = _mm_shuffle_epi32(X2, 0x4E); - X3 = _mm_shuffle_epi32(X3, 0x93); + // 2X round ------------------------------------------------------------- + T = _mm_add_epi32(X0, X3); + X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25)); + T = _mm_add_epi32(X1, X0); + X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23)); + T = _mm_add_epi32(X2, X1); + X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19)); + T = _mm_add_epi32(X3, X2); + X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14)); + X1 = _mm_shuffle_epi32(X1, 0x93); + X2 = _mm_shuffle_epi32(X2, 0x4E); + X3 = _mm_shuffle_epi32(X3, 0x39); + T = _mm_add_epi32(X0, X1); + X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25)); + T = _mm_add_epi32(X3, X0); + X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23)); + T = _mm_add_epi32(X2, X3); + X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19)); + T = _mm_add_epi32(X1, X2); + X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14)); + X1 = _mm_shuffle_epi32(X1, 0x39); + X2 = _mm_shuffle_epi32(X2, 0x4E); + X3 = _mm_shuffle_epi32(X3, 0x93); - // 2X round ------------------------------------------------------------- - T = _mm_add_epi32(X0, X3); - X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25)); - T = _mm_add_epi32(X1, X0); - X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23)); - T = _mm_add_epi32(X2, X1); - X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19)); - T = _mm_add_epi32(X3, X2); - X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14)); - X1 = _mm_shuffle_epi32(X1, 0x93); - X2 = _mm_shuffle_epi32(X2, 0x4E); - X3 = _mm_shuffle_epi32(X3, 0x39); - T = _mm_add_epi32(X0, X1); - X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25)); - T = _mm_add_epi32(X3, X0); - X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23)); - T = _mm_add_epi32(X2, X3); - X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19)); - T = _mm_add_epi32(X1, X2); - X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14)); - X1 = _mm_shuffle_epi32(X1, 0x39); - X2 = _mm_shuffle_epi32(X2, 0x4E); - X3 = _mm_shuffle_epi32(X3, 0x93); + // 2X round ------------------------------------------------------------- + T = _mm_add_epi32(X0, X3); + X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25)); + T = _mm_add_epi32(X1, X0); + X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23)); + T = _mm_add_epi32(X2, X1); + X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19)); + T = _mm_add_epi32(X3, X2); + X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14)); + X1 = _mm_shuffle_epi32(X1, 0x93); + X2 = _mm_shuffle_epi32(X2, 0x4E); + X3 = _mm_shuffle_epi32(X3, 0x39); + T = _mm_add_epi32(X0, X1); + X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25)); + T = _mm_add_epi32(X3, X0); + X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23)); + T = _mm_add_epi32(X2, X3); + X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19)); + T = _mm_add_epi32(X1, X2); + X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14)); + X1 = _mm_shuffle_epi32(X1, 0x39); + X2 = _mm_shuffle_epi32(X2, 0x4E); + X3 = _mm_shuffle_epi32(X3, 0x93); - X0 = _mm_add_epi32(X0s,X0); - X1 = _mm_add_epi32(X1s,X1); - X2 = _mm_add_epi32(X2s,X2); - X3 = _mm_add_epi32(X3s,X3); + X0 = _mm_add_epi32(X0s, X0); + X1 = _mm_add_epi32(X1s, X1); + X2 = _mm_add_epi32(X2s, X2); + X3 = _mm_add_epi32(X3s, X3); - __m128i k02 = _mm_shuffle_epi32(_mm_or_si128(_mm_slli_epi64(X0, 32), _mm_srli_epi64(X3, 32)), _MM_SHUFFLE(0, 1, 2, 3)); - __m128i k13 = _mm_shuffle_epi32(_mm_or_si128(_mm_slli_epi64(X1, 32), _mm_srli_epi64(X0, 32)), _MM_SHUFFLE(0, 1, 2, 3)); - __m128i k20 = _mm_or_si128(_mm_and_si128(X2, _S20SSECONSTANTS.maskLo32), _mm_and_si128(X1, _S20SSECONSTANTS.maskHi32)); - __m128i k31 = _mm_or_si128(_mm_and_si128(X3, _S20SSECONSTANTS.maskLo32), _mm_and_si128(X2, _S20SSECONSTANTS.maskHi32)); - _mm_storeu_ps(reinterpret_cast(c),_mm_castsi128_ps(_mm_xor_si128(_mm_unpackhi_epi64(k02,k20),_mm_castps_si128(_mm_loadu_ps(reinterpret_cast(m)))))); - _mm_storeu_ps(reinterpret_cast(c) + 4,_mm_castsi128_ps(_mm_xor_si128(_mm_unpackhi_epi64(k13,k31),_mm_castps_si128(_mm_loadu_ps(reinterpret_cast(m) + 4))))); - _mm_storeu_ps(reinterpret_cast(c) + 8,_mm_castsi128_ps(_mm_xor_si128(_mm_unpacklo_epi64(k20,k02),_mm_castps_si128(_mm_loadu_ps(reinterpret_cast(m) + 8))))); - _mm_storeu_ps(reinterpret_cast(c) + 12,_mm_castsi128_ps(_mm_xor_si128(_mm_unpacklo_epi64(k31,k13),_mm_castps_si128(_mm_loadu_ps(reinterpret_cast(m) + 12))))); + __m128i k02 = _mm_shuffle_epi32(_mm_or_si128(_mm_slli_epi64(X0, 32), _mm_srli_epi64(X3, 32)), _MM_SHUFFLE(0, 1, 2, 3)); + __m128i k13 = _mm_shuffle_epi32(_mm_or_si128(_mm_slli_epi64(X1, 32), _mm_srli_epi64(X0, 32)), _MM_SHUFFLE(0, 1, 2, 3)); + __m128i k20 = _mm_or_si128(_mm_and_si128(X2, _S20SSECONSTANTS.maskLo32), _mm_and_si128(X1, _S20SSECONSTANTS.maskHi32)); + __m128i k31 = _mm_or_si128(_mm_and_si128(X3, _S20SSECONSTANTS.maskLo32), _mm_and_si128(X2, _S20SSECONSTANTS.maskHi32)); + _mm_storeu_ps(reinterpret_cast(c), _mm_castsi128_ps(_mm_xor_si128(_mm_unpackhi_epi64(k02, k20), _mm_castps_si128(_mm_loadu_ps(reinterpret_cast(m)))))); + _mm_storeu_ps(reinterpret_cast(c) + 4, _mm_castsi128_ps(_mm_xor_si128(_mm_unpackhi_epi64(k13, k31), _mm_castps_si128(_mm_loadu_ps(reinterpret_cast(m) + 4))))); + _mm_storeu_ps(reinterpret_cast(c) + 8, _mm_castsi128_ps(_mm_xor_si128(_mm_unpacklo_epi64(k20, k02), _mm_castps_si128(_mm_loadu_ps(reinterpret_cast(m) + 8))))); + _mm_storeu_ps(reinterpret_cast(c) + 12, _mm_castsi128_ps(_mm_xor_si128(_mm_unpacklo_epi64(k31, k13), _mm_castps_si128(_mm_loadu_ps(reinterpret_cast(m) + 12))))); - if (!(++_state.i[8])) { - ++_state.i[5]; // state reordered for SSE - /* stopping at 2^70 bytes per nonce is user's responsibility */ - } + if (! (++_state.i[8])) { + ++_state.i[5]; // state reordered for SSE + /* stopping at 2^70 bytes per nonce is user's responsibility */ + } #else - x0 = j0; - x1 = j1; - x2 = j2; - x3 = j3; - x4 = j4; - x5 = j5; - x6 = j6; - x7 = j7; - x8 = j8; - x9 = j9; - x10 = j10; - x11 = j11; - x12 = j12; - x13 = j13; - x14 = j14; - x15 = j15; + x0 = j0; + x1 = j1; + x2 = j2; + x3 = j3; + x4 = j4; + x5 = j5; + x6 = j6; + x7 = j7; + x8 = j8; + x9 = j9; + x10 = j10; + x11 = j11; + x12 = j12; + x13 = j13; + x14 = j14; + x15 = j15; - // 2X round ------------------------------------------------------------- - x4 = XOR( x4,ROTATE(PLUS( x0,x12), 7)); - x8 = XOR( x8,ROTATE(PLUS( x4, x0), 9)); - x12 = XOR(x12,ROTATE(PLUS( x8, x4),13)); - x0 = XOR( x0,ROTATE(PLUS(x12, x8),18)); - x9 = XOR( x9,ROTATE(PLUS( x5, x1), 7)); - x13 = XOR(x13,ROTATE(PLUS( x9, x5), 9)); - x1 = XOR( x1,ROTATE(PLUS(x13, x9),13)); - x5 = XOR( x5,ROTATE(PLUS( x1,x13),18)); - x14 = XOR(x14,ROTATE(PLUS(x10, x6), 7)); - x2 = XOR( x2,ROTATE(PLUS(x14,x10), 9)); - x6 = XOR( x6,ROTATE(PLUS( x2,x14),13)); - x10 = XOR(x10,ROTATE(PLUS( x6, x2),18)); - x3 = XOR( x3,ROTATE(PLUS(x15,x11), 7)); - x7 = XOR( x7,ROTATE(PLUS( x3,x15), 9)); - x11 = XOR(x11,ROTATE(PLUS( x7, x3),13)); - x15 = XOR(x15,ROTATE(PLUS(x11, x7),18)); - x1 = XOR( x1,ROTATE(PLUS( x0, x3), 7)); - x2 = XOR( x2,ROTATE(PLUS( x1, x0), 9)); - x3 = XOR( x3,ROTATE(PLUS( x2, x1),13)); - x0 = XOR( x0,ROTATE(PLUS( x3, x2),18)); - x6 = XOR( x6,ROTATE(PLUS( x5, x4), 7)); - x7 = XOR( x7,ROTATE(PLUS( x6, x5), 9)); - x4 = XOR( x4,ROTATE(PLUS( x7, x6),13)); - x5 = XOR( x5,ROTATE(PLUS( x4, x7),18)); - x11 = XOR(x11,ROTATE(PLUS(x10, x9), 7)); - x8 = XOR( x8,ROTATE(PLUS(x11,x10), 9)); - x9 = XOR( x9,ROTATE(PLUS( x8,x11),13)); - x10 = XOR(x10,ROTATE(PLUS( x9, x8),18)); - x12 = XOR(x12,ROTATE(PLUS(x15,x14), 7)); - x13 = XOR(x13,ROTATE(PLUS(x12,x15), 9)); - x14 = XOR(x14,ROTATE(PLUS(x13,x12),13)); - x15 = XOR(x15,ROTATE(PLUS(x14,x13),18)); + // 2X round ------------------------------------------------------------- + x4 = XOR(x4, ROTATE(PLUS(x0, x12), 7)); + x8 = XOR(x8, ROTATE(PLUS(x4, x0), 9)); + x12 = XOR(x12, ROTATE(PLUS(x8, x4), 13)); + x0 = XOR(x0, ROTATE(PLUS(x12, x8), 18)); + x9 = XOR(x9, ROTATE(PLUS(x5, x1), 7)); + x13 = XOR(x13, ROTATE(PLUS(x9, x5), 9)); + x1 = XOR(x1, ROTATE(PLUS(x13, x9), 13)); + x5 = XOR(x5, ROTATE(PLUS(x1, x13), 18)); + x14 = XOR(x14, ROTATE(PLUS(x10, x6), 7)); + x2 = XOR(x2, ROTATE(PLUS(x14, x10), 9)); + x6 = XOR(x6, ROTATE(PLUS(x2, x14), 13)); + x10 = XOR(x10, ROTATE(PLUS(x6, x2), 18)); + x3 = XOR(x3, ROTATE(PLUS(x15, x11), 7)); + x7 = XOR(x7, ROTATE(PLUS(x3, x15), 9)); + x11 = XOR(x11, ROTATE(PLUS(x7, x3), 13)); + x15 = XOR(x15, ROTATE(PLUS(x11, x7), 18)); + x1 = XOR(x1, ROTATE(PLUS(x0, x3), 7)); + x2 = XOR(x2, ROTATE(PLUS(x1, x0), 9)); + x3 = XOR(x3, ROTATE(PLUS(x2, x1), 13)); + x0 = XOR(x0, ROTATE(PLUS(x3, x2), 18)); + x6 = XOR(x6, ROTATE(PLUS(x5, x4), 7)); + x7 = XOR(x7, ROTATE(PLUS(x6, x5), 9)); + x4 = XOR(x4, ROTATE(PLUS(x7, x6), 13)); + x5 = XOR(x5, ROTATE(PLUS(x4, x7), 18)); + x11 = XOR(x11, ROTATE(PLUS(x10, x9), 7)); + x8 = XOR(x8, ROTATE(PLUS(x11, x10), 9)); + x9 = XOR(x9, ROTATE(PLUS(x8, x11), 13)); + x10 = XOR(x10, ROTATE(PLUS(x9, x8), 18)); + x12 = XOR(x12, ROTATE(PLUS(x15, x14), 7)); + x13 = XOR(x13, ROTATE(PLUS(x12, x15), 9)); + x14 = XOR(x14, ROTATE(PLUS(x13, x12), 13)); + x15 = XOR(x15, ROTATE(PLUS(x14, x13), 18)); - // 2X round ------------------------------------------------------------- - x4 = XOR( x4,ROTATE(PLUS( x0,x12), 7)); - x8 = XOR( x8,ROTATE(PLUS( x4, x0), 9)); - x12 = XOR(x12,ROTATE(PLUS( x8, x4),13)); - x0 = XOR( x0,ROTATE(PLUS(x12, x8),18)); - x9 = XOR( x9,ROTATE(PLUS( x5, x1), 7)); - x13 = XOR(x13,ROTATE(PLUS( x9, x5), 9)); - x1 = XOR( x1,ROTATE(PLUS(x13, x9),13)); - x5 = XOR( x5,ROTATE(PLUS( x1,x13),18)); - x14 = XOR(x14,ROTATE(PLUS(x10, x6), 7)); - x2 = XOR( x2,ROTATE(PLUS(x14,x10), 9)); - x6 = XOR( x6,ROTATE(PLUS( x2,x14),13)); - x10 = XOR(x10,ROTATE(PLUS( x6, x2),18)); - x3 = XOR( x3,ROTATE(PLUS(x15,x11), 7)); - x7 = XOR( x7,ROTATE(PLUS( x3,x15), 9)); - x11 = XOR(x11,ROTATE(PLUS( x7, x3),13)); - x15 = XOR(x15,ROTATE(PLUS(x11, x7),18)); - x1 = XOR( x1,ROTATE(PLUS( x0, x3), 7)); - x2 = XOR( x2,ROTATE(PLUS( x1, x0), 9)); - x3 = XOR( x3,ROTATE(PLUS( x2, x1),13)); - x0 = XOR( x0,ROTATE(PLUS( x3, x2),18)); - x6 = XOR( x6,ROTATE(PLUS( x5, x4), 7)); - x7 = XOR( x7,ROTATE(PLUS( x6, x5), 9)); - x4 = XOR( x4,ROTATE(PLUS( x7, x6),13)); - x5 = XOR( x5,ROTATE(PLUS( x4, x7),18)); - x11 = XOR(x11,ROTATE(PLUS(x10, x9), 7)); - x8 = XOR( x8,ROTATE(PLUS(x11,x10), 9)); - x9 = XOR( x9,ROTATE(PLUS( x8,x11),13)); - x10 = XOR(x10,ROTATE(PLUS( x9, x8),18)); - x12 = XOR(x12,ROTATE(PLUS(x15,x14), 7)); - x13 = XOR(x13,ROTATE(PLUS(x12,x15), 9)); - x14 = XOR(x14,ROTATE(PLUS(x13,x12),13)); - x15 = XOR(x15,ROTATE(PLUS(x14,x13),18)); + // 2X round ------------------------------------------------------------- + x4 = XOR(x4, ROTATE(PLUS(x0, x12), 7)); + x8 = XOR(x8, ROTATE(PLUS(x4, x0), 9)); + x12 = XOR(x12, ROTATE(PLUS(x8, x4), 13)); + x0 = XOR(x0, ROTATE(PLUS(x12, x8), 18)); + x9 = XOR(x9, ROTATE(PLUS(x5, x1), 7)); + x13 = XOR(x13, ROTATE(PLUS(x9, x5), 9)); + x1 = XOR(x1, ROTATE(PLUS(x13, x9), 13)); + x5 = XOR(x5, ROTATE(PLUS(x1, x13), 18)); + x14 = XOR(x14, ROTATE(PLUS(x10, x6), 7)); + x2 = XOR(x2, ROTATE(PLUS(x14, x10), 9)); + x6 = XOR(x6, ROTATE(PLUS(x2, x14), 13)); + x10 = XOR(x10, ROTATE(PLUS(x6, x2), 18)); + x3 = XOR(x3, ROTATE(PLUS(x15, x11), 7)); + x7 = XOR(x7, ROTATE(PLUS(x3, x15), 9)); + x11 = XOR(x11, ROTATE(PLUS(x7, x3), 13)); + x15 = XOR(x15, ROTATE(PLUS(x11, x7), 18)); + x1 = XOR(x1, ROTATE(PLUS(x0, x3), 7)); + x2 = XOR(x2, ROTATE(PLUS(x1, x0), 9)); + x3 = XOR(x3, ROTATE(PLUS(x2, x1), 13)); + x0 = XOR(x0, ROTATE(PLUS(x3, x2), 18)); + x6 = XOR(x6, ROTATE(PLUS(x5, x4), 7)); + x7 = XOR(x7, ROTATE(PLUS(x6, x5), 9)); + x4 = XOR(x4, ROTATE(PLUS(x7, x6), 13)); + x5 = XOR(x5, ROTATE(PLUS(x4, x7), 18)); + x11 = XOR(x11, ROTATE(PLUS(x10, x9), 7)); + x8 = XOR(x8, ROTATE(PLUS(x11, x10), 9)); + x9 = XOR(x9, ROTATE(PLUS(x8, x11), 13)); + x10 = XOR(x10, ROTATE(PLUS(x9, x8), 18)); + x12 = XOR(x12, ROTATE(PLUS(x15, x14), 7)); + x13 = XOR(x13, ROTATE(PLUS(x12, x15), 9)); + x14 = XOR(x14, ROTATE(PLUS(x13, x12), 13)); + x15 = XOR(x15, ROTATE(PLUS(x14, x13), 18)); - // 2X round ------------------------------------------------------------- - x4 = XOR( x4,ROTATE(PLUS( x0,x12), 7)); - x8 = XOR( x8,ROTATE(PLUS( x4, x0), 9)); - x12 = XOR(x12,ROTATE(PLUS( x8, x4),13)); - x0 = XOR( x0,ROTATE(PLUS(x12, x8),18)); - x9 = XOR( x9,ROTATE(PLUS( x5, x1), 7)); - x13 = XOR(x13,ROTATE(PLUS( x9, x5), 9)); - x1 = XOR( x1,ROTATE(PLUS(x13, x9),13)); - x5 = XOR( x5,ROTATE(PLUS( x1,x13),18)); - x14 = XOR(x14,ROTATE(PLUS(x10, x6), 7)); - x2 = XOR( x2,ROTATE(PLUS(x14,x10), 9)); - x6 = XOR( x6,ROTATE(PLUS( x2,x14),13)); - x10 = XOR(x10,ROTATE(PLUS( x6, x2),18)); - x3 = XOR( x3,ROTATE(PLUS(x15,x11), 7)); - x7 = XOR( x7,ROTATE(PLUS( x3,x15), 9)); - x11 = XOR(x11,ROTATE(PLUS( x7, x3),13)); - x15 = XOR(x15,ROTATE(PLUS(x11, x7),18)); - x1 = XOR( x1,ROTATE(PLUS( x0, x3), 7)); - x2 = XOR( x2,ROTATE(PLUS( x1, x0), 9)); - x3 = XOR( x3,ROTATE(PLUS( x2, x1),13)); - x0 = XOR( x0,ROTATE(PLUS( x3, x2),18)); - x6 = XOR( x6,ROTATE(PLUS( x5, x4), 7)); - x7 = XOR( x7,ROTATE(PLUS( x6, x5), 9)); - x4 = XOR( x4,ROTATE(PLUS( x7, x6),13)); - x5 = XOR( x5,ROTATE(PLUS( x4, x7),18)); - x11 = XOR(x11,ROTATE(PLUS(x10, x9), 7)); - x8 = XOR( x8,ROTATE(PLUS(x11,x10), 9)); - x9 = XOR( x9,ROTATE(PLUS( x8,x11),13)); - x10 = XOR(x10,ROTATE(PLUS( x9, x8),18)); - x12 = XOR(x12,ROTATE(PLUS(x15,x14), 7)); - x13 = XOR(x13,ROTATE(PLUS(x12,x15), 9)); - x14 = XOR(x14,ROTATE(PLUS(x13,x12),13)); - x15 = XOR(x15,ROTATE(PLUS(x14,x13),18)); + // 2X round ------------------------------------------------------------- + x4 = XOR(x4, ROTATE(PLUS(x0, x12), 7)); + x8 = XOR(x8, ROTATE(PLUS(x4, x0), 9)); + x12 = XOR(x12, ROTATE(PLUS(x8, x4), 13)); + x0 = XOR(x0, ROTATE(PLUS(x12, x8), 18)); + x9 = XOR(x9, ROTATE(PLUS(x5, x1), 7)); + x13 = XOR(x13, ROTATE(PLUS(x9, x5), 9)); + x1 = XOR(x1, ROTATE(PLUS(x13, x9), 13)); + x5 = XOR(x5, ROTATE(PLUS(x1, x13), 18)); + x14 = XOR(x14, ROTATE(PLUS(x10, x6), 7)); + x2 = XOR(x2, ROTATE(PLUS(x14, x10), 9)); + x6 = XOR(x6, ROTATE(PLUS(x2, x14), 13)); + x10 = XOR(x10, ROTATE(PLUS(x6, x2), 18)); + x3 = XOR(x3, ROTATE(PLUS(x15, x11), 7)); + x7 = XOR(x7, ROTATE(PLUS(x3, x15), 9)); + x11 = XOR(x11, ROTATE(PLUS(x7, x3), 13)); + x15 = XOR(x15, ROTATE(PLUS(x11, x7), 18)); + x1 = XOR(x1, ROTATE(PLUS(x0, x3), 7)); + x2 = XOR(x2, ROTATE(PLUS(x1, x0), 9)); + x3 = XOR(x3, ROTATE(PLUS(x2, x1), 13)); + x0 = XOR(x0, ROTATE(PLUS(x3, x2), 18)); + x6 = XOR(x6, ROTATE(PLUS(x5, x4), 7)); + x7 = XOR(x7, ROTATE(PLUS(x6, x5), 9)); + x4 = XOR(x4, ROTATE(PLUS(x7, x6), 13)); + x5 = XOR(x5, ROTATE(PLUS(x4, x7), 18)); + x11 = XOR(x11, ROTATE(PLUS(x10, x9), 7)); + x8 = XOR(x8, ROTATE(PLUS(x11, x10), 9)); + x9 = XOR(x9, ROTATE(PLUS(x8, x11), 13)); + x10 = XOR(x10, ROTATE(PLUS(x9, x8), 18)); + x12 = XOR(x12, ROTATE(PLUS(x15, x14), 7)); + x13 = XOR(x13, ROTATE(PLUS(x12, x15), 9)); + x14 = XOR(x14, ROTATE(PLUS(x13, x12), 13)); + x15 = XOR(x15, ROTATE(PLUS(x14, x13), 18)); - // 2X round ------------------------------------------------------------- - x4 = XOR( x4,ROTATE(PLUS( x0,x12), 7)); - x8 = XOR( x8,ROTATE(PLUS( x4, x0), 9)); - x12 = XOR(x12,ROTATE(PLUS( x8, x4),13)); - x0 = XOR( x0,ROTATE(PLUS(x12, x8),18)); - x9 = XOR( x9,ROTATE(PLUS( x5, x1), 7)); - x13 = XOR(x13,ROTATE(PLUS( x9, x5), 9)); - x1 = XOR( x1,ROTATE(PLUS(x13, x9),13)); - x5 = XOR( x5,ROTATE(PLUS( x1,x13),18)); - x14 = XOR(x14,ROTATE(PLUS(x10, x6), 7)); - x2 = XOR( x2,ROTATE(PLUS(x14,x10), 9)); - x6 = XOR( x6,ROTATE(PLUS( x2,x14),13)); - x10 = XOR(x10,ROTATE(PLUS( x6, x2),18)); - x3 = XOR( x3,ROTATE(PLUS(x15,x11), 7)); - x7 = XOR( x7,ROTATE(PLUS( x3,x15), 9)); - x11 = XOR(x11,ROTATE(PLUS( x7, x3),13)); - x15 = XOR(x15,ROTATE(PLUS(x11, x7),18)); - x1 = XOR( x1,ROTATE(PLUS( x0, x3), 7)); - x2 = XOR( x2,ROTATE(PLUS( x1, x0), 9)); - x3 = XOR( x3,ROTATE(PLUS( x2, x1),13)); - x0 = XOR( x0,ROTATE(PLUS( x3, x2),18)); - x6 = XOR( x6,ROTATE(PLUS( x5, x4), 7)); - x7 = XOR( x7,ROTATE(PLUS( x6, x5), 9)); - x4 = XOR( x4,ROTATE(PLUS( x7, x6),13)); - x5 = XOR( x5,ROTATE(PLUS( x4, x7),18)); - x11 = XOR(x11,ROTATE(PLUS(x10, x9), 7)); - x8 = XOR( x8,ROTATE(PLUS(x11,x10), 9)); - x9 = XOR( x9,ROTATE(PLUS( x8,x11),13)); - x10 = XOR(x10,ROTATE(PLUS( x9, x8),18)); - x12 = XOR(x12,ROTATE(PLUS(x15,x14), 7)); - x13 = XOR(x13,ROTATE(PLUS(x12,x15), 9)); - x14 = XOR(x14,ROTATE(PLUS(x13,x12),13)); - x15 = XOR(x15,ROTATE(PLUS(x14,x13),18)); + // 2X round ------------------------------------------------------------- + x4 = XOR(x4, ROTATE(PLUS(x0, x12), 7)); + x8 = XOR(x8, ROTATE(PLUS(x4, x0), 9)); + x12 = XOR(x12, ROTATE(PLUS(x8, x4), 13)); + x0 = XOR(x0, ROTATE(PLUS(x12, x8), 18)); + x9 = XOR(x9, ROTATE(PLUS(x5, x1), 7)); + x13 = XOR(x13, ROTATE(PLUS(x9, x5), 9)); + x1 = XOR(x1, ROTATE(PLUS(x13, x9), 13)); + x5 = XOR(x5, ROTATE(PLUS(x1, x13), 18)); + x14 = XOR(x14, ROTATE(PLUS(x10, x6), 7)); + x2 = XOR(x2, ROTATE(PLUS(x14, x10), 9)); + x6 = XOR(x6, ROTATE(PLUS(x2, x14), 13)); + x10 = XOR(x10, ROTATE(PLUS(x6, x2), 18)); + x3 = XOR(x3, ROTATE(PLUS(x15, x11), 7)); + x7 = XOR(x7, ROTATE(PLUS(x3, x15), 9)); + x11 = XOR(x11, ROTATE(PLUS(x7, x3), 13)); + x15 = XOR(x15, ROTATE(PLUS(x11, x7), 18)); + x1 = XOR(x1, ROTATE(PLUS(x0, x3), 7)); + x2 = XOR(x2, ROTATE(PLUS(x1, x0), 9)); + x3 = XOR(x3, ROTATE(PLUS(x2, x1), 13)); + x0 = XOR(x0, ROTATE(PLUS(x3, x2), 18)); + x6 = XOR(x6, ROTATE(PLUS(x5, x4), 7)); + x7 = XOR(x7, ROTATE(PLUS(x6, x5), 9)); + x4 = XOR(x4, ROTATE(PLUS(x7, x6), 13)); + x5 = XOR(x5, ROTATE(PLUS(x4, x7), 18)); + x11 = XOR(x11, ROTATE(PLUS(x10, x9), 7)); + x8 = XOR(x8, ROTATE(PLUS(x11, x10), 9)); + x9 = XOR(x9, ROTATE(PLUS(x8, x11), 13)); + x10 = XOR(x10, ROTATE(PLUS(x9, x8), 18)); + x12 = XOR(x12, ROTATE(PLUS(x15, x14), 7)); + x13 = XOR(x13, ROTATE(PLUS(x12, x15), 9)); + x14 = XOR(x14, ROTATE(PLUS(x13, x12), 13)); + x15 = XOR(x15, ROTATE(PLUS(x14, x13), 18)); - // 2X round ------------------------------------------------------------- - x4 = XOR( x4,ROTATE(PLUS( x0,x12), 7)); - x8 = XOR( x8,ROTATE(PLUS( x4, x0), 9)); - x12 = XOR(x12,ROTATE(PLUS( x8, x4),13)); - x0 = XOR( x0,ROTATE(PLUS(x12, x8),18)); - x9 = XOR( x9,ROTATE(PLUS( x5, x1), 7)); - x13 = XOR(x13,ROTATE(PLUS( x9, x5), 9)); - x1 = XOR( x1,ROTATE(PLUS(x13, x9),13)); - x5 = XOR( x5,ROTATE(PLUS( x1,x13),18)); - x14 = XOR(x14,ROTATE(PLUS(x10, x6), 7)); - x2 = XOR( x2,ROTATE(PLUS(x14,x10), 9)); - x6 = XOR( x6,ROTATE(PLUS( x2,x14),13)); - x10 = XOR(x10,ROTATE(PLUS( x6, x2),18)); - x3 = XOR( x3,ROTATE(PLUS(x15,x11), 7)); - x7 = XOR( x7,ROTATE(PLUS( x3,x15), 9)); - x11 = XOR(x11,ROTATE(PLUS( x7, x3),13)); - x15 = XOR(x15,ROTATE(PLUS(x11, x7),18)); - x1 = XOR( x1,ROTATE(PLUS( x0, x3), 7)); - x2 = XOR( x2,ROTATE(PLUS( x1, x0), 9)); - x3 = XOR( x3,ROTATE(PLUS( x2, x1),13)); - x0 = XOR( x0,ROTATE(PLUS( x3, x2),18)); - x6 = XOR( x6,ROTATE(PLUS( x5, x4), 7)); - x7 = XOR( x7,ROTATE(PLUS( x6, x5), 9)); - x4 = XOR( x4,ROTATE(PLUS( x7, x6),13)); - x5 = XOR( x5,ROTATE(PLUS( x4, x7),18)); - x11 = XOR(x11,ROTATE(PLUS(x10, x9), 7)); - x8 = XOR( x8,ROTATE(PLUS(x11,x10), 9)); - x9 = XOR( x9,ROTATE(PLUS( x8,x11),13)); - x10 = XOR(x10,ROTATE(PLUS( x9, x8),18)); - x12 = XOR(x12,ROTATE(PLUS(x15,x14), 7)); - x13 = XOR(x13,ROTATE(PLUS(x12,x15), 9)); - x14 = XOR(x14,ROTATE(PLUS(x13,x12),13)); - x15 = XOR(x15,ROTATE(PLUS(x14,x13),18)); + // 2X round ------------------------------------------------------------- + x4 = XOR(x4, ROTATE(PLUS(x0, x12), 7)); + x8 = XOR(x8, ROTATE(PLUS(x4, x0), 9)); + x12 = XOR(x12, ROTATE(PLUS(x8, x4), 13)); + x0 = XOR(x0, ROTATE(PLUS(x12, x8), 18)); + x9 = XOR(x9, ROTATE(PLUS(x5, x1), 7)); + x13 = XOR(x13, ROTATE(PLUS(x9, x5), 9)); + x1 = XOR(x1, ROTATE(PLUS(x13, x9), 13)); + x5 = XOR(x5, ROTATE(PLUS(x1, x13), 18)); + x14 = XOR(x14, ROTATE(PLUS(x10, x6), 7)); + x2 = XOR(x2, ROTATE(PLUS(x14, x10), 9)); + x6 = XOR(x6, ROTATE(PLUS(x2, x14), 13)); + x10 = XOR(x10, ROTATE(PLUS(x6, x2), 18)); + x3 = XOR(x3, ROTATE(PLUS(x15, x11), 7)); + x7 = XOR(x7, ROTATE(PLUS(x3, x15), 9)); + x11 = XOR(x11, ROTATE(PLUS(x7, x3), 13)); + x15 = XOR(x15, ROTATE(PLUS(x11, x7), 18)); + x1 = XOR(x1, ROTATE(PLUS(x0, x3), 7)); + x2 = XOR(x2, ROTATE(PLUS(x1, x0), 9)); + x3 = XOR(x3, ROTATE(PLUS(x2, x1), 13)); + x0 = XOR(x0, ROTATE(PLUS(x3, x2), 18)); + x6 = XOR(x6, ROTATE(PLUS(x5, x4), 7)); + x7 = XOR(x7, ROTATE(PLUS(x6, x5), 9)); + x4 = XOR(x4, ROTATE(PLUS(x7, x6), 13)); + x5 = XOR(x5, ROTATE(PLUS(x4, x7), 18)); + x11 = XOR(x11, ROTATE(PLUS(x10, x9), 7)); + x8 = XOR(x8, ROTATE(PLUS(x11, x10), 9)); + x9 = XOR(x9, ROTATE(PLUS(x8, x11), 13)); + x10 = XOR(x10, ROTATE(PLUS(x9, x8), 18)); + x12 = XOR(x12, ROTATE(PLUS(x15, x14), 7)); + x13 = XOR(x13, ROTATE(PLUS(x12, x15), 9)); + x14 = XOR(x14, ROTATE(PLUS(x13, x12), 13)); + x15 = XOR(x15, ROTATE(PLUS(x14, x13), 18)); - // 2X round ------------------------------------------------------------- - x4 = XOR( x4,ROTATE(PLUS( x0,x12), 7)); - x8 = XOR( x8,ROTATE(PLUS( x4, x0), 9)); - x12 = XOR(x12,ROTATE(PLUS( x8, x4),13)); - x0 = XOR( x0,ROTATE(PLUS(x12, x8),18)); - x9 = XOR( x9,ROTATE(PLUS( x5, x1), 7)); - x13 = XOR(x13,ROTATE(PLUS( x9, x5), 9)); - x1 = XOR( x1,ROTATE(PLUS(x13, x9),13)); - x5 = XOR( x5,ROTATE(PLUS( x1,x13),18)); - x14 = XOR(x14,ROTATE(PLUS(x10, x6), 7)); - x2 = XOR( x2,ROTATE(PLUS(x14,x10), 9)); - x6 = XOR( x6,ROTATE(PLUS( x2,x14),13)); - x10 = XOR(x10,ROTATE(PLUS( x6, x2),18)); - x3 = XOR( x3,ROTATE(PLUS(x15,x11), 7)); - x7 = XOR( x7,ROTATE(PLUS( x3,x15), 9)); - x11 = XOR(x11,ROTATE(PLUS( x7, x3),13)); - x15 = XOR(x15,ROTATE(PLUS(x11, x7),18)); - x1 = XOR( x1,ROTATE(PLUS( x0, x3), 7)); - x2 = XOR( x2,ROTATE(PLUS( x1, x0), 9)); - x3 = XOR( x3,ROTATE(PLUS( x2, x1),13)); - x0 = XOR( x0,ROTATE(PLUS( x3, x2),18)); - x6 = XOR( x6,ROTATE(PLUS( x5, x4), 7)); - x7 = XOR( x7,ROTATE(PLUS( x6, x5), 9)); - x4 = XOR( x4,ROTATE(PLUS( x7, x6),13)); - x5 = XOR( x5,ROTATE(PLUS( x4, x7),18)); - x11 = XOR(x11,ROTATE(PLUS(x10, x9), 7)); - x8 = XOR( x8,ROTATE(PLUS(x11,x10), 9)); - x9 = XOR( x9,ROTATE(PLUS( x8,x11),13)); - x10 = XOR(x10,ROTATE(PLUS( x9, x8),18)); - x12 = XOR(x12,ROTATE(PLUS(x15,x14), 7)); - x13 = XOR(x13,ROTATE(PLUS(x12,x15), 9)); - x14 = XOR(x14,ROTATE(PLUS(x13,x12),13)); - x15 = XOR(x15,ROTATE(PLUS(x14,x13),18)); + // 2X round ------------------------------------------------------------- + x4 = XOR(x4, ROTATE(PLUS(x0, x12), 7)); + x8 = XOR(x8, ROTATE(PLUS(x4, x0), 9)); + x12 = XOR(x12, ROTATE(PLUS(x8, x4), 13)); + x0 = XOR(x0, ROTATE(PLUS(x12, x8), 18)); + x9 = XOR(x9, ROTATE(PLUS(x5, x1), 7)); + x13 = XOR(x13, ROTATE(PLUS(x9, x5), 9)); + x1 = XOR(x1, ROTATE(PLUS(x13, x9), 13)); + x5 = XOR(x5, ROTATE(PLUS(x1, x13), 18)); + x14 = XOR(x14, ROTATE(PLUS(x10, x6), 7)); + x2 = XOR(x2, ROTATE(PLUS(x14, x10), 9)); + x6 = XOR(x6, ROTATE(PLUS(x2, x14), 13)); + x10 = XOR(x10, ROTATE(PLUS(x6, x2), 18)); + x3 = XOR(x3, ROTATE(PLUS(x15, x11), 7)); + x7 = XOR(x7, ROTATE(PLUS(x3, x15), 9)); + x11 = XOR(x11, ROTATE(PLUS(x7, x3), 13)); + x15 = XOR(x15, ROTATE(PLUS(x11, x7), 18)); + x1 = XOR(x1, ROTATE(PLUS(x0, x3), 7)); + x2 = XOR(x2, ROTATE(PLUS(x1, x0), 9)); + x3 = XOR(x3, ROTATE(PLUS(x2, x1), 13)); + x0 = XOR(x0, ROTATE(PLUS(x3, x2), 18)); + x6 = XOR(x6, ROTATE(PLUS(x5, x4), 7)); + x7 = XOR(x7, ROTATE(PLUS(x6, x5), 9)); + x4 = XOR(x4, ROTATE(PLUS(x7, x6), 13)); + x5 = XOR(x5, ROTATE(PLUS(x4, x7), 18)); + x11 = XOR(x11, ROTATE(PLUS(x10, x9), 7)); + x8 = XOR(x8, ROTATE(PLUS(x11, x10), 9)); + x9 = XOR(x9, ROTATE(PLUS(x8, x11), 13)); + x10 = XOR(x10, ROTATE(PLUS(x9, x8), 18)); + x12 = XOR(x12, ROTATE(PLUS(x15, x14), 7)); + x13 = XOR(x13, ROTATE(PLUS(x12, x15), 9)); + x14 = XOR(x14, ROTATE(PLUS(x13, x12), 13)); + x15 = XOR(x15, ROTATE(PLUS(x14, x13), 18)); - // 2X round ------------------------------------------------------------- - x4 = XOR( x4,ROTATE(PLUS( x0,x12), 7)); - x8 = XOR( x8,ROTATE(PLUS( x4, x0), 9)); - x12 = XOR(x12,ROTATE(PLUS( x8, x4),13)); - x0 = XOR( x0,ROTATE(PLUS(x12, x8),18)); - x9 = XOR( x9,ROTATE(PLUS( x5, x1), 7)); - x13 = XOR(x13,ROTATE(PLUS( x9, x5), 9)); - x1 = XOR( x1,ROTATE(PLUS(x13, x9),13)); - x5 = XOR( x5,ROTATE(PLUS( x1,x13),18)); - x14 = XOR(x14,ROTATE(PLUS(x10, x6), 7)); - x2 = XOR( x2,ROTATE(PLUS(x14,x10), 9)); - x6 = XOR( x6,ROTATE(PLUS( x2,x14),13)); - x10 = XOR(x10,ROTATE(PLUS( x6, x2),18)); - x3 = XOR( x3,ROTATE(PLUS(x15,x11), 7)); - x7 = XOR( x7,ROTATE(PLUS( x3,x15), 9)); - x11 = XOR(x11,ROTATE(PLUS( x7, x3),13)); - x15 = XOR(x15,ROTATE(PLUS(x11, x7),18)); - x1 = XOR( x1,ROTATE(PLUS( x0, x3), 7)); - x2 = XOR( x2,ROTATE(PLUS( x1, x0), 9)); - x3 = XOR( x3,ROTATE(PLUS( x2, x1),13)); - x0 = XOR( x0,ROTATE(PLUS( x3, x2),18)); - x6 = XOR( x6,ROTATE(PLUS( x5, x4), 7)); - x7 = XOR( x7,ROTATE(PLUS( x6, x5), 9)); - x4 = XOR( x4,ROTATE(PLUS( x7, x6),13)); - x5 = XOR( x5,ROTATE(PLUS( x4, x7),18)); - x11 = XOR(x11,ROTATE(PLUS(x10, x9), 7)); - x8 = XOR( x8,ROTATE(PLUS(x11,x10), 9)); - x9 = XOR( x9,ROTATE(PLUS( x8,x11),13)); - x10 = XOR(x10,ROTATE(PLUS( x9, x8),18)); - x12 = XOR(x12,ROTATE(PLUS(x15,x14), 7)); - x13 = XOR(x13,ROTATE(PLUS(x12,x15), 9)); - x14 = XOR(x14,ROTATE(PLUS(x13,x12),13)); - x15 = XOR(x15,ROTATE(PLUS(x14,x13),18)); + // 2X round ------------------------------------------------------------- + x4 = XOR(x4, ROTATE(PLUS(x0, x12), 7)); + x8 = XOR(x8, ROTATE(PLUS(x4, x0), 9)); + x12 = XOR(x12, ROTATE(PLUS(x8, x4), 13)); + x0 = XOR(x0, ROTATE(PLUS(x12, x8), 18)); + x9 = XOR(x9, ROTATE(PLUS(x5, x1), 7)); + x13 = XOR(x13, ROTATE(PLUS(x9, x5), 9)); + x1 = XOR(x1, ROTATE(PLUS(x13, x9), 13)); + x5 = XOR(x5, ROTATE(PLUS(x1, x13), 18)); + x14 = XOR(x14, ROTATE(PLUS(x10, x6), 7)); + x2 = XOR(x2, ROTATE(PLUS(x14, x10), 9)); + x6 = XOR(x6, ROTATE(PLUS(x2, x14), 13)); + x10 = XOR(x10, ROTATE(PLUS(x6, x2), 18)); + x3 = XOR(x3, ROTATE(PLUS(x15, x11), 7)); + x7 = XOR(x7, ROTATE(PLUS(x3, x15), 9)); + x11 = XOR(x11, ROTATE(PLUS(x7, x3), 13)); + x15 = XOR(x15, ROTATE(PLUS(x11, x7), 18)); + x1 = XOR(x1, ROTATE(PLUS(x0, x3), 7)); + x2 = XOR(x2, ROTATE(PLUS(x1, x0), 9)); + x3 = XOR(x3, ROTATE(PLUS(x2, x1), 13)); + x0 = XOR(x0, ROTATE(PLUS(x3, x2), 18)); + x6 = XOR(x6, ROTATE(PLUS(x5, x4), 7)); + x7 = XOR(x7, ROTATE(PLUS(x6, x5), 9)); + x4 = XOR(x4, ROTATE(PLUS(x7, x6), 13)); + x5 = XOR(x5, ROTATE(PLUS(x4, x7), 18)); + x11 = XOR(x11, ROTATE(PLUS(x10, x9), 7)); + x8 = XOR(x8, ROTATE(PLUS(x11, x10), 9)); + x9 = XOR(x9, ROTATE(PLUS(x8, x11), 13)); + x10 = XOR(x10, ROTATE(PLUS(x9, x8), 18)); + x12 = XOR(x12, ROTATE(PLUS(x15, x14), 7)); + x13 = XOR(x13, ROTATE(PLUS(x12, x15), 9)); + x14 = XOR(x14, ROTATE(PLUS(x13, x12), 13)); + x15 = XOR(x15, ROTATE(PLUS(x14, x13), 18)); - // 2X round ------------------------------------------------------------- - x4 = XOR( x4,ROTATE(PLUS( x0,x12), 7)); - x8 = XOR( x8,ROTATE(PLUS( x4, x0), 9)); - x12 = XOR(x12,ROTATE(PLUS( x8, x4),13)); - x0 = XOR( x0,ROTATE(PLUS(x12, x8),18)); - x9 = XOR( x9,ROTATE(PLUS( x5, x1), 7)); - x13 = XOR(x13,ROTATE(PLUS( x9, x5), 9)); - x1 = XOR( x1,ROTATE(PLUS(x13, x9),13)); - x5 = XOR( x5,ROTATE(PLUS( x1,x13),18)); - x14 = XOR(x14,ROTATE(PLUS(x10, x6), 7)); - x2 = XOR( x2,ROTATE(PLUS(x14,x10), 9)); - x6 = XOR( x6,ROTATE(PLUS( x2,x14),13)); - x10 = XOR(x10,ROTATE(PLUS( x6, x2),18)); - x3 = XOR( x3,ROTATE(PLUS(x15,x11), 7)); - x7 = XOR( x7,ROTATE(PLUS( x3,x15), 9)); - x11 = XOR(x11,ROTATE(PLUS( x7, x3),13)); - x15 = XOR(x15,ROTATE(PLUS(x11, x7),18)); - x1 = XOR( x1,ROTATE(PLUS( x0, x3), 7)); - x2 = XOR( x2,ROTATE(PLUS( x1, x0), 9)); - x3 = XOR( x3,ROTATE(PLUS( x2, x1),13)); - x0 = XOR( x0,ROTATE(PLUS( x3, x2),18)); - x6 = XOR( x6,ROTATE(PLUS( x5, x4), 7)); - x7 = XOR( x7,ROTATE(PLUS( x6, x5), 9)); - x4 = XOR( x4,ROTATE(PLUS( x7, x6),13)); - x5 = XOR( x5,ROTATE(PLUS( x4, x7),18)); - x11 = XOR(x11,ROTATE(PLUS(x10, x9), 7)); - x8 = XOR( x8,ROTATE(PLUS(x11,x10), 9)); - x9 = XOR( x9,ROTATE(PLUS( x8,x11),13)); - x10 = XOR(x10,ROTATE(PLUS( x9, x8),18)); - x12 = XOR(x12,ROTATE(PLUS(x15,x14), 7)); - x13 = XOR(x13,ROTATE(PLUS(x12,x15), 9)); - x14 = XOR(x14,ROTATE(PLUS(x13,x12),13)); - x15 = XOR(x15,ROTATE(PLUS(x14,x13),18)); + // 2X round ------------------------------------------------------------- + x4 = XOR(x4, ROTATE(PLUS(x0, x12), 7)); + x8 = XOR(x8, ROTATE(PLUS(x4, x0), 9)); + x12 = XOR(x12, ROTATE(PLUS(x8, x4), 13)); + x0 = XOR(x0, ROTATE(PLUS(x12, x8), 18)); + x9 = XOR(x9, ROTATE(PLUS(x5, x1), 7)); + x13 = XOR(x13, ROTATE(PLUS(x9, x5), 9)); + x1 = XOR(x1, ROTATE(PLUS(x13, x9), 13)); + x5 = XOR(x5, ROTATE(PLUS(x1, x13), 18)); + x14 = XOR(x14, ROTATE(PLUS(x10, x6), 7)); + x2 = XOR(x2, ROTATE(PLUS(x14, x10), 9)); + x6 = XOR(x6, ROTATE(PLUS(x2, x14), 13)); + x10 = XOR(x10, ROTATE(PLUS(x6, x2), 18)); + x3 = XOR(x3, ROTATE(PLUS(x15, x11), 7)); + x7 = XOR(x7, ROTATE(PLUS(x3, x15), 9)); + x11 = XOR(x11, ROTATE(PLUS(x7, x3), 13)); + x15 = XOR(x15, ROTATE(PLUS(x11, x7), 18)); + x1 = XOR(x1, ROTATE(PLUS(x0, x3), 7)); + x2 = XOR(x2, ROTATE(PLUS(x1, x0), 9)); + x3 = XOR(x3, ROTATE(PLUS(x2, x1), 13)); + x0 = XOR(x0, ROTATE(PLUS(x3, x2), 18)); + x6 = XOR(x6, ROTATE(PLUS(x5, x4), 7)); + x7 = XOR(x7, ROTATE(PLUS(x6, x5), 9)); + x4 = XOR(x4, ROTATE(PLUS(x7, x6), 13)); + x5 = XOR(x5, ROTATE(PLUS(x4, x7), 18)); + x11 = XOR(x11, ROTATE(PLUS(x10, x9), 7)); + x8 = XOR(x8, ROTATE(PLUS(x11, x10), 9)); + x9 = XOR(x9, ROTATE(PLUS(x8, x11), 13)); + x10 = XOR(x10, ROTATE(PLUS(x9, x8), 18)); + x12 = XOR(x12, ROTATE(PLUS(x15, x14), 7)); + x13 = XOR(x13, ROTATE(PLUS(x12, x15), 9)); + x14 = XOR(x14, ROTATE(PLUS(x13, x12), 13)); + x15 = XOR(x15, ROTATE(PLUS(x14, x13), 18)); - // 2X round ------------------------------------------------------------- - x4 = XOR( x4,ROTATE(PLUS( x0,x12), 7)); - x8 = XOR( x8,ROTATE(PLUS( x4, x0), 9)); - x12 = XOR(x12,ROTATE(PLUS( x8, x4),13)); - x0 = XOR( x0,ROTATE(PLUS(x12, x8),18)); - x9 = XOR( x9,ROTATE(PLUS( x5, x1), 7)); - x13 = XOR(x13,ROTATE(PLUS( x9, x5), 9)); - x1 = XOR( x1,ROTATE(PLUS(x13, x9),13)); - x5 = XOR( x5,ROTATE(PLUS( x1,x13),18)); - x14 = XOR(x14,ROTATE(PLUS(x10, x6), 7)); - x2 = XOR( x2,ROTATE(PLUS(x14,x10), 9)); - x6 = XOR( x6,ROTATE(PLUS( x2,x14),13)); - x10 = XOR(x10,ROTATE(PLUS( x6, x2),18)); - x3 = XOR( x3,ROTATE(PLUS(x15,x11), 7)); - x7 = XOR( x7,ROTATE(PLUS( x3,x15), 9)); - x11 = XOR(x11,ROTATE(PLUS( x7, x3),13)); - x15 = XOR(x15,ROTATE(PLUS(x11, x7),18)); - x1 = XOR( x1,ROTATE(PLUS( x0, x3), 7)); - x2 = XOR( x2,ROTATE(PLUS( x1, x0), 9)); - x3 = XOR( x3,ROTATE(PLUS( x2, x1),13)); - x0 = XOR( x0,ROTATE(PLUS( x3, x2),18)); - x6 = XOR( x6,ROTATE(PLUS( x5, x4), 7)); - x7 = XOR( x7,ROTATE(PLUS( x6, x5), 9)); - x4 = XOR( x4,ROTATE(PLUS( x7, x6),13)); - x5 = XOR( x5,ROTATE(PLUS( x4, x7),18)); - x11 = XOR(x11,ROTATE(PLUS(x10, x9), 7)); - x8 = XOR( x8,ROTATE(PLUS(x11,x10), 9)); - x9 = XOR( x9,ROTATE(PLUS( x8,x11),13)); - x10 = XOR(x10,ROTATE(PLUS( x9, x8),18)); - x12 = XOR(x12,ROTATE(PLUS(x15,x14), 7)); - x13 = XOR(x13,ROTATE(PLUS(x12,x15), 9)); - x14 = XOR(x14,ROTATE(PLUS(x13,x12),13)); - x15 = XOR(x15,ROTATE(PLUS(x14,x13),18)); + // 2X round ------------------------------------------------------------- + x4 = XOR(x4, ROTATE(PLUS(x0, x12), 7)); + x8 = XOR(x8, ROTATE(PLUS(x4, x0), 9)); + x12 = XOR(x12, ROTATE(PLUS(x8, x4), 13)); + x0 = XOR(x0, ROTATE(PLUS(x12, x8), 18)); + x9 = XOR(x9, ROTATE(PLUS(x5, x1), 7)); + x13 = XOR(x13, ROTATE(PLUS(x9, x5), 9)); + x1 = XOR(x1, ROTATE(PLUS(x13, x9), 13)); + x5 = XOR(x5, ROTATE(PLUS(x1, x13), 18)); + x14 = XOR(x14, ROTATE(PLUS(x10, x6), 7)); + x2 = XOR(x2, ROTATE(PLUS(x14, x10), 9)); + x6 = XOR(x6, ROTATE(PLUS(x2, x14), 13)); + x10 = XOR(x10, ROTATE(PLUS(x6, x2), 18)); + x3 = XOR(x3, ROTATE(PLUS(x15, x11), 7)); + x7 = XOR(x7, ROTATE(PLUS(x3, x15), 9)); + x11 = XOR(x11, ROTATE(PLUS(x7, x3), 13)); + x15 = XOR(x15, ROTATE(PLUS(x11, x7), 18)); + x1 = XOR(x1, ROTATE(PLUS(x0, x3), 7)); + x2 = XOR(x2, ROTATE(PLUS(x1, x0), 9)); + x3 = XOR(x3, ROTATE(PLUS(x2, x1), 13)); + x0 = XOR(x0, ROTATE(PLUS(x3, x2), 18)); + x6 = XOR(x6, ROTATE(PLUS(x5, x4), 7)); + x7 = XOR(x7, ROTATE(PLUS(x6, x5), 9)); + x4 = XOR(x4, ROTATE(PLUS(x7, x6), 13)); + x5 = XOR(x5, ROTATE(PLUS(x4, x7), 18)); + x11 = XOR(x11, ROTATE(PLUS(x10, x9), 7)); + x8 = XOR(x8, ROTATE(PLUS(x11, x10), 9)); + x9 = XOR(x9, ROTATE(PLUS(x8, x11), 13)); + x10 = XOR(x10, ROTATE(PLUS(x9, x8), 18)); + x12 = XOR(x12, ROTATE(PLUS(x15, x14), 7)); + x13 = XOR(x13, ROTATE(PLUS(x12, x15), 9)); + x14 = XOR(x14, ROTATE(PLUS(x13, x12), 13)); + x15 = XOR(x15, ROTATE(PLUS(x14, x13), 18)); - // 2X round ------------------------------------------------------------- - x4 = XOR( x4,ROTATE(PLUS( x0,x12), 7)); - x8 = XOR( x8,ROTATE(PLUS( x4, x0), 9)); - x12 = XOR(x12,ROTATE(PLUS( x8, x4),13)); - x0 = XOR( x0,ROTATE(PLUS(x12, x8),18)); - x9 = XOR( x9,ROTATE(PLUS( x5, x1), 7)); - x13 = XOR(x13,ROTATE(PLUS( x9, x5), 9)); - x1 = XOR( x1,ROTATE(PLUS(x13, x9),13)); - x5 = XOR( x5,ROTATE(PLUS( x1,x13),18)); - x14 = XOR(x14,ROTATE(PLUS(x10, x6), 7)); - x2 = XOR( x2,ROTATE(PLUS(x14,x10), 9)); - x6 = XOR( x6,ROTATE(PLUS( x2,x14),13)); - x10 = XOR(x10,ROTATE(PLUS( x6, x2),18)); - x3 = XOR( x3,ROTATE(PLUS(x15,x11), 7)); - x7 = XOR( x7,ROTATE(PLUS( x3,x15), 9)); - x11 = XOR(x11,ROTATE(PLUS( x7, x3),13)); - x15 = XOR(x15,ROTATE(PLUS(x11, x7),18)); - x1 = XOR( x1,ROTATE(PLUS( x0, x3), 7)); - x2 = XOR( x2,ROTATE(PLUS( x1, x0), 9)); - x3 = XOR( x3,ROTATE(PLUS( x2, x1),13)); - x0 = XOR( x0,ROTATE(PLUS( x3, x2),18)); - x6 = XOR( x6,ROTATE(PLUS( x5, x4), 7)); - x7 = XOR( x7,ROTATE(PLUS( x6, x5), 9)); - x4 = XOR( x4,ROTATE(PLUS( x7, x6),13)); - x5 = XOR( x5,ROTATE(PLUS( x4, x7),18)); - x11 = XOR(x11,ROTATE(PLUS(x10, x9), 7)); - x8 = XOR( x8,ROTATE(PLUS(x11,x10), 9)); - x9 = XOR( x9,ROTATE(PLUS( x8,x11),13)); - x10 = XOR(x10,ROTATE(PLUS( x9, x8),18)); - x12 = XOR(x12,ROTATE(PLUS(x15,x14), 7)); - x13 = XOR(x13,ROTATE(PLUS(x12,x15), 9)); - x14 = XOR(x14,ROTATE(PLUS(x13,x12),13)); - x15 = XOR(x15,ROTATE(PLUS(x14,x13),18)); + // 2X round ------------------------------------------------------------- + x4 = XOR(x4, ROTATE(PLUS(x0, x12), 7)); + x8 = XOR(x8, ROTATE(PLUS(x4, x0), 9)); + x12 = XOR(x12, ROTATE(PLUS(x8, x4), 13)); + x0 = XOR(x0, ROTATE(PLUS(x12, x8), 18)); + x9 = XOR(x9, ROTATE(PLUS(x5, x1), 7)); + x13 = XOR(x13, ROTATE(PLUS(x9, x5), 9)); + x1 = XOR(x1, ROTATE(PLUS(x13, x9), 13)); + x5 = XOR(x5, ROTATE(PLUS(x1, x13), 18)); + x14 = XOR(x14, ROTATE(PLUS(x10, x6), 7)); + x2 = XOR(x2, ROTATE(PLUS(x14, x10), 9)); + x6 = XOR(x6, ROTATE(PLUS(x2, x14), 13)); + x10 = XOR(x10, ROTATE(PLUS(x6, x2), 18)); + x3 = XOR(x3, ROTATE(PLUS(x15, x11), 7)); + x7 = XOR(x7, ROTATE(PLUS(x3, x15), 9)); + x11 = XOR(x11, ROTATE(PLUS(x7, x3), 13)); + x15 = XOR(x15, ROTATE(PLUS(x11, x7), 18)); + x1 = XOR(x1, ROTATE(PLUS(x0, x3), 7)); + x2 = XOR(x2, ROTATE(PLUS(x1, x0), 9)); + x3 = XOR(x3, ROTATE(PLUS(x2, x1), 13)); + x0 = XOR(x0, ROTATE(PLUS(x3, x2), 18)); + x6 = XOR(x6, ROTATE(PLUS(x5, x4), 7)); + x7 = XOR(x7, ROTATE(PLUS(x6, x5), 9)); + x4 = XOR(x4, ROTATE(PLUS(x7, x6), 13)); + x5 = XOR(x5, ROTATE(PLUS(x4, x7), 18)); + x11 = XOR(x11, ROTATE(PLUS(x10, x9), 7)); + x8 = XOR(x8, ROTATE(PLUS(x11, x10), 9)); + x9 = XOR(x9, ROTATE(PLUS(x8, x11), 13)); + x10 = XOR(x10, ROTATE(PLUS(x9, x8), 18)); + x12 = XOR(x12, ROTATE(PLUS(x15, x14), 7)); + x13 = XOR(x13, ROTATE(PLUS(x12, x15), 9)); + x14 = XOR(x14, ROTATE(PLUS(x13, x12), 13)); + x15 = XOR(x15, ROTATE(PLUS(x14, x13), 18)); - x0 = PLUS(x0,j0); - x1 = PLUS(x1,j1); - x2 = PLUS(x2,j2); - x3 = PLUS(x3,j3); - x4 = PLUS(x4,j4); - x5 = PLUS(x5,j5); - x6 = PLUS(x6,j6); - x7 = PLUS(x7,j7); - x8 = PLUS(x8,j8); - x9 = PLUS(x9,j9); - x10 = PLUS(x10,j10); - x11 = PLUS(x11,j11); - x12 = PLUS(x12,j12); - x13 = PLUS(x13,j13); - x14 = PLUS(x14,j14); - x15 = PLUS(x15,j15); + x0 = PLUS(x0, j0); + x1 = PLUS(x1, j1); + x2 = PLUS(x2, j2); + x3 = PLUS(x3, j3); + x4 = PLUS(x4, j4); + x5 = PLUS(x5, j5); + x6 = PLUS(x6, j6); + x7 = PLUS(x7, j7); + x8 = PLUS(x8, j8); + x9 = PLUS(x9, j9); + x10 = PLUS(x10, j10); + x11 = PLUS(x11, j11); + x12 = PLUS(x12, j12); + x13 = PLUS(x13, j13); + x14 = PLUS(x14, j14); + x15 = PLUS(x15, j15); - U32TO8_LITTLE(c + 0,XOR(x0,U8TO32_LITTLE(m + 0))); - U32TO8_LITTLE(c + 4,XOR(x1,U8TO32_LITTLE(m + 4))); - U32TO8_LITTLE(c + 8,XOR(x2,U8TO32_LITTLE(m + 8))); - U32TO8_LITTLE(c + 12,XOR(x3,U8TO32_LITTLE(m + 12))); - U32TO8_LITTLE(c + 16,XOR(x4,U8TO32_LITTLE(m + 16))); - U32TO8_LITTLE(c + 20,XOR(x5,U8TO32_LITTLE(m + 20))); - U32TO8_LITTLE(c + 24,XOR(x6,U8TO32_LITTLE(m + 24))); - U32TO8_LITTLE(c + 28,XOR(x7,U8TO32_LITTLE(m + 28))); - U32TO8_LITTLE(c + 32,XOR(x8,U8TO32_LITTLE(m + 32))); - U32TO8_LITTLE(c + 36,XOR(x9,U8TO32_LITTLE(m + 36))); - U32TO8_LITTLE(c + 40,XOR(x10,U8TO32_LITTLE(m + 40))); - U32TO8_LITTLE(c + 44,XOR(x11,U8TO32_LITTLE(m + 44))); - U32TO8_LITTLE(c + 48,XOR(x12,U8TO32_LITTLE(m + 48))); - U32TO8_LITTLE(c + 52,XOR(x13,U8TO32_LITTLE(m + 52))); - U32TO8_LITTLE(c + 56,XOR(x14,U8TO32_LITTLE(m + 56))); - U32TO8_LITTLE(c + 60,XOR(x15,U8TO32_LITTLE(m + 60))); + U32TO8_LITTLE(c + 0, XOR(x0, U8TO32_LITTLE(m + 0))); + U32TO8_LITTLE(c + 4, XOR(x1, U8TO32_LITTLE(m + 4))); + U32TO8_LITTLE(c + 8, XOR(x2, U8TO32_LITTLE(m + 8))); + U32TO8_LITTLE(c + 12, XOR(x3, U8TO32_LITTLE(m + 12))); + U32TO8_LITTLE(c + 16, XOR(x4, U8TO32_LITTLE(m + 16))); + U32TO8_LITTLE(c + 20, XOR(x5, U8TO32_LITTLE(m + 20))); + U32TO8_LITTLE(c + 24, XOR(x6, U8TO32_LITTLE(m + 24))); + U32TO8_LITTLE(c + 28, XOR(x7, U8TO32_LITTLE(m + 28))); + U32TO8_LITTLE(c + 32, XOR(x8, U8TO32_LITTLE(m + 32))); + U32TO8_LITTLE(c + 36, XOR(x9, U8TO32_LITTLE(m + 36))); + U32TO8_LITTLE(c + 40, XOR(x10, U8TO32_LITTLE(m + 40))); + U32TO8_LITTLE(c + 44, XOR(x11, U8TO32_LITTLE(m + 44))); + U32TO8_LITTLE(c + 48, XOR(x12, U8TO32_LITTLE(m + 48))); + U32TO8_LITTLE(c + 52, XOR(x13, U8TO32_LITTLE(m + 52))); + U32TO8_LITTLE(c + 56, XOR(x14, U8TO32_LITTLE(m + 56))); + U32TO8_LITTLE(c + 60, XOR(x15, U8TO32_LITTLE(m + 60))); - if (!(++j8)) { - ++j9; - /* stopping at 2^70 bytes per nonce is user's responsibility */ - } + if (! (++j8)) { + ++j9; + /* stopping at 2^70 bytes per nonce is user's responsibility */ + } #endif - if (bytes <= 64) { - if (bytes < 64) { - for (i = 0;i < bytes;++i) { - ctarget[i] = c[i]; - } - } + if (bytes <= 64) { + if (bytes < 64) { + for (i = 0; i < bytes; ++i) { + ctarget[i] = c[i]; + } + } #ifndef ZT_SALSA20_SSE - _state.i[8] = j8; - _state.i[9] = j9; + _state.i[8] = j8; + _state.i[9] = j9; #endif - return; - } + return; + } - bytes -= 64; - c += 64; - m += 64; - } + bytes -= 64; + c += 64; + m += 64; + } } -} // namespace ZeroTier +} // namespace ZeroTier diff --git a/node/Salsa20.hpp b/node/Salsa20.hpp index 89355386..9ecc9960 100644 --- a/node/Salsa20.hpp +++ b/node/Salsa20.hpp @@ -7,153 +7,157 @@ #ifndef ZT_SALSA20_HPP #define ZT_SALSA20_HPP -#include -#include -#include -#include - #include "Constants.hpp" #include "Utils.hpp" -#if (!defined(ZT_SALSA20_SSE)) && (defined(__SSE2__) || (defined(__WINDOWS__) && !defined(__MINGW32__) && !defined(_M_ARM64))) +#include +#include +#include +#include + +#if (! defined(ZT_SALSA20_SSE)) && (defined(__SSE2__) || (defined(__WINDOWS__) && ! defined(__MINGW32__) && ! defined(_M_ARM64))) #define ZT_SALSA20_SSE 1 #endif #ifdef ZT_SALSA20_SSE #include -#endif // ZT_SALSA20_SSE +#endif // ZT_SALSA20_SSE namespace ZeroTier { /** * Salsa20 stream cipher */ -class Salsa20 -{ -public: - Salsa20() {} - ~Salsa20() { Utils::burn(&_state,sizeof(_state)); } +class Salsa20 { + public: + Salsa20() + { + } + ~Salsa20() + { + Utils::burn(&_state, sizeof(_state)); + } - /** - * XOR d with s - * - * This is done efficiently using e.g. SSE if available. It's used when - * alternative Salsa20 implementations are used in Packet and is here - * since this is where all the SSE stuff is already included. - * - * @param d Destination to XOR - * @param s Source bytes to XOR with destination - * @param len Length of s and d - */ - static inline void memxor(uint8_t *d,const uint8_t *s,unsigned int len) - { + /** + * XOR d with s + * + * This is done efficiently using e.g. SSE if available. It's used when + * alternative Salsa20 implementations are used in Packet and is here + * since this is where all the SSE stuff is already included. + * + * @param d Destination to XOR + * @param s Source bytes to XOR with destination + * @param len Length of s and d + */ + static inline void memxor(uint8_t* d, const uint8_t* s, unsigned int len) + { #ifdef ZT_SALSA20_SSE - while (len >= 128) { - __m128i s0 = _mm_loadu_si128(reinterpret_cast(s)); - __m128i s1 = _mm_loadu_si128(reinterpret_cast(s + 16)); - __m128i s2 = _mm_loadu_si128(reinterpret_cast(s + 32)); - __m128i s3 = _mm_loadu_si128(reinterpret_cast(s + 48)); - __m128i s4 = _mm_loadu_si128(reinterpret_cast(s + 64)); - __m128i s5 = _mm_loadu_si128(reinterpret_cast(s + 80)); - __m128i s6 = _mm_loadu_si128(reinterpret_cast(s + 96)); - __m128i s7 = _mm_loadu_si128(reinterpret_cast(s + 112)); - __m128i d0 = _mm_loadu_si128(reinterpret_cast<__m128i *>(d)); - __m128i d1 = _mm_loadu_si128(reinterpret_cast<__m128i *>(d + 16)); - __m128i d2 = _mm_loadu_si128(reinterpret_cast<__m128i *>(d + 32)); - __m128i d3 = _mm_loadu_si128(reinterpret_cast<__m128i *>(d + 48)); - __m128i d4 = _mm_loadu_si128(reinterpret_cast<__m128i *>(d + 64)); - __m128i d5 = _mm_loadu_si128(reinterpret_cast<__m128i *>(d + 80)); - __m128i d6 = _mm_loadu_si128(reinterpret_cast<__m128i *>(d + 96)); - __m128i d7 = _mm_loadu_si128(reinterpret_cast<__m128i *>(d + 112)); - d0 = _mm_xor_si128(d0,s0); - d1 = _mm_xor_si128(d1,s1); - d2 = _mm_xor_si128(d2,s2); - d3 = _mm_xor_si128(d3,s3); - d4 = _mm_xor_si128(d4,s4); - d5 = _mm_xor_si128(d5,s5); - d6 = _mm_xor_si128(d6,s6); - d7 = _mm_xor_si128(d7,s7); - _mm_storeu_si128(reinterpret_cast<__m128i *>(d),d0); - _mm_storeu_si128(reinterpret_cast<__m128i *>(d + 16),d1); - _mm_storeu_si128(reinterpret_cast<__m128i *>(d + 32),d2); - _mm_storeu_si128(reinterpret_cast<__m128i *>(d + 48),d3); - _mm_storeu_si128(reinterpret_cast<__m128i *>(d + 64),d4); - _mm_storeu_si128(reinterpret_cast<__m128i *>(d + 80),d5); - _mm_storeu_si128(reinterpret_cast<__m128i *>(d + 96),d6); - _mm_storeu_si128(reinterpret_cast<__m128i *>(d + 112),d7); - s += 128; - d += 128; - len -= 128; - } - while (len >= 16) { - _mm_storeu_si128(reinterpret_cast<__m128i *>(d),_mm_xor_si128(_mm_loadu_si128(reinterpret_cast<__m128i *>(d)),_mm_loadu_si128(reinterpret_cast(s)))); - s += 16; - d += 16; - len -= 16; - } + while (len >= 128) { + __m128i s0 = _mm_loadu_si128(reinterpret_cast(s)); + __m128i s1 = _mm_loadu_si128(reinterpret_cast(s + 16)); + __m128i s2 = _mm_loadu_si128(reinterpret_cast(s + 32)); + __m128i s3 = _mm_loadu_si128(reinterpret_cast(s + 48)); + __m128i s4 = _mm_loadu_si128(reinterpret_cast(s + 64)); + __m128i s5 = _mm_loadu_si128(reinterpret_cast(s + 80)); + __m128i s6 = _mm_loadu_si128(reinterpret_cast(s + 96)); + __m128i s7 = _mm_loadu_si128(reinterpret_cast(s + 112)); + __m128i d0 = _mm_loadu_si128(reinterpret_cast<__m128i*>(d)); + __m128i d1 = _mm_loadu_si128(reinterpret_cast<__m128i*>(d + 16)); + __m128i d2 = _mm_loadu_si128(reinterpret_cast<__m128i*>(d + 32)); + __m128i d3 = _mm_loadu_si128(reinterpret_cast<__m128i*>(d + 48)); + __m128i d4 = _mm_loadu_si128(reinterpret_cast<__m128i*>(d + 64)); + __m128i d5 = _mm_loadu_si128(reinterpret_cast<__m128i*>(d + 80)); + __m128i d6 = _mm_loadu_si128(reinterpret_cast<__m128i*>(d + 96)); + __m128i d7 = _mm_loadu_si128(reinterpret_cast<__m128i*>(d + 112)); + d0 = _mm_xor_si128(d0, s0); + d1 = _mm_xor_si128(d1, s1); + d2 = _mm_xor_si128(d2, s2); + d3 = _mm_xor_si128(d3, s3); + d4 = _mm_xor_si128(d4, s4); + d5 = _mm_xor_si128(d5, s5); + d6 = _mm_xor_si128(d6, s6); + d7 = _mm_xor_si128(d7, s7); + _mm_storeu_si128(reinterpret_cast<__m128i*>(d), d0); + _mm_storeu_si128(reinterpret_cast<__m128i*>(d + 16), d1); + _mm_storeu_si128(reinterpret_cast<__m128i*>(d + 32), d2); + _mm_storeu_si128(reinterpret_cast<__m128i*>(d + 48), d3); + _mm_storeu_si128(reinterpret_cast<__m128i*>(d + 64), d4); + _mm_storeu_si128(reinterpret_cast<__m128i*>(d + 80), d5); + _mm_storeu_si128(reinterpret_cast<__m128i*>(d + 96), d6); + _mm_storeu_si128(reinterpret_cast<__m128i*>(d + 112), d7); + s += 128; + d += 128; + len -= 128; + } + while (len >= 16) { + _mm_storeu_si128(reinterpret_cast<__m128i*>(d), _mm_xor_si128(_mm_loadu_si128(reinterpret_cast<__m128i*>(d)), _mm_loadu_si128(reinterpret_cast(s)))); + s += 16; + d += 16; + len -= 16; + } #else #ifndef ZT_NO_TYPE_PUNNING - while (len >= 16) { - (*reinterpret_cast(d)) ^= (*reinterpret_cast(s)); - s += 8; - d += 8; - (*reinterpret_cast(d)) ^= (*reinterpret_cast(s)); - s += 8; - d += 8; - len -= 16; - } + while (len >= 16) { + (*reinterpret_cast(d)) ^= (*reinterpret_cast(s)); + s += 8; + d += 8; + (*reinterpret_cast(d)) ^= (*reinterpret_cast(s)); + s += 8; + d += 8; + len -= 16; + } #endif #endif - while (len) { - --len; - *(d++) ^= *(s++); - } - } + while (len) { + --len; + *(d++) ^= *(s++); + } + } - /** - * @param key 256-bit (32 byte) key - * @param iv 64-bit initialization vector - */ - Salsa20(const void *key,const void *iv) - { - init(key,iv); - } + /** + * @param key 256-bit (32 byte) key + * @param iv 64-bit initialization vector + */ + Salsa20(const void* key, const void* iv) + { + init(key, iv); + } - /** - * Initialize cipher - * - * @param key Key bits - * @param iv 64-bit initialization vector - */ - void init(const void *key,const void *iv); + /** + * Initialize cipher + * + * @param key Key bits + * @param iv 64-bit initialization vector + */ + void init(const void* key, const void* iv); - /** - * Encrypt/decrypt data using Salsa20/12 - * - * @param in Input data - * @param out Output buffer - * @param bytes Length of data - */ - void crypt12(const void *in,void *out,unsigned int bytes); + /** + * Encrypt/decrypt data using Salsa20/12 + * + * @param in Input data + * @param out Output buffer + * @param bytes Length of data + */ + void crypt12(const void* in, void* out, unsigned int bytes); - /** - * Encrypt/decrypt data using Salsa20/20 - * - * @param in Input data - * @param out Output buffer - * @param bytes Length of data - */ - void crypt20(const void *in,void *out,unsigned int bytes); + /** + * Encrypt/decrypt data using Salsa20/20 + * + * @param in Input data + * @param out Output buffer + * @param bytes Length of data + */ + void crypt20(const void* in, void* out, unsigned int bytes); -private: - union { + private: + union { #ifdef ZT_SALSA20_SSE - __m128i v[4]; -#endif // ZT_SALSA20_SSE - uint32_t i[16]; - } _state; + __m128i v[4]; +#endif // ZT_SALSA20_SSE + uint32_t i[16]; + } _state; }; -} // namespace ZeroTier +} // namespace ZeroTier #endif diff --git a/node/SelfAwareness.cpp b/node/SelfAwareness.cpp index dab19c6b..bd645644 100644 --- a/node/SelfAwareness.cpp +++ b/node/SelfAwareness.cpp @@ -11,122 +11,121 @@ */ /****/ +#include "SelfAwareness.hpp" + +#include "Constants.hpp" +#include "Node.hpp" +#include "Packet.hpp" +#include "Peer.hpp" +#include "RuntimeEnvironment.hpp" +#include "Switch.hpp" +#include "Topology.hpp" +#include "Trace.hpp" + +#include #include #include #include - -#include #include -#include "Constants.hpp" -#include "SelfAwareness.hpp" -#include "RuntimeEnvironment.hpp" -#include "Node.hpp" -#include "Topology.hpp" -#include "Packet.hpp" -#include "Peer.hpp" -#include "Switch.hpp" -#include "Trace.hpp" - // Entry timeout -- make it fairly long since this is just to prevent stale buildup #define ZT_SELFAWARENESS_ENTRY_TIMEOUT 600000 namespace ZeroTier { -class _ResetWithinScope -{ -public: - _ResetWithinScope(void *tPtr,int64_t now,int inetAddressFamily,InetAddress::IpScope scope) : - _now(now), - _tPtr(tPtr), - _family(inetAddressFamily), - _scope(scope) {} +class _ResetWithinScope { + public: + _ResetWithinScope(void* tPtr, int64_t now, int inetAddressFamily, InetAddress::IpScope scope) : _now(now), _tPtr(tPtr), _family(inetAddressFamily), _scope(scope) + { + } - inline void operator()(Topology &t,const SharedPtr &p) { p->resetWithinScope(_tPtr,_scope,_family,_now); } + inline void operator()(Topology& t, const SharedPtr& p) + { + p->resetWithinScope(_tPtr, _scope, _family, _now); + } -private: - uint64_t _now; - void *_tPtr; - int _family; - InetAddress::IpScope _scope; + private: + uint64_t _now; + void* _tPtr; + int _family; + InetAddress::IpScope _scope; }; -SelfAwareness::SelfAwareness(const RuntimeEnvironment *renv) : - RR(renv), - _phy(128) +SelfAwareness::SelfAwareness(const RuntimeEnvironment* renv) : RR(renv), _phy(128) { } -void SelfAwareness::iam(void *tPtr,const Address &reporter,const int64_t receivedOnLocalSocket,const InetAddress &reporterPhysicalAddress,const InetAddress &myPhysicalAddress,bool trusted,int64_t now) +void SelfAwareness::iam(void* tPtr, const Address& reporter, const int64_t receivedOnLocalSocket, const InetAddress& reporterPhysicalAddress, const InetAddress& myPhysicalAddress, bool trusted, int64_t now) { - const InetAddress::IpScope scope = myPhysicalAddress.ipScope(); + const InetAddress::IpScope scope = myPhysicalAddress.ipScope(); - if ((scope != reporterPhysicalAddress.ipScope())||(scope == InetAddress::IP_SCOPE_NONE)||(scope == InetAddress::IP_SCOPE_LOOPBACK)||(scope == InetAddress::IP_SCOPE_MULTICAST)) { - return; - } + if ((scope != reporterPhysicalAddress.ipScope()) || (scope == InetAddress::IP_SCOPE_NONE) || (scope == InetAddress::IP_SCOPE_LOOPBACK) || (scope == InetAddress::IP_SCOPE_MULTICAST)) { + return; + } - Mutex::Lock _l(_phy_m); - PhySurfaceEntry &entry = _phy[PhySurfaceKey(reporter,receivedOnLocalSocket,reporterPhysicalAddress,scope)]; + Mutex::Lock _l(_phy_m); + PhySurfaceEntry& entry = _phy[PhySurfaceKey(reporter, receivedOnLocalSocket, reporterPhysicalAddress, scope)]; - if ( (trusted) && ((now - entry.ts) < ZT_SELFAWARENESS_ENTRY_TIMEOUT) && (!entry.mySurface.ipsEqual(myPhysicalAddress)) ) { - // Changes to external surface reported by trusted peers causes path reset in this scope - RR->t->resettingPathsInScope(tPtr,reporter,reporterPhysicalAddress,myPhysicalAddress,scope); + if ((trusted) && ((now - entry.ts) < ZT_SELFAWARENESS_ENTRY_TIMEOUT) && (! entry.mySurface.ipsEqual(myPhysicalAddress))) { + // Changes to external surface reported by trusted peers causes path reset in this scope + RR->t->resettingPathsInScope(tPtr, reporter, reporterPhysicalAddress, myPhysicalAddress, scope); - entry.mySurface = myPhysicalAddress; - entry.ts = now; - entry.trusted = trusted; + entry.mySurface = myPhysicalAddress; + entry.ts = now; + entry.trusted = trusted; - // Erase all entries in this scope that were not reported from this remote address to prevent 'thrashing' - // due to multiple reports of endpoint change. - // Don't use 'entry' after this since hash table gets modified. - { - Hashtable< PhySurfaceKey,PhySurfaceEntry >::Iterator i(_phy); - PhySurfaceKey *k = (PhySurfaceKey *)0; - PhySurfaceEntry *e = (PhySurfaceEntry *)0; - while (i.next(k,e)) { - if ((k->reporterPhysicalAddress != reporterPhysicalAddress)&&(k->scope == scope)) { - _phy.erase(*k); - } - } - } + // Erase all entries in this scope that were not reported from this remote address to prevent 'thrashing' + // due to multiple reports of endpoint change. + // Don't use 'entry' after this since hash table gets modified. + { + Hashtable::Iterator i(_phy); + PhySurfaceKey* k = (PhySurfaceKey*)0; + PhySurfaceEntry* e = (PhySurfaceEntry*)0; + while (i.next(k, e)) { + if ((k->reporterPhysicalAddress != reporterPhysicalAddress) && (k->scope == scope)) { + _phy.erase(*k); + } + } + } - // Reset all paths within this scope and address family - _ResetWithinScope rset(tPtr,now,myPhysicalAddress.ss_family,(InetAddress::IpScope)scope); - RR->topology->eachPeer<_ResetWithinScope &>(rset); - } else { - // Otherwise just update DB to use to determine external surface info - entry.mySurface = myPhysicalAddress; - entry.ts = now; - entry.trusted = trusted; - } + // Reset all paths within this scope and address family + _ResetWithinScope rset(tPtr, now, myPhysicalAddress.ss_family, (InetAddress::IpScope)scope); + RR->topology->eachPeer<_ResetWithinScope&>(rset); + } + else { + // Otherwise just update DB to use to determine external surface info + entry.mySurface = myPhysicalAddress; + entry.ts = now; + entry.trusted = trusted; + } } std::vector SelfAwareness::whoami() { - std::vector surfaceAddresses; - Mutex::Lock _l(_phy_m); - Hashtable< PhySurfaceKey,PhySurfaceEntry >::Iterator i(_phy); - PhySurfaceKey *k = (PhySurfaceKey *)0; - PhySurfaceEntry *e = (PhySurfaceEntry *)0; - while (i.next(k,e)) { - if (std::find(surfaceAddresses.begin(), surfaceAddresses.end(), e->mySurface) == surfaceAddresses.end()) { - surfaceAddresses.push_back(e->mySurface); - } - } - return surfaceAddresses; + std::vector surfaceAddresses; + Mutex::Lock _l(_phy_m); + Hashtable::Iterator i(_phy); + PhySurfaceKey* k = (PhySurfaceKey*)0; + PhySurfaceEntry* e = (PhySurfaceEntry*)0; + while (i.next(k, e)) { + if (std::find(surfaceAddresses.begin(), surfaceAddresses.end(), e->mySurface) == surfaceAddresses.end()) { + surfaceAddresses.push_back(e->mySurface); + } + } + return surfaceAddresses; } void SelfAwareness::clean(int64_t now) { - Mutex::Lock _l(_phy_m); - Hashtable< PhySurfaceKey,PhySurfaceEntry >::Iterator i(_phy); - PhySurfaceKey *k = (PhySurfaceKey *)0; - PhySurfaceEntry *e = (PhySurfaceEntry *)0; - while (i.next(k,e)) { - if ((now - e->ts) >= ZT_SELFAWARENESS_ENTRY_TIMEOUT) { - _phy.erase(*k); - } - } + Mutex::Lock _l(_phy_m); + Hashtable::Iterator i(_phy); + PhySurfaceKey* k = (PhySurfaceKey*)0; + PhySurfaceEntry* e = (PhySurfaceEntry*)0; + while (i.next(k, e)) { + if ((now - e->ts) >= ZT_SELFAWARENESS_ENTRY_TIMEOUT) { + _phy.erase(*k); + } + } } -} // namespace ZeroTier +} // namespace ZeroTier diff --git a/node/SelfAwareness.hpp b/node/SelfAwareness.hpp index 2f735282..a71f31f2 100644 --- a/node/SelfAwareness.hpp +++ b/node/SelfAwareness.hpp @@ -14,10 +14,10 @@ #ifndef ZT_SELFAWARENESS_HPP #define ZT_SELFAWARENESS_HPP -#include "Constants.hpp" -#include "InetAddress.hpp" -#include "Hashtable.hpp" #include "Address.hpp" +#include "Constants.hpp" +#include "Hashtable.hpp" +#include "InetAddress.hpp" #include "Mutex.hpp" namespace ZeroTier { @@ -27,67 +27,78 @@ class RuntimeEnvironment; /** * Tracks changes to this peer's real world addresses */ -class SelfAwareness -{ -public: - SelfAwareness(const RuntimeEnvironment *renv); +class SelfAwareness { + public: + SelfAwareness(const RuntimeEnvironment* renv); - /** - * Called when a trusted remote peer informs us of our external network address - * - * @param reporter ZeroTier address of reporting peer - * @param receivedOnLocalAddress Local address on which report was received - * @param reporterPhysicalAddress Physical address that reporting peer seems to have - * @param myPhysicalAddress Physical address that peer says we have - * @param trusted True if this peer is trusted as an authority to inform us of external address changes - * @param now Current time - */ - void iam(void *tPtr,const Address &reporter,const int64_t receivedOnLocalSocket,const InetAddress &reporterPhysicalAddress,const InetAddress &myPhysicalAddress,bool trusted,int64_t now); + /** + * Called when a trusted remote peer informs us of our external network address + * + * @param reporter ZeroTier address of reporting peer + * @param receivedOnLocalAddress Local address on which report was received + * @param reporterPhysicalAddress Physical address that reporting peer seems to have + * @param myPhysicalAddress Physical address that peer says we have + * @param trusted True if this peer is trusted as an authority to inform us of external address changes + * @param now Current time + */ + void iam(void* tPtr, const Address& reporter, const int64_t receivedOnLocalSocket, const InetAddress& reporterPhysicalAddress, const InetAddress& myPhysicalAddress, bool trusted, int64_t now); - /** - * Return all known external surface addresses reported by peers - * - * @return A vector of InetAddress(es) - */ - std::vector whoami(); + /** + * Return all known external surface addresses reported by peers + * + * @return A vector of InetAddress(es) + */ + std::vector whoami(); - /** - * Clean up database periodically - * - * @param now Current time - */ - void clean(int64_t now); + /** + * Clean up database periodically + * + * @param now Current time + */ + void clean(int64_t now); -private: - struct PhySurfaceKey - { - Address reporter; - int64_t receivedOnLocalSocket; - InetAddress reporterPhysicalAddress; - InetAddress::IpScope scope; + private: + struct PhySurfaceKey { + Address reporter; + int64_t receivedOnLocalSocket; + InetAddress reporterPhysicalAddress; + InetAddress::IpScope scope; - PhySurfaceKey() : reporter(),scope(InetAddress::IP_SCOPE_NONE) {} - PhySurfaceKey(const Address &r,const int64_t rol,const InetAddress &ra,InetAddress::IpScope s) : reporter(r),receivedOnLocalSocket(rol),reporterPhysicalAddress(ra),scope(s) {} + PhySurfaceKey() : reporter(), scope(InetAddress::IP_SCOPE_NONE) + { + } + PhySurfaceKey(const Address& r, const int64_t rol, const InetAddress& ra, InetAddress::IpScope s) : reporter(r), receivedOnLocalSocket(rol), reporterPhysicalAddress(ra), scope(s) + { + } - inline unsigned long hashCode() const { return ((unsigned long)reporter.toInt() + (unsigned long)scope); } - inline bool operator==(const PhySurfaceKey &k) const { return ((reporter == k.reporter)&&(receivedOnLocalSocket == k.receivedOnLocalSocket)&&(reporterPhysicalAddress == k.reporterPhysicalAddress)&&(scope == k.scope)); } - }; - struct PhySurfaceEntry - { - InetAddress mySurface; - uint64_t ts; - bool trusted; + inline unsigned long hashCode() const + { + return ((unsigned long)reporter.toInt() + (unsigned long)scope); + } + inline bool operator==(const PhySurfaceKey& k) const + { + return ((reporter == k.reporter) && (receivedOnLocalSocket == k.receivedOnLocalSocket) && (reporterPhysicalAddress == k.reporterPhysicalAddress) && (scope == k.scope)); + } + }; + struct PhySurfaceEntry { + InetAddress mySurface; + uint64_t ts; + bool trusted; - PhySurfaceEntry() : mySurface(),ts(0),trusted(false) {} - PhySurfaceEntry(const InetAddress &a,const uint64_t t) : mySurface(a),ts(t),trusted(false) {} - }; + PhySurfaceEntry() : mySurface(), ts(0), trusted(false) + { + } + PhySurfaceEntry(const InetAddress& a, const uint64_t t) : mySurface(a), ts(t), trusted(false) + { + } + }; - const RuntimeEnvironment *RR; + const RuntimeEnvironment* RR; - Hashtable< PhySurfaceKey,PhySurfaceEntry > _phy; - Mutex _phy_m; + Hashtable _phy; + Mutex _phy_m; }; -} // namespace ZeroTier +} // namespace ZeroTier #endif diff --git a/node/SharedPtr.hpp b/node/SharedPtr.hpp index e172b578..bc2b795c 100644 --- a/node/SharedPtr.hpp +++ b/node/SharedPtr.hpp @@ -14,8 +14,8 @@ #ifndef ZT_SHAREDPTR_HPP #define ZT_SHAREDPTR_HPP -#include "Mutex.hpp" #include "AtomicCounter.hpp" +#include "Mutex.hpp" namespace ZeroTier { @@ -26,115 +26,150 @@ namespace ZeroTier { * counted must list this as a 'friend' and must have a private instance of * AtomicCounter called __refCount. */ -template -class SharedPtr -{ -public: - SharedPtr() : _ptr((T *)0) {} - SharedPtr(T *obj) : _ptr(obj) { ++obj->__refCount; } - SharedPtr(const SharedPtr &sp) : _ptr(sp._getAndInc()) {} +template class SharedPtr { + public: + SharedPtr() : _ptr((T*)0) + { + } + SharedPtr(T* obj) : _ptr(obj) + { + ++obj->__refCount; + } + SharedPtr(const SharedPtr& sp) : _ptr(sp._getAndInc()) + { + } - ~SharedPtr() - { - if (_ptr) { - if (--_ptr->__refCount <= 0) { - delete _ptr; - } - } - } + ~SharedPtr() + { + if (_ptr) { + if (--_ptr->__refCount <= 0) { + delete _ptr; + } + } + } - inline SharedPtr &operator=(const SharedPtr &sp) - { - if (_ptr != sp._ptr) { - T *p = sp._getAndInc(); - if (_ptr) { - if (--_ptr->__refCount <= 0) { - delete _ptr; - } - } - _ptr = p; - } - return *this; - } + inline SharedPtr& operator=(const SharedPtr& sp) + { + if (_ptr != sp._ptr) { + T* p = sp._getAndInc(); + if (_ptr) { + if (--_ptr->__refCount <= 0) { + delete _ptr; + } + } + _ptr = p; + } + return *this; + } - /** - * Set to a naked pointer and increment its reference count - * - * This assumes this SharedPtr is NULL and that ptr is not a 'zombie.' No - * checks are performed. - * - * @param ptr Naked pointer to assign - */ - inline void set(T *ptr) - { - zero(); - ++ptr->__refCount; - _ptr = ptr; - } + /** + * Set to a naked pointer and increment its reference count + * + * This assumes this SharedPtr is NULL and that ptr is not a 'zombie.' No + * checks are performed. + * + * @param ptr Naked pointer to assign + */ + inline void set(T* ptr) + { + zero(); + ++ptr->__refCount; + _ptr = ptr; + } - /** - * Swap with another pointer 'for free' without ref count overhead - * - * @param with Pointer to swap with - */ - inline void swap(SharedPtr &with) - { - T *tmp = _ptr; - _ptr = with._ptr; - with._ptr = tmp; - } + /** + * Swap with another pointer 'for free' without ref count overhead + * + * @param with Pointer to swap with + */ + inline void swap(SharedPtr& with) + { + T* tmp = _ptr; + _ptr = with._ptr; + with._ptr = tmp; + } - inline operator bool() const { return (_ptr != (T *)0); } - inline T &operator*() const { return *_ptr; } - inline T *operator->() const { return _ptr; } + inline operator bool() const + { + return (_ptr != (T*)0); + } + inline T& operator*() const + { + return *_ptr; + } + inline T* operator->() const + { + return _ptr; + } - /** - * @return Raw pointer to held object - */ - inline T *ptr() const { return _ptr; } + /** + * @return Raw pointer to held object + */ + inline T* ptr() const + { + return _ptr; + } - /** - * Set this pointer to NULL - */ - inline void zero() - { - if (_ptr) { - if (--_ptr->__refCount <= 0) { - delete _ptr; - } - _ptr = (T *)0; - } - } + /** + * Set this pointer to NULL + */ + inline void zero() + { + if (_ptr) { + if (--_ptr->__refCount <= 0) { + delete _ptr; + } + _ptr = (T*)0; + } + } - /** - * @return Number of references according to this object's ref count or 0 if NULL - */ - inline int references() - { - if (_ptr) { - return _ptr->__refCount.load(); - } - return 0; - } + /** + * @return Number of references according to this object's ref count or 0 if NULL + */ + inline int references() + { + if (_ptr) { + return _ptr->__refCount.load(); + } + return 0; + } - inline bool operator==(const SharedPtr &sp) const { return (_ptr == sp._ptr); } - inline bool operator!=(const SharedPtr &sp) const { return (_ptr != sp._ptr); } - inline bool operator>(const SharedPtr &sp) const { return (_ptr > sp._ptr); } - inline bool operator<(const SharedPtr &sp) const { return (_ptr < sp._ptr); } - inline bool operator>=(const SharedPtr &sp) const { return (_ptr >= sp._ptr); } - inline bool operator<=(const SharedPtr &sp) const { return (_ptr <= sp._ptr); } + inline bool operator==(const SharedPtr& sp) const + { + return (_ptr == sp._ptr); + } + inline bool operator!=(const SharedPtr& sp) const + { + return (_ptr != sp._ptr); + } + inline bool operator>(const SharedPtr& sp) const + { + return (_ptr > sp._ptr); + } + inline bool operator<(const SharedPtr& sp) const + { + return (_ptr < sp._ptr); + } + inline bool operator>=(const SharedPtr& sp) const + { + return (_ptr >= sp._ptr); + } + inline bool operator<=(const SharedPtr& sp) const + { + return (_ptr <= sp._ptr); + } -private: - inline T *_getAndInc() const - { - if (_ptr) { - ++_ptr->__refCount; - } - return _ptr; - } - T *_ptr; + private: + inline T* _getAndInc() const + { + if (_ptr) { + ++_ptr->__refCount; + } + return _ptr; + } + T* _ptr; }; -} // namespace ZeroTier +} // namespace ZeroTier #endif diff --git a/node/Switch.cpp b/node/Switch.cpp index 7664f7a4..e8ca47dc 100644 --- a/node/Switch.cpp +++ b/node/Switch.cpp @@ -11,1233 +11,1222 @@ */ /****/ -#include -#include +#include "Switch.hpp" + +#include "../include/ZeroTierOne.h" +#include "../version.h" +#include "Constants.hpp" +#include "InetAddress.hpp" +#include "Metrics.hpp" +#include "Node.hpp" +#include "Packet.hpp" +#include "Peer.hpp" +#include "RuntimeEnvironment.hpp" +#include "SelfAwareness.hpp" +#include "Topology.hpp" +#include "Trace.hpp" #include -#include #include - -#include "../version.h" -#include "../include/ZeroTierOne.h" - -#include "Constants.hpp" -#include "RuntimeEnvironment.hpp" -#include "Switch.hpp" -#include "Node.hpp" -#include "InetAddress.hpp" -#include "Topology.hpp" -#include "Peer.hpp" -#include "SelfAwareness.hpp" -#include "Packet.hpp" -#include "Trace.hpp" -#include "Metrics.hpp" +#include +#include +#include namespace ZeroTier { -Switch::Switch(const RuntimeEnvironment *renv) : - RR(renv), - _lastBeaconResponse(0), - _lastCheckedQueues(0), - _lastUniteAttempt(8) // only really used on root servers and upstreams, and it'll grow there just fine +Switch::Switch(const RuntimeEnvironment* renv) : RR(renv), _lastBeaconResponse(0), _lastCheckedQueues(0), _lastUniteAttempt(8) // only really used on root servers and upstreams, and it'll grow there just fine { } // Returns true if packet appears valid; pos and proto will be set -static bool _ipv6GetPayload(const uint8_t *frameData,unsigned int frameLen,unsigned int &pos,unsigned int &proto) +static bool _ipv6GetPayload(const uint8_t* frameData, unsigned int frameLen, unsigned int& pos, unsigned int& proto) { - if (frameLen < 40) { - return false; - } - pos = 40; - proto = frameData[6]; - while (pos <= frameLen) { - switch(proto) { - case 0: // hop-by-hop options - case 43: // routing - case 60: // destination options - case 135: // mobility options - if ((pos + 8) > frameLen) { - return false; // invalid! - } - proto = frameData[pos]; - pos += ((unsigned int)frameData[pos + 1] * 8) + 8; - break; + if (frameLen < 40) { + return false; + } + pos = 40; + proto = frameData[6]; + while (pos <= frameLen) { + switch (proto) { + case 0: // hop-by-hop options + case 43: // routing + case 60: // destination options + case 135: // mobility options + if ((pos + 8) > frameLen) { + return false; // invalid! + } + proto = frameData[pos]; + pos += ((unsigned int)frameData[pos + 1] * 8) + 8; + break; - //case 44: // fragment -- we currently can't parse these and they are deprecated in IPv6 anyway - //case 50: - //case 51: // IPSec ESP and AH -- we have to stop here since this is encrypted stuff - default: - return true; - } - } - return false; // overflow == invalid + // case 44: // fragment -- we currently can't parse these and they are deprecated in IPv6 anyway + // case 50: + // case 51: // IPSec ESP and AH -- we have to stop here since this is encrypted stuff + default: + return true; + } + } + return false; // overflow == invalid } -void Switch::onRemotePacket(void *tPtr,const int64_t localSocket,const InetAddress &fromAddr,const void *data,unsigned int len) +void Switch::onRemotePacket(void* tPtr, const int64_t localSocket, const InetAddress& fromAddr, const void* data, unsigned int len) { - int32_t flowId = ZT_QOS_NO_FLOW; - try { - const int64_t now = RR->node->now(); + int32_t flowId = ZT_QOS_NO_FLOW; + try { + const int64_t now = RR->node->now(); - const SharedPtr path(RR->topology->getPath(localSocket,fromAddr)); - path->received(now); + const SharedPtr path(RR->topology->getPath(localSocket, fromAddr)); + path->received(now); - if (len == 13) { - /* LEGACY: before VERB_PUSH_DIRECT_PATHS, peers used broadcast - * announcements on the LAN to solve the 'same network problem.' We - * no longer send these, but we'll listen for them for a while to - * locate peers with versions <1.0.4. */ + if (len > ZT_PROTO_MIN_FRAGMENT_LENGTH) { + if (reinterpret_cast(data)[ZT_PACKET_FRAGMENT_IDX_FRAGMENT_INDICATOR] == ZT_PACKET_FRAGMENT_INDICATOR) { + // Handle fragment ---------------------------------------------------- - const Address beaconAddr(reinterpret_cast(data) + 8,5); - if (beaconAddr == RR->identity.address()) { - return; - } - if (!RR->node->shouldUsePathForZeroTierTraffic(tPtr,beaconAddr,localSocket,fromAddr)) { - return; - } - const SharedPtr peer(RR->topology->getPeer(tPtr,beaconAddr)); - if (peer) { // we'll only respond to beacons from known peers - if ((now - _lastBeaconResponse) >= 2500) { // limit rate of responses - _lastBeaconResponse = now; - Packet outp(peer->address(),RR->identity.address(),Packet::VERB_NOP); - outp.armor(peer->key(),true,peer->aesKeysIfSupported()); - Metrics::pkt_nop_out++; - path->send(RR,tPtr,outp.data(),outp.size(),now); - } - } + Packet::Fragment fragment(data, len); + const Address destination(fragment.destination()); - } else if (len > ZT_PROTO_MIN_FRAGMENT_LENGTH) { // SECURITY: min length check is important since we do some C-style stuff below! - if (reinterpret_cast(data)[ZT_PACKET_FRAGMENT_IDX_FRAGMENT_INDICATOR] == ZT_PACKET_FRAGMENT_INDICATOR) { - // Handle fragment ---------------------------------------------------- + if (destination != RR->identity.address()) { + if ((! RR->topology->amUpstream()) && (! path->trustEstablished(now))) { + return; + } - Packet::Fragment fragment(data,len); - const Address destination(fragment.destination()); + if (fragment.hops() < ZT_RELAY_MAX_HOPS) { + fragment.incrementHops(); - if (destination != RR->identity.address()) { - if ( (!RR->topology->amUpstream()) && (!path->trustEstablished(now)) ) { - return; - } + // Note: we don't bother initiating NAT-t for fragments, since heads will set that off. + // It wouldn't hurt anything, just redundant and unnecessary. + SharedPtr relayTo = RR->topology->getPeer(tPtr, destination); + if ((! relayTo) || (! relayTo->sendDirect(tPtr, fragment.data(), fragment.size(), now, false))) { + // Don't know peer or no direct path -- so relay via someone upstream + relayTo = RR->topology->getUpstreamPeer(); + if (relayTo) { + relayTo->sendDirect(tPtr, fragment.data(), fragment.size(), now, true); + } + } + } + } + else { + // Fragment looks like ours + const uint64_t fragmentPacketId = fragment.packetId(); + const unsigned int fragmentNumber = fragment.fragmentNumber(); + const unsigned int totalFragments = fragment.totalFragments(); - if (fragment.hops() < ZT_RELAY_MAX_HOPS) { - fragment.incrementHops(); + if ((totalFragments <= ZT_MAX_PACKET_FRAGMENTS) && (fragmentNumber < ZT_MAX_PACKET_FRAGMENTS) && (fragmentNumber > 0) && (totalFragments > 1)) { + // Fragment appears basically sane. Its fragment number must be + // 1 or more, since a Packet with fragmented bit set is fragment 0. + // Total fragments must be more than 1, otherwise why are we + // seeing a Packet::Fragment? - // Note: we don't bother initiating NAT-t for fragments, since heads will set that off. - // It wouldn't hurt anything, just redundant and unnecessary. - SharedPtr relayTo = RR->topology->getPeer(tPtr,destination); - if ((!relayTo)||(!relayTo->sendDirect(tPtr,fragment.data(),fragment.size(),now,false))) { - // Don't know peer or no direct path -- so relay via someone upstream - relayTo = RR->topology->getUpstreamPeer(); - if (relayTo) { - relayTo->sendDirect(tPtr,fragment.data(),fragment.size(),now,true); - } - } - } - } else { - // Fragment looks like ours - const uint64_t fragmentPacketId = fragment.packetId(); - const unsigned int fragmentNumber = fragment.fragmentNumber(); - const unsigned int totalFragments = fragment.totalFragments(); + RXQueueEntry* const rq = _findRXQueueEntry(fragmentPacketId); + Mutex::Lock rql(rq->lock); + if (rq->packetId != fragmentPacketId) { + // No packet found, so we received a fragment without its head. - if ((totalFragments <= ZT_MAX_PACKET_FRAGMENTS)&&(fragmentNumber < ZT_MAX_PACKET_FRAGMENTS)&&(fragmentNumber > 0)&&(totalFragments > 1)) { - // Fragment appears basically sane. Its fragment number must be - // 1 or more, since a Packet with fragmented bit set is fragment 0. - // Total fragments must be more than 1, otherwise why are we - // seeing a Packet::Fragment? + rq->flowId = flowId; + rq->timestamp = now; + rq->packetId = fragmentPacketId; + rq->frags[fragmentNumber - 1] = fragment; + rq->totalFragments = totalFragments; // total fragment count is known + rq->haveFragments = 1 << fragmentNumber; // we have only this fragment + rq->complete = false; + } + else if (! (rq->haveFragments & (1 << fragmentNumber))) { + // We have other fragments and maybe the head, so add this one and check - RXQueueEntry *const rq = _findRXQueueEntry(fragmentPacketId); - Mutex::Lock rql(rq->lock); - if (rq->packetId != fragmentPacketId) { - // No packet found, so we received a fragment without its head. + rq->frags[fragmentNumber - 1] = fragment; + rq->totalFragments = totalFragments; - rq->flowId = flowId; - rq->timestamp = now; - rq->packetId = fragmentPacketId; - rq->frags[fragmentNumber - 1] = fragment; - rq->totalFragments = totalFragments; // total fragment count is known - rq->haveFragments = 1 << fragmentNumber; // we have only this fragment - rq->complete = false; - } else if (!(rq->haveFragments & (1 << fragmentNumber))) { - // We have other fragments and maybe the head, so add this one and check + if (Utils::countBits(rq->haveFragments |= (1 << fragmentNumber)) == totalFragments) { + // We have all fragments -- assemble and process full Packet - rq->frags[fragmentNumber - 1] = fragment; - rq->totalFragments = totalFragments; + for (unsigned int f = 1; f < totalFragments; ++f) { + rq->frag0.append(rq->frags[f - 1].payload(), rq->frags[f - 1].payloadLength()); + } - if (Utils::countBits(rq->haveFragments |= (1 << fragmentNumber)) == totalFragments) { - // We have all fragments -- assemble and process full Packet + if (rq->frag0.tryDecode(RR, tPtr, flowId)) { + rq->timestamp = 0; // packet decoded, free entry + } + else { + rq->complete = true; // set complete flag but leave entry since it probably needs WHOIS or something + } + } + } // else this is a duplicate fragment, ignore + } + } - for(unsigned int f=1;ffrag0.append(rq->frags[f - 1].payload(),rq->frags[f - 1].payloadLength()); - } + // -------------------------------------------------------------------- + } + else if (len >= ZT_PROTO_MIN_PACKET_LENGTH) { // min length check is important! + // Handle packet head ------------------------------------------------- - if (rq->frag0.tryDecode(RR,tPtr,flowId)) { - rq->timestamp = 0; // packet decoded, free entry - } else { - rq->complete = true; // set complete flag but leave entry since it probably needs WHOIS or something - } - } - } // else this is a duplicate fragment, ignore - } - } + const Address destination(reinterpret_cast(data) + 8, ZT_ADDRESS_LENGTH); + const Address source(reinterpret_cast(data) + 13, ZT_ADDRESS_LENGTH); - // -------------------------------------------------------------------- - } else if (len >= ZT_PROTO_MIN_PACKET_LENGTH) { // min length check is important! - // Handle packet head ------------------------------------------------- + if (source == RR->identity.address()) { + return; + } - const Address destination(reinterpret_cast(data) + 8,ZT_ADDRESS_LENGTH); - const Address source(reinterpret_cast(data) + 13,ZT_ADDRESS_LENGTH); + if (destination != RR->identity.address()) { + if ((! RR->topology->amUpstream()) && (! path->trustEstablished(now)) && (source != RR->identity.address())) { + return; + } - if (source == RR->identity.address()) { - return; - } + Packet packet(data, len); - if (destination != RR->identity.address()) { - if ( (!RR->topology->amUpstream()) && (!path->trustEstablished(now)) && (source != RR->identity.address()) ) { - return; - } + if (packet.hops() < ZT_RELAY_MAX_HOPS) { + packet.incrementHops(); + SharedPtr relayTo = RR->topology->getPeer(tPtr, destination); + if ((relayTo) && (relayTo->sendDirect(tPtr, packet.data(), packet.size(), now, false))) { + if ((source != RR->identity.address()) && (_shouldUnite(now, source, destination))) { + const SharedPtr sourcePeer(RR->topology->getPeer(tPtr, source)); + if (sourcePeer) { + relayTo->introduce(tPtr, now, sourcePeer); + } + } + } + else { + relayTo = RR->topology->getUpstreamPeer(); + if ((relayTo) && (relayTo->address() != source)) { + if (relayTo->sendDirect(tPtr, packet.data(), packet.size(), now, true)) { + const SharedPtr sourcePeer(RR->topology->getPeer(tPtr, source)); + if (sourcePeer) { + relayTo->introduce(tPtr, now, sourcePeer); + } + } + } + } + } + } + else if ((reinterpret_cast(data)[ZT_PACKET_IDX_FLAGS] & ZT_PROTO_FLAG_FRAGMENTED) != 0) { + // Packet is the head of a fragmented packet series - Packet packet(data,len); + const uint64_t packetId = + ((((uint64_t)reinterpret_cast(data)[0]) << 56) | (((uint64_t)reinterpret_cast(data)[1]) << 48) | (((uint64_t)reinterpret_cast(data)[2]) << 40) + | (((uint64_t)reinterpret_cast(data)[3]) << 32) | (((uint64_t)reinterpret_cast(data)[4]) << 24) | (((uint64_t)reinterpret_cast(data)[5]) << 16) + | (((uint64_t)reinterpret_cast(data)[6]) << 8) | ((uint64_t)reinterpret_cast(data)[7])); - if (packet.hops() < ZT_RELAY_MAX_HOPS) { - packet.incrementHops(); - SharedPtr relayTo = RR->topology->getPeer(tPtr,destination); - if ((relayTo)&&(relayTo->sendDirect(tPtr,packet.data(),packet.size(),now,false))) { - if ((source != RR->identity.address())&&(_shouldUnite(now,source,destination))) { - const SharedPtr sourcePeer(RR->topology->getPeer(tPtr,source)); - if (sourcePeer) { - relayTo->introduce(tPtr,now,sourcePeer); - } - } - } else { - relayTo = RR->topology->getUpstreamPeer(); - if ((relayTo)&&(relayTo->address() != source)) { - if (relayTo->sendDirect(tPtr,packet.data(),packet.size(),now,true)) { - const SharedPtr sourcePeer(RR->topology->getPeer(tPtr,source)); - if (sourcePeer) { - relayTo->introduce(tPtr,now,sourcePeer); - } - } - } - } - } - } else if ((reinterpret_cast(data)[ZT_PACKET_IDX_FLAGS] & ZT_PROTO_FLAG_FRAGMENTED) != 0) { - // Packet is the head of a fragmented packet series + RXQueueEntry* const rq = _findRXQueueEntry(packetId); + Mutex::Lock rql(rq->lock); + if (rq->packetId != packetId) { + // If we have no other fragments yet, create an entry and save the head - const uint64_t packetId = ( - (((uint64_t)reinterpret_cast(data)[0]) << 56) | - (((uint64_t)reinterpret_cast(data)[1]) << 48) | - (((uint64_t)reinterpret_cast(data)[2]) << 40) | - (((uint64_t)reinterpret_cast(data)[3]) << 32) | - (((uint64_t)reinterpret_cast(data)[4]) << 24) | - (((uint64_t)reinterpret_cast(data)[5]) << 16) | - (((uint64_t)reinterpret_cast(data)[6]) << 8) | - ((uint64_t)reinterpret_cast(data)[7]) - ); + rq->flowId = flowId; + rq->timestamp = now; + rq->packetId = packetId; + rq->frag0.init(data, len, path, now); + rq->totalFragments = 0; + rq->haveFragments = 1; + rq->complete = false; + } + else if (! (rq->haveFragments & 1)) { + // If we have other fragments but no head, see if we are complete with the head - RXQueueEntry *const rq = _findRXQueueEntry(packetId); - Mutex::Lock rql(rq->lock); - if (rq->packetId != packetId) { - // If we have no other fragments yet, create an entry and save the head + if ((rq->totalFragments > 1) && (Utils::countBits(rq->haveFragments |= 1) == rq->totalFragments)) { + // We have all fragments -- assemble and process full Packet - rq->flowId = flowId; - rq->timestamp = now; - rq->packetId = packetId; - rq->frag0.init(data,len,path,now); - rq->totalFragments = 0; - rq->haveFragments = 1; - rq->complete = false; - } else if (!(rq->haveFragments & 1)) { - // If we have other fragments but no head, see if we are complete with the head + rq->frag0.init(data, len, path, now); + for (unsigned int f = 1; f < rq->totalFragments; ++f) { + rq->frag0.append(rq->frags[f - 1].payload(), rq->frags[f - 1].payloadLength()); + } - if ((rq->totalFragments > 1)&&(Utils::countBits(rq->haveFragments |= 1) == rq->totalFragments)) { - // We have all fragments -- assemble and process full Packet + if (rq->frag0.tryDecode(RR, tPtr, flowId)) { + rq->timestamp = 0; // packet decoded, free entry + } + else { + rq->complete = true; // set complete flag but leave entry since it probably needs WHOIS or something + } + } + else { + // Still waiting on more fragments, but keep the head + rq->frag0.init(data, len, path, now); + } + } // else this is a duplicate head, ignore + } + else { + // Packet is unfragmented, so just process it + IncomingPacket packet(data, len, path, now); + if (! packet.tryDecode(RR, tPtr, flowId)) { + RXQueueEntry* const rq = _nextRXQueueEntry(); + Mutex::Lock rql(rq->lock); + rq->flowId = flowId; + rq->timestamp = now; + rq->packetId = packet.packetId(); + rq->frag0 = packet; + rq->totalFragments = 1; + rq->haveFragments = 1; + rq->complete = true; + } + } - rq->frag0.init(data,len,path,now); - for(unsigned int f=1;ftotalFragments;++f) { - rq->frag0.append(rq->frags[f - 1].payload(),rq->frags[f - 1].payloadLength()); - } - - if (rq->frag0.tryDecode(RR,tPtr,flowId)) { - rq->timestamp = 0; // packet decoded, free entry - } else { - rq->complete = true; // set complete flag but leave entry since it probably needs WHOIS or something - } - } else { - // Still waiting on more fragments, but keep the head - rq->frag0.init(data,len,path,now); - } - } // else this is a duplicate head, ignore - } else { - // Packet is unfragmented, so just process it - IncomingPacket packet(data,len,path,now); - if (!packet.tryDecode(RR,tPtr,flowId)) { - RXQueueEntry *const rq = _nextRXQueueEntry(); - Mutex::Lock rql(rq->lock); - rq->flowId = flowId; - rq->timestamp = now; - rq->packetId = packet.packetId(); - rq->frag0 = packet; - rq->totalFragments = 1; - rq->haveFragments = 1; - rq->complete = true; - } - } - - // -------------------------------------------------------------------- - } - } - } catch ( ... ) {} // sanity check, should be caught elsewhere + // -------------------------------------------------------------------- + } + } + } + catch (...) { + } // sanity check, should be caught elsewhere } -void Switch::onLocalEthernet(void *tPtr,const SharedPtr &network,const MAC &from,const MAC &to,unsigned int etherType,unsigned int vlanId,const void *data,unsigned int len) +void Switch::onLocalEthernet(void* tPtr, const SharedPtr& network, const MAC& from, const MAC& to, unsigned int etherType, unsigned int vlanId, const void* data, unsigned int len) { - if (!network->hasConfig()) { - return; - } + if (! network->hasConfig()) { + return; + } - // Check if this packet is from someone other than the tap -- i.e. bridged in - bool fromBridged; - if ((fromBridged = (from != network->mac()))) { - if (!network->config().permitsBridging(RR->identity.address())) { - RR->t->outgoingNetworkFrameDropped(tPtr,network,from,to,etherType,vlanId,len,"not a bridge"); - return; - } - } + // Check if this packet is from someone other than the tap -- i.e. bridged in + bool fromBridged; + if ((fromBridged = (from != network->mac()))) { + if (! network->config().permitsBridging(RR->identity.address())) { + RR->t->outgoingNetworkFrameDropped(tPtr, network, from, to, etherType, vlanId, len, "not a bridge"); + return; + } + } - uint8_t qosBucket = ZT_AQM_DEFAULT_BUCKET; + uint8_t qosBucket = ZT_AQM_DEFAULT_BUCKET; - /** - * A pseudo-unique identifier used by balancing and bonding policies to - * categorize individual flows/conversations for assignment to a specific - * physical path. This identifier consists of the source port and - * destination port of the encapsulated frame. - * - * A flowId of -1 will indicate that there is no preference for how this - * packet shall be sent. An example of this would be an ICMP packet. - */ + /** + * A pseudo-unique identifier used by balancing and bonding policies to + * categorize individual flows/conversations for assignment to a specific + * physical path. This identifier consists of the source port and + * destination port of the encapsulated frame. + * + * A flowId of -1 will indicate that there is no preference for how this + * packet shall be sent. An example of this would be an ICMP packet. + */ - int32_t flowId = ZT_QOS_NO_FLOW; + int32_t flowId = ZT_QOS_NO_FLOW; - if (etherType == ZT_ETHERTYPE_IPV4 && (len >= 20)) { - uint16_t srcPort = 0; - uint16_t dstPort = 0; - uint8_t proto = (reinterpret_cast(data)[9]); - const unsigned int headerLen = 4 * (reinterpret_cast(data)[0] & 0xf); - switch(proto) { - case 0x01: // ICMP - //flowId = 0x01; - break; - // All these start with 16-bit source and destination port in that order - case 0x06: // TCP - case 0x11: // UDP - case 0x84: // SCTP - case 0x88: // UDPLite - if (len > (headerLen + 4)) { - unsigned int pos = headerLen + 0; - srcPort = (reinterpret_cast(data)[pos++]) << 8; - srcPort |= (reinterpret_cast(data)[pos]); - pos++; - dstPort = (reinterpret_cast(data)[pos++]) << 8; - dstPort |= (reinterpret_cast(data)[pos]); - flowId = dstPort ^ srcPort ^ proto; - } - break; - } - } + if (etherType == ZT_ETHERTYPE_IPV4 && (len >= 20)) { + uint16_t srcPort = 0; + uint16_t dstPort = 0; + uint8_t proto = (reinterpret_cast(data)[9]); + const unsigned int headerLen = 4 * (reinterpret_cast(data)[0] & 0xf); + switch (proto) { + case 0x01: // ICMP + // flowId = 0x01; + break; + // All these start with 16-bit source and destination port in that order + case 0x06: // TCP + case 0x11: // UDP + case 0x84: // SCTP + case 0x88: // UDPLite + if (len > (headerLen + 4)) { + unsigned int pos = headerLen + 0; + srcPort = (reinterpret_cast(data)[pos++]) << 8; + srcPort |= (reinterpret_cast(data)[pos]); + pos++; + dstPort = (reinterpret_cast(data)[pos++]) << 8; + dstPort |= (reinterpret_cast(data)[pos]); + flowId = dstPort ^ srcPort ^ proto; + } + break; + } + } - if (etherType == ZT_ETHERTYPE_IPV6 && (len >= 40)) { - uint16_t srcPort = 0; - uint16_t dstPort = 0; - unsigned int pos; - unsigned int proto; - _ipv6GetPayload((const uint8_t *)data, len, pos, proto); - switch(proto) { - case 0x3A: // ICMPv6 - //flowId = 0x3A; - break; - // All these start with 16-bit source and destination port in that order - case 0x06: // TCP - case 0x11: // UDP - case 0x84: // SCTP - case 0x88: // UDPLite - if (len > (pos + 4)) { - srcPort = (reinterpret_cast(data)[pos++]) << 8; - srcPort |= (reinterpret_cast(data)[pos]); - pos++; - dstPort = (reinterpret_cast(data)[pos++]) << 8; - dstPort |= (reinterpret_cast(data)[pos]); - flowId = dstPort ^ srcPort ^ proto; - } - break; - default: - break; - } - } + if (etherType == ZT_ETHERTYPE_IPV6 && (len >= 40)) { + uint16_t srcPort = 0; + uint16_t dstPort = 0; + unsigned int pos; + unsigned int proto; + _ipv6GetPayload((const uint8_t*)data, len, pos, proto); + switch (proto) { + case 0x3A: // ICMPv6 + // flowId = 0x3A; + break; + // All these start with 16-bit source and destination port in that order + case 0x06: // TCP + case 0x11: // UDP + case 0x84: // SCTP + case 0x88: // UDPLite + if (len > (pos + 4)) { + srcPort = (reinterpret_cast(data)[pos++]) << 8; + srcPort |= (reinterpret_cast(data)[pos]); + pos++; + dstPort = (reinterpret_cast(data)[pos++]) << 8; + dstPort |= (reinterpret_cast(data)[pos]); + flowId = dstPort ^ srcPort ^ proto; + } + break; + default: + break; + } + } - if (to.isMulticast()) { - MulticastGroup multicastGroup(to,0); + if (to.isMulticast()) { + MulticastGroup multicastGroup(to, 0); - if (to.isBroadcast()) { - if ( (etherType == ZT_ETHERTYPE_ARP) && (len >= 28) && ((((const uint8_t *)data)[2] == 0x08)&&(((const uint8_t *)data)[3] == 0x00)&&(((const uint8_t *)data)[4] == 6)&&(((const uint8_t *)data)[5] == 4)&&(((const uint8_t *)data)[7] == 0x01)) ) { - /* IPv4 ARP is one of the few special cases that we impose upon what is - * otherwise a straightforward Ethernet switch emulation. Vanilla ARP - * is dumb old broadcast and simply doesn't scale. ZeroTier multicast - * groups have an additional field called ADI (additional distinguishing - * information) which was added specifically for ARP though it could - * be used for other things too. We then take ARP broadcasts and turn - * them into multicasts by stuffing the IP address being queried into - * the 32-bit ADI field. In practice this uses our multicast pub/sub - * system to implement a kind of extended/distributed ARP table. */ - multicastGroup = MulticastGroup::deriveMulticastGroupForAddressResolution(InetAddress(((const unsigned char *)data) + 24,4,0)); - } else if (!network->config().enableBroadcast()) { - // Don't transmit broadcasts if this network doesn't want them - RR->t->outgoingNetworkFrameDropped(tPtr,network,from,to,etherType,vlanId,len,"broadcast disabled"); - return; - } - } else if ((etherType == ZT_ETHERTYPE_IPV6)&&(len >= (40 + 8 + 16))) { - // IPv6 NDP emulation for certain very special patterns of private IPv6 addresses -- if enabled - if ((network->config().ndpEmulation())&&(reinterpret_cast(data)[6] == 0x3a)&&(reinterpret_cast(data)[40] == 0x87)) { // ICMPv6 neighbor solicitation - Address v6EmbeddedAddress; - const uint8_t *const pkt6 = reinterpret_cast(data) + 40 + 8; - const uint8_t *my6 = (const uint8_t *)0; + if (to.isBroadcast()) { + if ((etherType == ZT_ETHERTYPE_ARP) && (len >= 28) + && ((((const uint8_t*)data)[2] == 0x08) && (((const uint8_t*)data)[3] == 0x00) && (((const uint8_t*)data)[4] == 6) && (((const uint8_t*)data)[5] == 4) && (((const uint8_t*)data)[7] == 0x01))) { + /* IPv4 ARP is one of the few special cases that we impose upon what is + * otherwise a straightforward Ethernet switch emulation. Vanilla ARP + * is dumb old broadcast and simply doesn't scale. ZeroTier multicast + * groups have an additional field called ADI (additional distinguishing + * information) which was added specifically for ARP though it could + * be used for other things too. We then take ARP broadcasts and turn + * them into multicasts by stuffing the IP address being queried into + * the 32-bit ADI field. In practice this uses our multicast pub/sub + * system to implement a kind of extended/distributed ARP table. */ + multicastGroup = MulticastGroup::deriveMulticastGroupForAddressResolution(InetAddress(((const unsigned char*)data) + 24, 4, 0)); + } + else if (! network->config().enableBroadcast()) { + // Don't transmit broadcasts if this network doesn't want them + RR->t->outgoingNetworkFrameDropped(tPtr, network, from, to, etherType, vlanId, len, "broadcast disabled"); + return; + } + } + else if ((etherType == ZT_ETHERTYPE_IPV6) && (len >= (40 + 8 + 16))) { + // IPv6 NDP emulation for certain very special patterns of private IPv6 addresses -- if enabled + if ((network->config().ndpEmulation()) && (reinterpret_cast(data)[6] == 0x3a) && (reinterpret_cast(data)[40] == 0x87)) { // ICMPv6 neighbor solicitation + Address v6EmbeddedAddress; + const uint8_t* const pkt6 = reinterpret_cast(data) + 40 + 8; + const uint8_t* my6 = (const uint8_t*)0; - // ZT-RFC4193 address: fdNN:NNNN:NNNN:NNNN:NN99:93DD:DDDD:DDDD / 88 (one /128 per actual host) + // ZT-RFC4193 address: fdNN:NNNN:NNNN:NNNN:NN99:93DD:DDDD:DDDD / 88 (one /128 per actual host) - // ZT-6PLANE address: fcXX:XXXX:XXDD:DDDD:DDDD:####:####:#### / 40 (one /80 per actual host) - // (XX - lower 32 bits of network ID XORed with higher 32 bits) + // ZT-6PLANE address: fcXX:XXXX:XXDD:DDDD:DDDD:####:####:#### / 40 (one /80 per actual host) + // (XX - lower 32 bits of network ID XORed with higher 32 bits) - // For these to work, we must have a ZT-managed address assigned in one of the - // above formats, and the query must match its prefix. - for(unsigned int sipk=0;sipkconfig().staticIpCount;++sipk) { - const InetAddress *const sip = &(network->config().staticIps[sipk]); - if (sip->ss_family == AF_INET6) { - my6 = reinterpret_cast(reinterpret_cast(&(*sip))->sin6_addr.s6_addr); - const unsigned int sipNetmaskBits = Utils::ntoh((uint16_t)reinterpret_cast(&(*sip))->sin6_port); - if ((sipNetmaskBits == 88)&&(my6[0] == 0xfd)&&(my6[9] == 0x99)&&(my6[10] == 0x93)) { // ZT-RFC4193 /88 ??? - unsigned int ptr = 0; - while (ptr != 11) { - if (pkt6[ptr] != my6[ptr]) { - break; - } - ++ptr; - } - if (ptr == 11) { // prefix match! - v6EmbeddedAddress.setTo(pkt6 + ptr,5); - break; - } - } else if (sipNetmaskBits == 40) { // ZT-6PLANE /40 ??? - const uint32_t nwid32 = (uint32_t)((network->id() ^ (network->id() >> 32)) & 0xffffffff); - if ( (my6[0] == 0xfc) && (my6[1] == (uint8_t)((nwid32 >> 24) & 0xff)) && (my6[2] == (uint8_t)((nwid32 >> 16) & 0xff)) && (my6[3] == (uint8_t)((nwid32 >> 8) & 0xff)) && (my6[4] == (uint8_t)(nwid32 & 0xff))) { - unsigned int ptr = 0; - while (ptr != 5) { - if (pkt6[ptr] != my6[ptr]) { - break; - } - ++ptr; - } - if (ptr == 5) { // prefix match! - v6EmbeddedAddress.setTo(pkt6 + ptr,5); - break; - } - } - } - } - } + // For these to work, we must have a ZT-managed address assigned in one of the + // above formats, and the query must match its prefix. + for (unsigned int sipk = 0; sipk < network->config().staticIpCount; ++sipk) { + const InetAddress* const sip = &(network->config().staticIps[sipk]); + if (sip->ss_family == AF_INET6) { + my6 = reinterpret_cast(reinterpret_cast(&(*sip))->sin6_addr.s6_addr); + const unsigned int sipNetmaskBits = Utils::ntoh((uint16_t)reinterpret_cast(&(*sip))->sin6_port); + if ((sipNetmaskBits == 88) && (my6[0] == 0xfd) && (my6[9] == 0x99) && (my6[10] == 0x93)) { // ZT-RFC4193 /88 ??? + unsigned int ptr = 0; + while (ptr != 11) { + if (pkt6[ptr] != my6[ptr]) { + break; + } + ++ptr; + } + if (ptr == 11) { // prefix match! + v6EmbeddedAddress.setTo(pkt6 + ptr, 5); + break; + } + } + else if (sipNetmaskBits == 40) { // ZT-6PLANE /40 ??? + const uint32_t nwid32 = (uint32_t)((network->id() ^ (network->id() >> 32)) & 0xffffffff); + if ((my6[0] == 0xfc) && (my6[1] == (uint8_t)((nwid32 >> 24) & 0xff)) && (my6[2] == (uint8_t)((nwid32 >> 16) & 0xff)) && (my6[3] == (uint8_t)((nwid32 >> 8) & 0xff)) && (my6[4] == (uint8_t)(nwid32 & 0xff))) { + unsigned int ptr = 0; + while (ptr != 5) { + if (pkt6[ptr] != my6[ptr]) { + break; + } + ++ptr; + } + if (ptr == 5) { // prefix match! + v6EmbeddedAddress.setTo(pkt6 + ptr, 5); + break; + } + } + } + } + } - if ((v6EmbeddedAddress)&&(v6EmbeddedAddress != RR->identity.address())) { - const MAC peerMac(v6EmbeddedAddress,network->id()); + if ((v6EmbeddedAddress) && (v6EmbeddedAddress != RR->identity.address())) { + const MAC peerMac(v6EmbeddedAddress, network->id()); - uint8_t adv[72]; - adv[0] = 0x60; - adv[1] = 0x00; - adv[2] = 0x00; - adv[3] = 0x00; - adv[4] = 0x00; - adv[5] = 0x20; - adv[6] = 0x3a; - adv[7] = 0xff; - for(int i=0;i<16;++i) { - adv[8 + i] = pkt6[i]; - } - for(int i=0;i<16;++i) { - adv[24 + i] = my6[i]; - } - adv[40] = 0x88; - adv[41] = 0x00; - adv[42] = 0x00; - adv[43] = 0x00; // future home of checksum - adv[44] = 0x60; - adv[45] = 0x00; - adv[46] = 0x00; - adv[47] = 0x00; - for(int i=0;i<16;++i) { - adv[48 + i] = pkt6[i]; - } - adv[64] = 0x02; - adv[65] = 0x01; - adv[66] = peerMac[0]; - adv[67] = peerMac[1]; - adv[68] = peerMac[2]; - adv[69] = peerMac[3]; - adv[70] = peerMac[4]; - adv[71] = peerMac[5]; + uint8_t adv[72]; + adv[0] = 0x60; + adv[1] = 0x00; + adv[2] = 0x00; + adv[3] = 0x00; + adv[4] = 0x00; + adv[5] = 0x20; + adv[6] = 0x3a; + adv[7] = 0xff; + for (int i = 0; i < 16; ++i) { + adv[8 + i] = pkt6[i]; + } + for (int i = 0; i < 16; ++i) { + adv[24 + i] = my6[i]; + } + adv[40] = 0x88; + adv[41] = 0x00; + adv[42] = 0x00; + adv[43] = 0x00; // future home of checksum + adv[44] = 0x60; + adv[45] = 0x00; + adv[46] = 0x00; + adv[47] = 0x00; + for (int i = 0; i < 16; ++i) { + adv[48 + i] = pkt6[i]; + } + adv[64] = 0x02; + adv[65] = 0x01; + adv[66] = peerMac[0]; + adv[67] = peerMac[1]; + adv[68] = peerMac[2]; + adv[69] = peerMac[3]; + adv[70] = peerMac[4]; + adv[71] = peerMac[5]; - uint16_t pseudo_[36]; - uint8_t *const pseudo = reinterpret_cast(pseudo_); - for(int i=0;i<32;++i) { - pseudo[i] = adv[8 + i]; - } - pseudo[32] = 0x00; - pseudo[33] = 0x00; - pseudo[34] = 0x00; - pseudo[35] = 0x20; - pseudo[36] = 0x00; - pseudo[37] = 0x00; - pseudo[38] = 0x00; - pseudo[39] = 0x3a; - for(int i=0;i<32;++i) { - pseudo[40 + i] = adv[40 + i]; - } - uint32_t checksum = 0; - for(int i=0;i<36;++i) { - checksum += Utils::hton(pseudo_[i]); - } - while ((checksum >> 16)) { - checksum = (checksum & 0xffff) + (checksum >> 16); - } - checksum = ~checksum; - adv[42] = (checksum >> 8) & 0xff; - adv[43] = checksum & 0xff; + uint16_t pseudo_[36]; + uint8_t* const pseudo = reinterpret_cast(pseudo_); + for (int i = 0; i < 32; ++i) { + pseudo[i] = adv[8 + i]; + } + pseudo[32] = 0x00; + pseudo[33] = 0x00; + pseudo[34] = 0x00; + pseudo[35] = 0x20; + pseudo[36] = 0x00; + pseudo[37] = 0x00; + pseudo[38] = 0x00; + pseudo[39] = 0x3a; + for (int i = 0; i < 32; ++i) { + pseudo[40 + i] = adv[40 + i]; + } + uint32_t checksum = 0; + for (int i = 0; i < 36; ++i) { + checksum += Utils::hton(pseudo_[i]); + } + while ((checksum >> 16)) { + checksum = (checksum & 0xffff) + (checksum >> 16); + } + checksum = ~checksum; + adv[42] = (checksum >> 8) & 0xff; + adv[43] = checksum & 0xff; - // - // call on separate background thread - // this prevents problems related to trying to do rx while inside of doing tx, such as acquiring same lock recursively - // + // + // call on separate background thread + // this prevents problems related to trying to do rx while inside of doing tx, such as acquiring same lock recursively + // - std::thread([=]() { + std::thread([=]() { + RR->node->putFrame(tPtr, network->id(), network->userPtr(), peerMac, from, ZT_ETHERTYPE_IPV6, 0, adv, 72); + }).detach(); - RR->node->putFrame(tPtr, network->id(), network->userPtr(), peerMac, from, ZT_ETHERTYPE_IPV6, 0, adv, 72); + return; // NDP emulation done. We have forged a "fake" reply, so no need to send actual NDP query. + } // else no NDP emulation + } // else no NDP emulation + } - }).detach(); + // Check this after NDP emulation, since that has to be allowed in exactly this case + if (network->config().multicastLimit == 0) { + RR->t->outgoingNetworkFrameDropped(tPtr, network, from, to, etherType, vlanId, len, "multicast disabled"); + return; + } - return; // NDP emulation done. We have forged a "fake" reply, so no need to send actual NDP query. - } // else no NDP emulation - } // else no NDP emulation - } + /* Learn multicast groups for bridged-in hosts. + * Note that some OSes, most notably Linux, do this for you by learning + * multicast addresses on bridge interfaces and subscribing each slave. + * But in that case this does no harm, as the sets are just merged. */ + if (fromBridged) { + network->learnBridgedMulticastGroup(tPtr, multicastGroup, RR->node->now()); + } - // Check this after NDP emulation, since that has to be allowed in exactly this case - if (network->config().multicastLimit == 0) { - RR->t->outgoingNetworkFrameDropped(tPtr,network,from,to,etherType,vlanId,len,"multicast disabled"); - return; - } + // First pass sets noTee to false, but noTee is set to true in OutboundMulticast to prevent duplicates. + if (! network->filterOutgoingPacket(tPtr, false, RR->identity.address(), Address(), from, to, (const uint8_t*)data, len, etherType, vlanId, qosBucket)) { + RR->t->outgoingNetworkFrameDropped(tPtr, network, from, to, etherType, vlanId, len, "filter blocked"); + return; + } - /* Learn multicast groups for bridged-in hosts. - * Note that some OSes, most notably Linux, do this for you by learning - * multicast addresses on bridge interfaces and subscribing each slave. - * But in that case this does no harm, as the sets are just merged. */ - if (fromBridged) { - network->learnBridgedMulticastGroup(tPtr,multicastGroup,RR->node->now()); - } + RR->mc->send(tPtr, RR->node->now(), network, Address(), multicastGroup, (fromBridged) ? from : MAC(), etherType, data, len); + } + else if (to == network->mac()) { + // Destination is this node, so just reinject it - // First pass sets noTee to false, but noTee is set to true in OutboundMulticast to prevent duplicates. - if (!network->filterOutgoingPacket(tPtr,false,RR->identity.address(),Address(),from,to,(const uint8_t *)data,len,etherType,vlanId,qosBucket)) { - RR->t->outgoingNetworkFrameDropped(tPtr,network,from,to,etherType,vlanId,len,"filter blocked"); - return; - } + // + // same pattern as putFrame call above + // + std::thread([=]() { + RR->node->putFrame(tPtr, network->id(), network->userPtr(), from, to, etherType, vlanId, data, len); + }).detach(); + } + else if (to[0] == MAC::firstOctetForNetwork(network->id())) { + // Destination is another ZeroTier peer on the same network - RR->mc->send( - tPtr, - RR->node->now(), - network, - Address(), - multicastGroup, - (fromBridged) ? from : MAC(), - etherType, - data, - len); - } else if (to == network->mac()) { + Address toZT(to.toAddress(network->id())); // since in-network MACs are derived from addresses and network IDs, we can reverse this + SharedPtr toPeer(RR->topology->getPeer(tPtr, toZT)); - // Destination is this node, so just reinject it + if (! network->filterOutgoingPacket(tPtr, false, RR->identity.address(), toZT, from, to, (const uint8_t*)data, len, etherType, vlanId, qosBucket)) { + RR->t->outgoingNetworkFrameDropped(tPtr, network, from, to, etherType, vlanId, len, "filter blocked"); + return; + } - // - // same pattern as putFrame call above - // - std::thread([=]() { + network->pushCredentialsIfNeeded(tPtr, toZT, RR->node->now()); - RR->node->putFrame(tPtr, network->id(), network->userPtr(), from, to, etherType, vlanId, data, len); + if (! fromBridged) { + Packet outp(toZT, RR->identity.address(), Packet::VERB_FRAME); + outp.append(network->id()); + outp.append((uint16_t)etherType); + outp.append(data, len); + // 1.4.8: disable compression for unicast as it almost never helps + // if (!network->config().disableCompression()) + // outp.compress(); + aqm_enqueue(tPtr, network, outp, true, qosBucket, flowId); + } + else { + Packet outp(toZT, RR->identity.address(), Packet::VERB_EXT_FRAME); + outp.append(network->id()); + outp.append((unsigned char)0x00); + to.appendTo(outp); + from.appendTo(outp); + outp.append((uint16_t)etherType); + outp.append(data, len); + // 1.4.8: disable compression for unicast as it almost never helps + // if (!network->config().disableCompression()) + // outp.compress(); + aqm_enqueue(tPtr, network, outp, true, qosBucket, flowId); + } + } + else { + // Destination is bridged behind a remote peer - }).detach(); + // We filter with a NULL destination ZeroTier address first. Filtrations + // for each ZT destination are also done below. This is the same rationale + // and design as for multicast. + if (! network->filterOutgoingPacket(tPtr, false, RR->identity.address(), Address(), from, to, (const uint8_t*)data, len, etherType, vlanId, qosBucket)) { + RR->t->outgoingNetworkFrameDropped(tPtr, network, from, to, etherType, vlanId, len, "filter blocked"); + return; + } - } else if (to[0] == MAC::firstOctetForNetwork(network->id())) { - // Destination is another ZeroTier peer on the same network + Address bridges[ZT_MAX_BRIDGE_SPAM]; + unsigned int numBridges = 0; - Address toZT(to.toAddress(network->id())); // since in-network MACs are derived from addresses and network IDs, we can reverse this - SharedPtr toPeer(RR->topology->getPeer(tPtr,toZT)); + /* Create an array of up to ZT_MAX_BRIDGE_SPAM recipients for this bridged frame. */ + bridges[0] = network->findBridgeTo(to); + std::vector
activeBridges(network->config().activeBridges()); + if ((bridges[0]) && (bridges[0] != RR->identity.address()) && (network->config().permitsBridging(bridges[0]))) { + /* We have a known bridge route for this MAC, send it there. */ + ++numBridges; + } + else if (! activeBridges.empty()) { + /* If there is no known route, spam to up to ZT_MAX_BRIDGE_SPAM active + * bridges. If someone responds, we'll learn the route. */ + std::vector
::const_iterator ab(activeBridges.begin()); + if (activeBridges.size() <= ZT_MAX_BRIDGE_SPAM) { + // If there are <= ZT_MAX_BRIDGE_SPAM active bridges, spam them all + while (ab != activeBridges.end()) { + bridges[numBridges++] = *ab; + ++ab; + } + } + else { + // Otherwise pick a random set of them + while (numBridges < ZT_MAX_BRIDGE_SPAM) { + if (ab == activeBridges.end()) { + ab = activeBridges.begin(); + } + if (((unsigned long)RR->node->prng() % (unsigned long)activeBridges.size()) == 0) { + bridges[numBridges++] = *ab; + ++ab; + } + else { + ++ab; + } + } + } + } - if (!network->filterOutgoingPacket(tPtr,false,RR->identity.address(),toZT,from,to,(const uint8_t *)data,len,etherType,vlanId,qosBucket)) { - RR->t->outgoingNetworkFrameDropped(tPtr,network,from,to,etherType,vlanId,len,"filter blocked"); - return; - } - - network->pushCredentialsIfNeeded(tPtr,toZT,RR->node->now()); - - if (!fromBridged) { - Packet outp(toZT,RR->identity.address(),Packet::VERB_FRAME); - outp.append(network->id()); - outp.append((uint16_t)etherType); - outp.append(data,len); - // 1.4.8: disable compression for unicast as it almost never helps - //if (!network->config().disableCompression()) - // outp.compress(); - aqm_enqueue(tPtr,network,outp,true,qosBucket,flowId); - } else { - Packet outp(toZT,RR->identity.address(),Packet::VERB_EXT_FRAME); - outp.append(network->id()); - outp.append((unsigned char)0x00); - to.appendTo(outp); - from.appendTo(outp); - outp.append((uint16_t)etherType); - outp.append(data,len); - // 1.4.8: disable compression for unicast as it almost never helps - //if (!network->config().disableCompression()) - // outp.compress(); - aqm_enqueue(tPtr,network,outp,true,qosBucket,flowId); - } - } else { - // Destination is bridged behind a remote peer - - // We filter with a NULL destination ZeroTier address first. Filtrations - // for each ZT destination are also done below. This is the same rationale - // and design as for multicast. - if (!network->filterOutgoingPacket(tPtr,false,RR->identity.address(),Address(),from,to,(const uint8_t *)data,len,etherType,vlanId,qosBucket)) { - RR->t->outgoingNetworkFrameDropped(tPtr,network,from,to,etherType,vlanId,len,"filter blocked"); - return; - } - - Address bridges[ZT_MAX_BRIDGE_SPAM]; - unsigned int numBridges = 0; - - /* Create an array of up to ZT_MAX_BRIDGE_SPAM recipients for this bridged frame. */ - bridges[0] = network->findBridgeTo(to); - std::vector
activeBridges(network->config().activeBridges()); - if ((bridges[0])&&(bridges[0] != RR->identity.address())&&(network->config().permitsBridging(bridges[0]))) { - /* We have a known bridge route for this MAC, send it there. */ - ++numBridges; - } else if (!activeBridges.empty()) { - /* If there is no known route, spam to up to ZT_MAX_BRIDGE_SPAM active - * bridges. If someone responds, we'll learn the route. */ - std::vector
::const_iterator ab(activeBridges.begin()); - if (activeBridges.size() <= ZT_MAX_BRIDGE_SPAM) { - // If there are <= ZT_MAX_BRIDGE_SPAM active bridges, spam them all - while (ab != activeBridges.end()) { - bridges[numBridges++] = *ab; - ++ab; - } - } else { - // Otherwise pick a random set of them - while (numBridges < ZT_MAX_BRIDGE_SPAM) { - if (ab == activeBridges.end()) { - ab = activeBridges.begin(); - } - if (((unsigned long)RR->node->prng() % (unsigned long)activeBridges.size()) == 0) { - bridges[numBridges++] = *ab; - ++ab; - } else { - ++ab; - } - } - } - } - - for(unsigned int b=0;bfilterOutgoingPacket(tPtr,true,RR->identity.address(),bridges[b],from,to,(const uint8_t *)data,len,etherType,vlanId,qosBucket)) { - Packet outp(bridges[b],RR->identity.address(),Packet::VERB_EXT_FRAME); - outp.append(network->id()); - outp.append((uint8_t)0x00); - to.appendTo(outp); - from.appendTo(outp); - outp.append((uint16_t)etherType); - outp.append(data,len); - // 1.4.8: disable compression for unicast as it almost never helps - //if (!network->config().disableCompression()) - // outp.compress(); - aqm_enqueue(tPtr,network,outp,true,qosBucket,flowId); - } else { - RR->t->outgoingNetworkFrameDropped(tPtr,network,from,to,etherType,vlanId,len,"filter blocked (bridge replication)"); - } - } - } + for (unsigned int b = 0; b < numBridges; ++b) { + if (network->filterOutgoingPacket(tPtr, true, RR->identity.address(), bridges[b], from, to, (const uint8_t*)data, len, etherType, vlanId, qosBucket)) { + Packet outp(bridges[b], RR->identity.address(), Packet::VERB_EXT_FRAME); + outp.append(network->id()); + outp.append((uint8_t)0x00); + to.appendTo(outp); + from.appendTo(outp); + outp.append((uint16_t)etherType); + outp.append(data, len); + // 1.4.8: disable compression for unicast as it almost never helps + // if (!network->config().disableCompression()) + // outp.compress(); + aqm_enqueue(tPtr, network, outp, true, qosBucket, flowId); + } + else { + RR->t->outgoingNetworkFrameDropped(tPtr, network, from, to, etherType, vlanId, len, "filter blocked (bridge replication)"); + } + } + } } -void Switch::aqm_enqueue(void *tPtr, const SharedPtr &network, Packet &packet,bool encrypt,int qosBucket,int32_t flowId) +void Switch::aqm_enqueue(void* tPtr, const SharedPtr& network, Packet& packet, bool encrypt, int qosBucket, int32_t flowId) { - if(!network->qosEnabled()) { - send(tPtr, packet, encrypt, flowId); - return; - } - NetworkQoSControlBlock *nqcb = _netQueueControlBlock[network->id()]; - if (!nqcb) { - nqcb = new NetworkQoSControlBlock(); - _netQueueControlBlock[network->id()] = nqcb; - // Initialize ZT_QOS_NUM_BUCKETS queues and place them in the INACTIVE list - // These queues will be shuffled between the new/old/inactive lists by the enqueue/dequeue algorithm - for (int i=0; iinactiveQueues.push_back(new ManagedQueue(i)); - } - } - // Don't apply QoS scheduling to ZT protocol traffic - if (packet.verb() != Packet::VERB_FRAME && packet.verb() != Packet::VERB_EXT_FRAME) { - send(tPtr, packet, encrypt, flowId); - } + if (! network->qosEnabled()) { + send(tPtr, packet, encrypt, flowId); + return; + } + NetworkQoSControlBlock* nqcb = _netQueueControlBlock[network->id()]; + if (! nqcb) { + nqcb = new NetworkQoSControlBlock(); + _netQueueControlBlock[network->id()] = nqcb; + // Initialize ZT_QOS_NUM_BUCKETS queues and place them in the INACTIVE list + // These queues will be shuffled between the new/old/inactive lists by the enqueue/dequeue algorithm + for (int i = 0; i < ZT_AQM_NUM_BUCKETS; i++) { + nqcb->inactiveQueues.push_back(new ManagedQueue(i)); + } + } + // Don't apply QoS scheduling to ZT protocol traffic + if (packet.verb() != Packet::VERB_FRAME && packet.verb() != Packet::VERB_EXT_FRAME) { + send(tPtr, packet, encrypt, flowId); + } - _aqm_m.lock(); + _aqm_m.lock(); - // Enqueue packet and move queue to appropriate list + // Enqueue packet and move queue to appropriate list - const Address dest(packet.destination()); - TXQueueEntry *txEntry = new TXQueueEntry(dest,RR->node->now(),packet,encrypt,flowId); + const Address dest(packet.destination()); + TXQueueEntry* txEntry = new TXQueueEntry(dest, RR->node->now(), packet, encrypt, flowId); - ManagedQueue *selectedQueue = nullptr; - for (size_t i=0; ioldQueues.size()) { // search old queues first (I think this is best since old would imply most recent usage of the queue) - if (nqcb->oldQueues[i]->id == qosBucket) { - selectedQueue = nqcb->oldQueues[i]; - } - } - if (i < nqcb->newQueues.size()) { // search new queues (this would imply not often-used queues) - if (nqcb->newQueues[i]->id == qosBucket) { - selectedQueue = nqcb->newQueues[i]; - } - } - if (i < nqcb->inactiveQueues.size()) { // search inactive queues - if (nqcb->inactiveQueues[i]->id == qosBucket) { - selectedQueue = nqcb->inactiveQueues[i]; - // move queue to end of NEW queue list - selectedQueue->byteCredit = ZT_AQM_QUANTUM; - // DEBUG_INFO("moving q=%p from INACTIVE to NEW list", selectedQueue); - nqcb->newQueues.push_back(selectedQueue); - nqcb->inactiveQueues.erase(nqcb->inactiveQueues.begin() + i); - } - } - } - if (!selectedQueue) { - _aqm_m.unlock(); - return; - } + ManagedQueue* selectedQueue = nullptr; + for (size_t i = 0; i < ZT_AQM_NUM_BUCKETS; i++) { + if (i < nqcb->oldQueues.size()) { // search old queues first (I think this is best since old would imply most recent usage of the queue) + if (nqcb->oldQueues[i]->id == qosBucket) { + selectedQueue = nqcb->oldQueues[i]; + } + } + if (i < nqcb->newQueues.size()) { // search new queues (this would imply not often-used queues) + if (nqcb->newQueues[i]->id == qosBucket) { + selectedQueue = nqcb->newQueues[i]; + } + } + if (i < nqcb->inactiveQueues.size()) { // search inactive queues + if (nqcb->inactiveQueues[i]->id == qosBucket) { + selectedQueue = nqcb->inactiveQueues[i]; + // move queue to end of NEW queue list + selectedQueue->byteCredit = ZT_AQM_QUANTUM; + // DEBUG_INFO("moving q=%p from INACTIVE to NEW list", selectedQueue); + nqcb->newQueues.push_back(selectedQueue); + nqcb->inactiveQueues.erase(nqcb->inactiveQueues.begin() + i); + } + } + } + if (! selectedQueue) { + _aqm_m.unlock(); + return; + } - selectedQueue->q.push_back(txEntry); - selectedQueue->byteLength+=txEntry->packet.payloadLength(); - nqcb->_currEnqueuedPackets++; + selectedQueue->q.push_back(txEntry); + selectedQueue->byteLength += txEntry->packet.payloadLength(); + nqcb->_currEnqueuedPackets++; - // DEBUG_INFO("nq=%2lu, oq=%2lu, iq=%2lu, nqcb.size()=%3d, bucket=%2d, q=%p", nqcb->newQueues.size(), nqcb->oldQueues.size(), nqcb->inactiveQueues.size(), nqcb->_currEnqueuedPackets, qosBucket, selectedQueue); + // DEBUG_INFO("nq=%2lu, oq=%2lu, iq=%2lu, nqcb.size()=%3d, bucket=%2d, q=%p", nqcb->newQueues.size(), nqcb->oldQueues.size(), nqcb->inactiveQueues.size(), nqcb->_currEnqueuedPackets, qosBucket, selectedQueue); - // Drop a packet if necessary - ManagedQueue *selectedQueueToDropFrom = nullptr; - if (nqcb->_currEnqueuedPackets > ZT_AQM_MAX_ENQUEUED_PACKETS) { - // DEBUG_INFO("too many enqueued packets (%d), finding packet to drop", nqcb->_currEnqueuedPackets); - int maxQueueLength = 0; - for (size_t i=0; ioldQueues.size()) { - if (nqcb->oldQueues[i]->byteLength > maxQueueLength) { - maxQueueLength = nqcb->oldQueues[i]->byteLength; - selectedQueueToDropFrom = nqcb->oldQueues[i]; - } - } - if (i < nqcb->newQueues.size()) { - if (nqcb->newQueues[i]->byteLength > maxQueueLength) { - maxQueueLength = nqcb->newQueues[i]->byteLength; - selectedQueueToDropFrom = nqcb->newQueues[i]; - } - } - if (i < nqcb->inactiveQueues.size()) { - if (nqcb->inactiveQueues[i]->byteLength > maxQueueLength) { - maxQueueLength = nqcb->inactiveQueues[i]->byteLength; - selectedQueueToDropFrom = nqcb->inactiveQueues[i]; - } - } - } - if (selectedQueueToDropFrom) { - // DEBUG_INFO("dropping packet from head of largest queue (%d payload bytes)", maxQueueLength); - int sizeOfDroppedPacket = selectedQueueToDropFrom->q.front()->packet.payloadLength(); - delete selectedQueueToDropFrom->q.front(); - selectedQueueToDropFrom->q.pop_front(); - selectedQueueToDropFrom->byteLength-=sizeOfDroppedPacket; - nqcb->_currEnqueuedPackets--; - } - } - _aqm_m.unlock(); - aqm_dequeue(tPtr); + // Drop a packet if necessary + ManagedQueue* selectedQueueToDropFrom = nullptr; + if (nqcb->_currEnqueuedPackets > ZT_AQM_MAX_ENQUEUED_PACKETS) { + // DEBUG_INFO("too many enqueued packets (%d), finding packet to drop", nqcb->_currEnqueuedPackets); + int maxQueueLength = 0; + for (size_t i = 0; i < ZT_AQM_NUM_BUCKETS; i++) { + if (i < nqcb->oldQueues.size()) { + if (nqcb->oldQueues[i]->byteLength > maxQueueLength) { + maxQueueLength = nqcb->oldQueues[i]->byteLength; + selectedQueueToDropFrom = nqcb->oldQueues[i]; + } + } + if (i < nqcb->newQueues.size()) { + if (nqcb->newQueues[i]->byteLength > maxQueueLength) { + maxQueueLength = nqcb->newQueues[i]->byteLength; + selectedQueueToDropFrom = nqcb->newQueues[i]; + } + } + if (i < nqcb->inactiveQueues.size()) { + if (nqcb->inactiveQueues[i]->byteLength > maxQueueLength) { + maxQueueLength = nqcb->inactiveQueues[i]->byteLength; + selectedQueueToDropFrom = nqcb->inactiveQueues[i]; + } + } + } + if (selectedQueueToDropFrom) { + // DEBUG_INFO("dropping packet from head of largest queue (%d payload bytes)", maxQueueLength); + int sizeOfDroppedPacket = selectedQueueToDropFrom->q.front()->packet.payloadLength(); + delete selectedQueueToDropFrom->q.front(); + selectedQueueToDropFrom->q.pop_front(); + selectedQueueToDropFrom->byteLength -= sizeOfDroppedPacket; + nqcb->_currEnqueuedPackets--; + } + } + _aqm_m.unlock(); + aqm_dequeue(tPtr); } uint64_t Switch::control_law(uint64_t t, int count) { - return (uint64_t)(t + ZT_AQM_INTERVAL / sqrt(count)); + return (uint64_t)(t + ZT_AQM_INTERVAL / sqrt(count)); } -Switch::dqr Switch::dodequeue(ManagedQueue *q, uint64_t now) +Switch::dqr Switch::dodequeue(ManagedQueue* q, uint64_t now) { - dqr r; - r.ok_to_drop = false; - r.p = q->q.front(); + dqr r; + r.ok_to_drop = false; + r.p = q->q.front(); - if (r.p == NULL) { - q->first_above_time = 0; - return r; - } - uint64_t sojourn_time = now - r.p->creationTime; - if (sojourn_time < ZT_AQM_TARGET || q->byteLength <= ZT_DEFAULT_MTU) { - // went below - stay below for at least interval - q->first_above_time = 0; - } else { - if (q->first_above_time == 0) { - // just went above from below. if still above at - // first_above_time, will say it's ok to drop. - q->first_above_time = now + ZT_AQM_INTERVAL; - } else if (now >= q->first_above_time) { - r.ok_to_drop = true; - } - } - return r; + if (r.p == NULL) { + q->first_above_time = 0; + return r; + } + uint64_t sojourn_time = now - r.p->creationTime; + if (sojourn_time < ZT_AQM_TARGET || q->byteLength <= ZT_DEFAULT_MTU) { + // went below - stay below for at least interval + q->first_above_time = 0; + } + else { + if (q->first_above_time == 0) { + // just went above from below. if still above at + // first_above_time, will say it's ok to drop. + q->first_above_time = now + ZT_AQM_INTERVAL; + } + else if (now >= q->first_above_time) { + r.ok_to_drop = true; + } + } + return r; } -Switch::TXQueueEntry * Switch::CoDelDequeue(ManagedQueue *q, bool isNew, uint64_t now) +Switch::TXQueueEntry* Switch::CoDelDequeue(ManagedQueue* q, bool isNew, uint64_t now) { - dqr r = dodequeue(q, now); + dqr r = dodequeue(q, now); - if (q->dropping) { - if (!r.ok_to_drop) { - q->dropping = false; - } - while (now >= q->drop_next && q->dropping) { - q->q.pop_front(); // drop - r = dodequeue(q, now); - if (!r.ok_to_drop) { - // leave dropping state - q->dropping = false; - } else { - ++(q->count); - // schedule the next drop. - q->drop_next = control_law(q->drop_next, q->count); - } - } - } else if (r.ok_to_drop) { - q->q.pop_front(); // drop - r = dodequeue(q, now); - q->dropping = true; - q->count = (q->count > 2 && now - q->drop_next < 8*ZT_AQM_INTERVAL)? - q->count - 2 : 1; - q->drop_next = control_law(now, q->count); - } - return r.p; + if (q->dropping) { + if (! r.ok_to_drop) { + q->dropping = false; + } + while (now >= q->drop_next && q->dropping) { + q->q.pop_front(); // drop + r = dodequeue(q, now); + if (! r.ok_to_drop) { + // leave dropping state + q->dropping = false; + } + else { + ++(q->count); + // schedule the next drop. + q->drop_next = control_law(q->drop_next, q->count); + } + } + } + else if (r.ok_to_drop) { + q->q.pop_front(); // drop + r = dodequeue(q, now); + q->dropping = true; + q->count = (q->count > 2 && now - q->drop_next < 8 * ZT_AQM_INTERVAL) ? q->count - 2 : 1; + q->drop_next = control_law(now, q->count); + } + return r.p; } -void Switch::aqm_dequeue(void *tPtr) +void Switch::aqm_dequeue(void* tPtr) { - // Cycle through network-specific QoS control blocks - for(std::map::iterator nqcb(_netQueueControlBlock.begin());nqcb!=_netQueueControlBlock.end();) { - if (!(*nqcb).second->_currEnqueuedPackets) { - return; - } + // Cycle through network-specific QoS control blocks + for (std::map::iterator nqcb(_netQueueControlBlock.begin()); nqcb != _netQueueControlBlock.end();) { + if (! (*nqcb).second->_currEnqueuedPackets) { + return; + } - uint64_t now = RR->node->now(); - TXQueueEntry *entryToEmit = nullptr; - std::vector *currQueues = &((*nqcb).second->newQueues); - std::vector *oldQueues = &((*nqcb).second->oldQueues); - std::vector *inactiveQueues = &((*nqcb).second->inactiveQueues); + uint64_t now = RR->node->now(); + TXQueueEntry* entryToEmit = nullptr; + std::vector* currQueues = &((*nqcb).second->newQueues); + std::vector* oldQueues = &((*nqcb).second->oldQueues); + std::vector* inactiveQueues = &((*nqcb).second->inactiveQueues); - _aqm_m.lock(); + _aqm_m.lock(); - // Attempt dequeue from queues in NEW list - bool examiningNewQueues = true; - while (currQueues->size()) { - ManagedQueue *queueAtFrontOfList = currQueues->front(); - if (queueAtFrontOfList->byteCredit < 0) { - queueAtFrontOfList->byteCredit += ZT_AQM_QUANTUM; - // Move to list of OLD queues - // DEBUG_INFO("moving q=%p from NEW to OLD list", queueAtFrontOfList); - oldQueues->push_back(queueAtFrontOfList); - currQueues->erase(currQueues->begin()); - } else { - entryToEmit = CoDelDequeue(queueAtFrontOfList, examiningNewQueues, now); - if (!entryToEmit) { - // Move to end of list of OLD queues - // DEBUG_INFO("moving q=%p from NEW to OLD list", queueAtFrontOfList); - oldQueues->push_back(queueAtFrontOfList); - currQueues->erase(currQueues->begin()); - } else { - int len = entryToEmit->packet.payloadLength(); - queueAtFrontOfList->byteLength -= len; - queueAtFrontOfList->byteCredit -= len; - // Send the packet! - queueAtFrontOfList->q.pop_front(); - send(tPtr, entryToEmit->packet, entryToEmit->encrypt, entryToEmit->flowId); - (*nqcb).second->_currEnqueuedPackets--; - } - if (queueAtFrontOfList) { - //DEBUG_INFO("dequeuing from q=%p, len=%lu in NEW list (byteCredit=%d)", queueAtFrontOfList, queueAtFrontOfList->q.size(), queueAtFrontOfList->byteCredit); - } - break; - } - } + // Attempt dequeue from queues in NEW list + bool examiningNewQueues = true; + while (currQueues->size()) { + ManagedQueue* queueAtFrontOfList = currQueues->front(); + if (queueAtFrontOfList->byteCredit < 0) { + queueAtFrontOfList->byteCredit += ZT_AQM_QUANTUM; + // Move to list of OLD queues + // DEBUG_INFO("moving q=%p from NEW to OLD list", queueAtFrontOfList); + oldQueues->push_back(queueAtFrontOfList); + currQueues->erase(currQueues->begin()); + } + else { + entryToEmit = CoDelDequeue(queueAtFrontOfList, examiningNewQueues, now); + if (! entryToEmit) { + // Move to end of list of OLD queues + // DEBUG_INFO("moving q=%p from NEW to OLD list", queueAtFrontOfList); + oldQueues->push_back(queueAtFrontOfList); + currQueues->erase(currQueues->begin()); + } + else { + int len = entryToEmit->packet.payloadLength(); + queueAtFrontOfList->byteLength -= len; + queueAtFrontOfList->byteCredit -= len; + // Send the packet! + queueAtFrontOfList->q.pop_front(); + send(tPtr, entryToEmit->packet, entryToEmit->encrypt, entryToEmit->flowId); + (*nqcb).second->_currEnqueuedPackets--; + } + if (queueAtFrontOfList) { + // DEBUG_INFO("dequeuing from q=%p, len=%lu in NEW list (byteCredit=%d)", queueAtFrontOfList, queueAtFrontOfList->q.size(), queueAtFrontOfList->byteCredit); + } + break; + } + } - // Attempt dequeue from queues in OLD list - examiningNewQueues = false; - currQueues = &((*nqcb).second->oldQueues); - while (currQueues->size()) { - ManagedQueue *queueAtFrontOfList = currQueues->front(); - if (queueAtFrontOfList->byteCredit < 0) { - queueAtFrontOfList->byteCredit += ZT_AQM_QUANTUM; - oldQueues->push_back(queueAtFrontOfList); - currQueues->erase(currQueues->begin()); - } else { - entryToEmit = CoDelDequeue(queueAtFrontOfList, examiningNewQueues, now); - if (!entryToEmit) { - //DEBUG_INFO("moving q=%p from OLD to INACTIVE list", queueAtFrontOfList); - // Move to inactive list of queues - inactiveQueues->push_back(queueAtFrontOfList); - currQueues->erase(currQueues->begin()); - } else { - int len = entryToEmit->packet.payloadLength(); - queueAtFrontOfList->byteLength -= len; - queueAtFrontOfList->byteCredit -= len; - queueAtFrontOfList->q.pop_front(); - send(tPtr, entryToEmit->packet, entryToEmit->encrypt, entryToEmit->flowId); - (*nqcb).second->_currEnqueuedPackets--; - } - if (queueAtFrontOfList) { - //DEBUG_INFO("dequeuing from q=%p, len=%lu in OLD list (byteCredit=%d)", queueAtFrontOfList, queueAtFrontOfList->q.size(), queueAtFrontOfList->byteCredit); - } - break; - } - } - nqcb++; - _aqm_m.unlock(); - } + // Attempt dequeue from queues in OLD list + examiningNewQueues = false; + currQueues = &((*nqcb).second->oldQueues); + while (currQueues->size()) { + ManagedQueue* queueAtFrontOfList = currQueues->front(); + if (queueAtFrontOfList->byteCredit < 0) { + queueAtFrontOfList->byteCredit += ZT_AQM_QUANTUM; + oldQueues->push_back(queueAtFrontOfList); + currQueues->erase(currQueues->begin()); + } + else { + entryToEmit = CoDelDequeue(queueAtFrontOfList, examiningNewQueues, now); + if (! entryToEmit) { + // DEBUG_INFO("moving q=%p from OLD to INACTIVE list", queueAtFrontOfList); + // Move to inactive list of queues + inactiveQueues->push_back(queueAtFrontOfList); + currQueues->erase(currQueues->begin()); + } + else { + int len = entryToEmit->packet.payloadLength(); + queueAtFrontOfList->byteLength -= len; + queueAtFrontOfList->byteCredit -= len; + queueAtFrontOfList->q.pop_front(); + send(tPtr, entryToEmit->packet, entryToEmit->encrypt, entryToEmit->flowId); + (*nqcb).second->_currEnqueuedPackets--; + } + if (queueAtFrontOfList) { + // DEBUG_INFO("dequeuing from q=%p, len=%lu in OLD list (byteCredit=%d)", queueAtFrontOfList, queueAtFrontOfList->q.size(), queueAtFrontOfList->byteCredit); + } + break; + } + } + nqcb++; + _aqm_m.unlock(); + } } void Switch::removeNetworkQoSControlBlock(uint64_t nwid) { - NetworkQoSControlBlock *nq = _netQueueControlBlock[nwid]; - if (nq) { - _netQueueControlBlock.erase(nwid); - delete nq; - nq = NULL; - } + NetworkQoSControlBlock* nq = _netQueueControlBlock[nwid]; + if (nq) { + _netQueueControlBlock.erase(nwid); + delete nq; + nq = NULL; + } } -void Switch::send(void *tPtr,Packet &packet,bool encrypt,int32_t flowId) +void Switch::send(void* tPtr, Packet& packet, bool encrypt, int32_t flowId) { - const Address dest(packet.destination()); - if (dest == RR->identity.address()) { - return; - } - _recordOutgoingPacketMetrics(packet); - if (!_trySend(tPtr,packet,encrypt,flowId)) { - { - Mutex::Lock _l(_txQueue_m); - if (_txQueue.size() >= ZT_TX_QUEUE_SIZE) { - _txQueue.pop_front(); - } - _txQueue.push_back(TXQueueEntry(dest,RR->node->now(),packet,encrypt,flowId)); - } - if (!RR->topology->getPeer(tPtr,dest)) { - requestWhois(tPtr,RR->node->now(),dest); - } - } + const Address dest(packet.destination()); + if (dest == RR->identity.address()) { + return; + } + _recordOutgoingPacketMetrics(packet); + if (! _trySend(tPtr, packet, encrypt, flowId)) { + { + Mutex::Lock _l(_txQueue_m); + if (_txQueue.size() >= ZT_TX_QUEUE_SIZE) { + _txQueue.pop_front(); + } + _txQueue.push_back(TXQueueEntry(dest, RR->node->now(), packet, encrypt, flowId)); + } + if (! RR->topology->getPeer(tPtr, dest)) { + requestWhois(tPtr, RR->node->now(), dest); + } + } } -void Switch::requestWhois(void *tPtr,const int64_t now,const Address &addr) +void Switch::requestWhois(void* tPtr, const int64_t now, const Address& addr) { - if (addr == RR->identity.address()) { - return; - } + if (addr == RR->identity.address()) { + return; + } - { - Mutex::Lock _l(_lastSentWhoisRequest_m); - int64_t &last = _lastSentWhoisRequest[addr]; - if ((now - last) < ZT_WHOIS_RETRY_DELAY) { - return; - } else { - last = now; - } - } + { + Mutex::Lock _l(_lastSentWhoisRequest_m); + int64_t& last = _lastSentWhoisRequest[addr]; + if ((now - last) < ZT_WHOIS_RETRY_DELAY) { + return; + } + else { + last = now; + } + } - const SharedPtr upstream(RR->topology->getUpstreamPeer()); - if (upstream) { - int32_t flowId = ZT_QOS_NO_FLOW; - Packet outp(upstream->address(),RR->identity.address(),Packet::VERB_WHOIS); - addr.appendTo(outp); - send(tPtr,outp,true,flowId); - } + const SharedPtr upstream(RR->topology->getUpstreamPeer()); + if (upstream) { + int32_t flowId = ZT_QOS_NO_FLOW; + Packet outp(upstream->address(), RR->identity.address(), Packet::VERB_WHOIS); + addr.appendTo(outp); + send(tPtr, outp, true, flowId); + } } -void Switch::doAnythingWaitingForPeer(void *tPtr,const SharedPtr &peer) +void Switch::doAnythingWaitingForPeer(void* tPtr, const SharedPtr& peer) { - { - Mutex::Lock _l(_lastSentWhoisRequest_m); - _lastSentWhoisRequest.erase(peer->address()); - } + { + Mutex::Lock _l(_lastSentWhoisRequest_m); + _lastSentWhoisRequest.erase(peer->address()); + } - const int64_t now = RR->node->now(); - for(unsigned int ptr=0;ptrlock); - if ((rq->timestamp)&&(rq->complete)) { - if ((rq->frag0.tryDecode(RR,tPtr,rq->flowId))||((now - rq->timestamp) > ZT_RECEIVE_QUEUE_TIMEOUT)) { - rq->timestamp = 0; - } - } - } + const int64_t now = RR->node->now(); + for (unsigned int ptr = 0; ptr < ZT_RX_QUEUE_SIZE; ++ptr) { + RXQueueEntry* const rq = &(_rxQueue[ptr]); + Mutex::Lock rql(rq->lock); + if ((rq->timestamp) && (rq->complete)) { + if ((rq->frag0.tryDecode(RR, tPtr, rq->flowId)) || ((now - rq->timestamp) > ZT_RECEIVE_QUEUE_TIMEOUT)) { + rq->timestamp = 0; + } + } + } - { - Mutex::Lock _l(_txQueue_m); - for(std::list< TXQueueEntry >::iterator txi(_txQueue.begin());txi!=_txQueue.end();) { - if (txi->dest == peer->address()) { - if (_trySend(tPtr,txi->packet,txi->encrypt,txi->flowId)) { - _txQueue.erase(txi++); - } else { - ++txi; - } - } else { - ++txi; - } - } - } + { + Mutex::Lock _l(_txQueue_m); + for (std::list::iterator txi(_txQueue.begin()); txi != _txQueue.end();) { + if (txi->dest == peer->address()) { + if (_trySend(tPtr, txi->packet, txi->encrypt, txi->flowId)) { + _txQueue.erase(txi++); + } + else { + ++txi; + } + } + else { + ++txi; + } + } + } } -unsigned long Switch::doTimerTasks(void *tPtr,int64_t now) +unsigned long Switch::doTimerTasks(void* tPtr, int64_t now) { - const uint64_t timeSinceLastCheck = now - _lastCheckedQueues; - if (timeSinceLastCheck < ZT_WHOIS_RETRY_DELAY) { - return (unsigned long)(ZT_WHOIS_RETRY_DELAY - timeSinceLastCheck); - } - _lastCheckedQueues = now; + const uint64_t timeSinceLastCheck = now - _lastCheckedQueues; + if (timeSinceLastCheck < ZT_WHOIS_RETRY_DELAY) { + return (unsigned long)(ZT_WHOIS_RETRY_DELAY - timeSinceLastCheck); + } + _lastCheckedQueues = now; - std::vector
needWhois; - { - Mutex::Lock _l(_txQueue_m); + std::vector
needWhois; + { + Mutex::Lock _l(_txQueue_m); - for(std::list< TXQueueEntry >::iterator txi(_txQueue.begin());txi!=_txQueue.end();) { - if (_trySend(tPtr,txi->packet,txi->encrypt,txi->flowId)) { - _txQueue.erase(txi++); - } else if ((now - txi->creationTime) > ZT_TRANSMIT_QUEUE_TIMEOUT) { - _txQueue.erase(txi++); - } else { - if (!RR->topology->getPeer(tPtr,txi->dest)) { - needWhois.push_back(txi->dest); - } - ++txi; - } - } - } - for(std::vector
::const_iterator i(needWhois.begin());i!=needWhois.end();++i) { - requestWhois(tPtr,now,*i); - } + for (std::list::iterator txi(_txQueue.begin()); txi != _txQueue.end();) { + if (_trySend(tPtr, txi->packet, txi->encrypt, txi->flowId)) { + _txQueue.erase(txi++); + } + else if ((now - txi->creationTime) > ZT_TRANSMIT_QUEUE_TIMEOUT) { + _txQueue.erase(txi++); + } + else { + if (! RR->topology->getPeer(tPtr, txi->dest)) { + needWhois.push_back(txi->dest); + } + ++txi; + } + } + } + for (std::vector
::const_iterator i(needWhois.begin()); i != needWhois.end(); ++i) { + requestWhois(tPtr, now, *i); + } - for(unsigned int ptr=0;ptrlock); - if ((rq->timestamp)&&(rq->complete)) { - if ((rq->frag0.tryDecode(RR,tPtr,rq->flowId))||((now - rq->timestamp) > ZT_RECEIVE_QUEUE_TIMEOUT)) { - rq->timestamp = 0; - } else { - const Address src(rq->frag0.source()); - if (!RR->topology->getPeer(tPtr,src)) { - requestWhois(tPtr,now,src); - } - } - } - } + for (unsigned int ptr = 0; ptr < ZT_RX_QUEUE_SIZE; ++ptr) { + RXQueueEntry* const rq = &(_rxQueue[ptr]); + Mutex::Lock rql(rq->lock); + if ((rq->timestamp) && (rq->complete)) { + if ((rq->frag0.tryDecode(RR, tPtr, rq->flowId)) || ((now - rq->timestamp) > ZT_RECEIVE_QUEUE_TIMEOUT)) { + rq->timestamp = 0; + } + else { + const Address src(rq->frag0.source()); + if (! RR->topology->getPeer(tPtr, src)) { + requestWhois(tPtr, now, src); + } + } + } + } - { - Mutex::Lock _l(_lastUniteAttempt_m); - Hashtable< _LastUniteKey,uint64_t >::Iterator i(_lastUniteAttempt); - _LastUniteKey *k = (_LastUniteKey *)0; - uint64_t *v = (uint64_t *)0; - while (i.next(k,v)) { - if ((now - *v) >= (ZT_MIN_UNITE_INTERVAL * 8)) { - _lastUniteAttempt.erase(*k); - } - } - } + { + Mutex::Lock _l(_lastUniteAttempt_m); + Hashtable<_LastUniteKey, uint64_t>::Iterator i(_lastUniteAttempt); + _LastUniteKey* k = (_LastUniteKey*)0; + uint64_t* v = (uint64_t*)0; + while (i.next(k, v)) { + if ((now - *v) >= (ZT_MIN_UNITE_INTERVAL * 8)) { + _lastUniteAttempt.erase(*k); + } + } + } - { - Mutex::Lock _l(_lastSentWhoisRequest_m); - Hashtable< Address,int64_t >::Iterator i(_lastSentWhoisRequest); - Address *a = (Address *)0; - int64_t *ts = (int64_t *)0; - while (i.next(a,ts)) { - if ((now - *ts) > (ZT_WHOIS_RETRY_DELAY * 2)) { - _lastSentWhoisRequest.erase(*a); - } - } - } + { + Mutex::Lock _l(_lastSentWhoisRequest_m); + Hashtable::Iterator i(_lastSentWhoisRequest); + Address* a = (Address*)0; + int64_t* ts = (int64_t*)0; + while (i.next(a, ts)) { + if ((now - *ts) > (ZT_WHOIS_RETRY_DELAY * 2)) { + _lastSentWhoisRequest.erase(*a); + } + } + } - return ZT_WHOIS_RETRY_DELAY; + return ZT_WHOIS_RETRY_DELAY; } -bool Switch::_shouldUnite(const int64_t now,const Address &source,const Address &destination) +bool Switch::_shouldUnite(const int64_t now, const Address& source, const Address& destination) { - Mutex::Lock _l(_lastUniteAttempt_m); - uint64_t &ts = _lastUniteAttempt[_LastUniteKey(source,destination)]; - if ((now - ts) >= ZT_MIN_UNITE_INTERVAL) { - ts = now; - return true; - } - return false; + Mutex::Lock _l(_lastUniteAttempt_m); + uint64_t& ts = _lastUniteAttempt[_LastUniteKey(source, destination)]; + if ((now - ts) >= ZT_MIN_UNITE_INTERVAL) { + ts = now; + return true; + } + return false; } -bool Switch::_trySend(void *tPtr,Packet &packet,bool encrypt,int32_t flowId) +bool Switch::_trySend(void* tPtr, Packet& packet, bool encrypt, int32_t flowId) { - SharedPtr viaPath; - const int64_t now = RR->node->now(); - const Address destination(packet.destination()); + SharedPtr viaPath; + const int64_t now = RR->node->now(); + const Address destination(packet.destination()); - const SharedPtr peer(RR->topology->getPeer(tPtr,destination)); - if (peer) { - if ((peer->bondingPolicy() == ZT_BOND_POLICY_BROADCAST) - && (packet.verb() == Packet::VERB_FRAME || packet.verb() == Packet::VERB_EXT_FRAME)) { - const SharedPtr relay(RR->topology->getUpstreamPeer()); - Mutex::Lock _l(peer->_paths_m); - for(int i=0;i_paths[i].p && peer->_paths[i].p->alive(now)) { - uint16_t userSpecifiedMtu = peer->_paths[i].p->mtu(); - _sendViaSpecificPath(tPtr,peer,peer->_paths[i].p, userSpecifiedMtu,now,packet,encrypt,flowId); - } - } - return true; - } else { - viaPath = peer->getAppropriatePath(now,false,flowId); - if (!viaPath) { - peer->tryMemorizedPath(tPtr,now); // periodically attempt memorized or statically defined paths, if any are known - const SharedPtr relay(RR->topology->getUpstreamPeer()); - if ( (!relay) || (!(viaPath = relay->getAppropriatePath(now,false,flowId))) ) { - if (!(viaPath = peer->getAppropriatePath(now,true,flowId))) { - return false; - } - } - } - if (viaPath) { - uint16_t userSpecifiedMtu = viaPath->mtu(); - _sendViaSpecificPath(tPtr,peer,viaPath,userSpecifiedMtu,now,packet,encrypt,flowId); - return true; - } - } - } - return false; + const SharedPtr peer(RR->topology->getPeer(tPtr, destination)); + if (peer) { + if ((peer->bondingPolicy() == ZT_BOND_POLICY_BROADCAST) && (packet.verb() == Packet::VERB_FRAME || packet.verb() == Packet::VERB_EXT_FRAME)) { + const SharedPtr relay(RR->topology->getUpstreamPeer()); + Mutex::Lock _l(peer->_paths_m); + for (int i = 0; i < ZT_MAX_PEER_NETWORK_PATHS; ++i) { + if (peer->_paths[i].p && peer->_paths[i].p->alive(now)) { + uint16_t userSpecifiedMtu = peer->_paths[i].p->mtu(); + _sendViaSpecificPath(tPtr, peer, peer->_paths[i].p, userSpecifiedMtu, now, packet, encrypt, flowId); + } + } + return true; + } + else { + viaPath = peer->getAppropriatePath(now, false, flowId); + if (! viaPath) { + peer->tryMemorizedPath(tPtr, now); // periodically attempt memorized or statically defined paths, if any are known + const SharedPtr relay(RR->topology->getUpstreamPeer()); + if ((! relay) || (! (viaPath = relay->getAppropriatePath(now, false, flowId)))) { + if (! (viaPath = peer->getAppropriatePath(now, true, flowId))) { + return false; + } + } + } + if (viaPath) { + uint16_t userSpecifiedMtu = viaPath->mtu(); + _sendViaSpecificPath(tPtr, peer, viaPath, userSpecifiedMtu, now, packet, encrypt, flowId); + return true; + } + } + } + return false; } -void Switch::_sendViaSpecificPath(void *tPtr,SharedPtr peer,SharedPtr viaPath,uint16_t userSpecifiedMtu, int64_t now,Packet &packet,bool encrypt,int32_t flowId) +void Switch::_sendViaSpecificPath(void* tPtr, SharedPtr peer, SharedPtr viaPath, uint16_t userSpecifiedMtu, int64_t now, Packet& packet, bool encrypt, int32_t flowId) { - unsigned int mtu = ZT_DEFAULT_PHYSMTU; - uint64_t trustedPathId = 0; - RR->topology->getOutboundPathInfo(viaPath->address(),mtu,trustedPathId); + unsigned int mtu = ZT_DEFAULT_PHYSMTU; + uint64_t trustedPathId = 0; + RR->topology->getOutboundPathInfo(viaPath->address(), mtu, trustedPathId); - if (userSpecifiedMtu > 0) { - mtu = userSpecifiedMtu; - } - unsigned int chunkSize = std::min(packet.size(),mtu); - packet.setFragmented(chunkSize < packet.size()); + if (userSpecifiedMtu > 0) { + mtu = userSpecifiedMtu; + } + unsigned int chunkSize = std::min(packet.size(), mtu); + packet.setFragmented(chunkSize < packet.size()); - if (trustedPathId) { - packet.setTrusted(trustedPathId); - } else { - if (!packet.isEncrypted()) { - packet.armor(peer->key(),encrypt,peer->aesKeysIfSupported()); - } - RR->node->expectReplyTo(packet.packetId()); - } + if (trustedPathId) { + packet.setTrusted(trustedPathId); + } + else { + if (! packet.isEncrypted()) { + packet.armor(peer->key(), encrypt, false, peer->aesKeysIfSupported(), peer->identity()); + } + RR->node->expectReplyTo(packet.packetId()); + } - peer->recordOutgoingPacket(viaPath, packet.packetId(), packet.payloadLength(), packet.verb(), flowId, now); + peer->recordOutgoingPacket(viaPath, packet.packetId(), packet.payloadLength(), packet.verb(), flowId, now); - if (viaPath->send(RR,tPtr,packet.data(),chunkSize,now)) { - if (chunkSize < packet.size()) { - // Too big for one packet, fragment the rest - unsigned int fragStart = chunkSize; - unsigned int remaining = packet.size() - chunkSize; - unsigned int fragsRemaining = (remaining / (mtu - ZT_PROTO_MIN_FRAGMENT_LENGTH)); - if ((fragsRemaining * (mtu - ZT_PROTO_MIN_FRAGMENT_LENGTH)) < remaining) { - ++fragsRemaining; - } - const unsigned int totalFragments = fragsRemaining + 1; + if (viaPath->send(RR, tPtr, packet.data(), chunkSize, now)) { + if (chunkSize < packet.size()) { + // Too big for one packet, fragment the rest + unsigned int fragStart = chunkSize; + unsigned int remaining = packet.size() - chunkSize; + unsigned int fragsRemaining = (remaining / (mtu - ZT_PROTO_MIN_FRAGMENT_LENGTH)); + if ((fragsRemaining * (mtu - ZT_PROTO_MIN_FRAGMENT_LENGTH)) < remaining) { + ++fragsRemaining; + } + const unsigned int totalFragments = fragsRemaining + 1; - for(unsigned int fno=1;fnosend(RR,tPtr,frag.data(),frag.size(),now); - fragStart += chunkSize; - remaining -= chunkSize; - } - } - } + for (unsigned int fno = 1; fno < totalFragments; ++fno) { + chunkSize = std::min(remaining, (unsigned int)(mtu - ZT_PROTO_MIN_FRAGMENT_LENGTH)); + Packet::Fragment frag(packet, fragStart, chunkSize, fno, totalFragments); + viaPath->send(RR, tPtr, frag.data(), frag.size(), now); + fragStart += chunkSize; + remaining -= chunkSize; + } + } + } } -void Switch::_recordOutgoingPacketMetrics(const Packet &p) { - switch (p.verb()) { - case Packet::VERB_NOP: - Metrics::pkt_nop_out++; - break; - case Packet::VERB_HELLO: - Metrics::pkt_hello_out++; - break; - case Packet::VERB_ERROR: - Metrics::pkt_error_out++; - break; - case Packet::VERB_OK: - Metrics::pkt_ok_out++; - break; - case Packet::VERB_WHOIS: - Metrics::pkt_whois_out++; - break; - case Packet::VERB_RENDEZVOUS: - Metrics::pkt_rendezvous_out++; - break; - case Packet::VERB_FRAME: - Metrics::pkt_frame_out++; - break; - case Packet::VERB_EXT_FRAME: - Metrics::pkt_ext_frame_out++; - break; - case Packet::VERB_ECHO: - Metrics::pkt_echo_out++; - break; - case Packet::VERB_MULTICAST_LIKE: - Metrics::pkt_multicast_like_out++; - break; - case Packet::VERB_NETWORK_CREDENTIALS: - Metrics::pkt_network_credentials_out++; - break; - case Packet::VERB_NETWORK_CONFIG_REQUEST: - Metrics::pkt_network_config_request_out++; - break; - case Packet::VERB_NETWORK_CONFIG: - Metrics::pkt_network_config_out++; - break; - case Packet::VERB_MULTICAST_GATHER: - Metrics::pkt_multicast_gather_out++; - break; - case Packet::VERB_MULTICAST_FRAME: - Metrics::pkt_multicast_frame_out++; - break; - case Packet::VERB_PUSH_DIRECT_PATHS: - Metrics::pkt_push_direct_paths_out++; - break; - case Packet::VERB_ACK: - Metrics::pkt_ack_out++; - break; - case Packet::VERB_QOS_MEASUREMENT: - Metrics::pkt_qos_out++; - break; - case Packet::VERB_USER_MESSAGE: - Metrics::pkt_user_message_out++; - break; - case Packet::VERB_REMOTE_TRACE: - Metrics::pkt_remote_trace_out++; - break; - case Packet::VERB_PATH_NEGOTIATION_REQUEST: - Metrics::pkt_path_negotiation_request_out++; - break; - } +void Switch::_recordOutgoingPacketMetrics(const Packet& p) +{ + switch (p.verb()) { + case Packet::VERB_NOP: + Metrics::pkt_nop_out++; + break; + case Packet::VERB_HELLO: + Metrics::pkt_hello_out++; + break; + case Packet::VERB_ERROR: + Metrics::pkt_error_out++; + break; + case Packet::VERB_OK: + Metrics::pkt_ok_out++; + break; + case Packet::VERB_WHOIS: + Metrics::pkt_whois_out++; + break; + case Packet::VERB_RENDEZVOUS: + Metrics::pkt_rendezvous_out++; + break; + case Packet::VERB_FRAME: + Metrics::pkt_frame_out++; + break; + case Packet::VERB_EXT_FRAME: + Metrics::pkt_ext_frame_out++; + break; + case Packet::VERB_ECHO: + Metrics::pkt_echo_out++; + break; + case Packet::VERB_MULTICAST_LIKE: + Metrics::pkt_multicast_like_out++; + break; + case Packet::VERB_NETWORK_CREDENTIALS: + Metrics::pkt_network_credentials_out++; + break; + case Packet::VERB_NETWORK_CONFIG_REQUEST: + Metrics::pkt_network_config_request_out++; + break; + case Packet::VERB_NETWORK_CONFIG: + Metrics::pkt_network_config_out++; + break; + case Packet::VERB_MULTICAST_GATHER: + Metrics::pkt_multicast_gather_out++; + break; + case Packet::VERB_MULTICAST_FRAME: + Metrics::pkt_multicast_frame_out++; + break; + case Packet::VERB_PUSH_DIRECT_PATHS: + Metrics::pkt_push_direct_paths_out++; + break; + case Packet::VERB_ACK: + Metrics::pkt_ack_out++; + break; + case Packet::VERB_QOS_MEASUREMENT: + Metrics::pkt_qos_out++; + break; + case Packet::VERB_USER_MESSAGE: + Metrics::pkt_user_message_out++; + break; + case Packet::VERB_REMOTE_TRACE: + Metrics::pkt_remote_trace_out++; + break; + case Packet::VERB_PATH_NEGOTIATION_REQUEST: + Metrics::pkt_path_negotiation_request_out++; + break; + } } -} // namespace ZeroTier +} // namespace ZeroTier diff --git a/node/Switch.hpp b/node/Switch.hpp index 0fd98044..318e4587 100644 --- a/node/Switch.hpp +++ b/node/Switch.hpp @@ -14,32 +14,32 @@ #ifndef ZT_N_SWITCH_HPP #define ZT_N_SWITCH_HPP +#include "Constants.hpp" +#include "Hashtable.hpp" +#include "IncomingPacket.hpp" +#include "InetAddress.hpp" +#include "MAC.hpp" +#include "Mutex.hpp" +#include "Network.hpp" +#include "Packet.hpp" +#include "SharedPtr.hpp" +#include "Topology.hpp" +#include "Utils.hpp" + +#include #include #include #include -#include - -#include "Constants.hpp" -#include "Mutex.hpp" -#include "MAC.hpp" -#include "Packet.hpp" -#include "Utils.hpp" -#include "InetAddress.hpp" -#include "Topology.hpp" -#include "Network.hpp" -#include "SharedPtr.hpp" -#include "IncomingPacket.hpp" -#include "Hashtable.hpp" /* Ethernet frame types that might be relevant to us */ -#define ZT_ETHERTYPE_IPV4 0x0800 -#define ZT_ETHERTYPE_ARP 0x0806 -#define ZT_ETHERTYPE_RARP 0x8035 +#define ZT_ETHERTYPE_IPV4 0x0800 +#define ZT_ETHERTYPE_ARP 0x0806 +#define ZT_ETHERTYPE_RARP 0x8035 #define ZT_ETHERTYPE_ATALK 0x809b -#define ZT_ETHERTYPE_AARP 0x80f3 +#define ZT_ETHERTYPE_AARP 0x80f3 #define ZT_ETHERTYPE_IPX_A 0x8137 #define ZT_ETHERTYPE_IPX_B 0x8138 -#define ZT_ETHERTYPE_IPV6 0x86dd +#define ZT_ETHERTYPE_IPV6 0x86dd namespace ZeroTier { @@ -54,279 +54,280 @@ class Peer; * packets from tap devices, and this sends them where they need to go and * wraps/unwraps accordingly. It also handles queues and timeouts and such. */ -class Switch -{ - struct ManagedQueue; - struct TXQueueEntry; +class Switch { + struct ManagedQueue; + struct TXQueueEntry; - friend class SharedPtr; + friend class SharedPtr; - typedef struct { - TXQueueEntry *p; - bool ok_to_drop; - } dqr; + typedef struct { + TXQueueEntry* p; + bool ok_to_drop; + } dqr; -public: - Switch(const RuntimeEnvironment *renv); + public: + Switch(const RuntimeEnvironment* renv); - /** - * Called when a packet is received from the real network - * - * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call - * @param localSocket Local I/O socket as supplied by external code - * @param fromAddr Internet IP address of origin - * @param data Packet data - * @param len Packet length - */ - void onRemotePacket(void *tPtr,const int64_t localSocket,const InetAddress &fromAddr,const void *data,unsigned int len); + /** + * Called when a packet is received from the real network + * + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call + * @param localSocket Local I/O socket as supplied by external code + * @param fromAddr Internet IP address of origin + * @param data Packet data + * @param len Packet length + */ + void onRemotePacket(void* tPtr, const int64_t localSocket, const InetAddress& fromAddr, const void* data, unsigned int len); - /** - * Returns whether our bonding or balancing policy is aware of flows. - */ - bool isFlowAware(); + /** + * Returns whether our bonding or balancing policy is aware of flows. + */ + bool isFlowAware(); - /** - * Called when a packet comes from a local Ethernet tap - * - * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call - * @param network Which network's TAP did this packet come from? - * @param from Originating MAC address - * @param to Destination MAC address - * @param etherType Ethernet packet type - * @param vlanId VLAN ID or 0 if none - * @param data Ethernet payload - * @param len Frame length - */ - void onLocalEthernet(void *tPtr,const SharedPtr &network,const MAC &from,const MAC &to,unsigned int etherType,unsigned int vlanId,const void *data,unsigned int len); + /** + * Called when a packet comes from a local Ethernet tap + * + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call + * @param network Which network's TAP did this packet come from? + * @param from Originating MAC address + * @param to Destination MAC address + * @param etherType Ethernet packet type + * @param vlanId VLAN ID or 0 if none + * @param data Ethernet payload + * @param len Frame length + */ + void onLocalEthernet(void* tPtr, const SharedPtr& network, const MAC& from, const MAC& to, unsigned int etherType, unsigned int vlanId, const void* data, unsigned int len); - /** - * Determines the next drop schedule for packets in the TX queue - * - * @param t Current time - * @param count Number of packets dropped this round - */ - uint64_t control_law(uint64_t t, int count); + /** + * Determines the next drop schedule for packets in the TX queue + * + * @param t Current time + * @param count Number of packets dropped this round + */ + uint64_t control_law(uint64_t t, int count); - /** - * Selects a packet eligible for transmission from a TX queue. According to the control law, multiple packets - * may be intentionally dropped before a packet is returned to the AQM scheduler. - * - * @param q The TX queue that is being dequeued from - * @param now Current time - */ - dqr dodequeue(ManagedQueue *q, uint64_t now); + /** + * Selects a packet eligible for transmission from a TX queue. According to the control law, multiple packets + * may be intentionally dropped before a packet is returned to the AQM scheduler. + * + * @param q The TX queue that is being dequeued from + * @param now Current time + */ + dqr dodequeue(ManagedQueue* q, uint64_t now); - /** - * Presents a packet to the AQM scheduler. - * - * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call - * @param network Network that the packet shall be sent over - * @param packet Packet to be sent - * @param encrypt Encrypt packet payload? (always true except for HELLO) - * @param qosBucket Which bucket the rule-system determined this packet should fall into - */ - void aqm_enqueue(void *tPtr, const SharedPtr &network, Packet &packet,bool encrypt,int qosBucket,int32_t flowId = ZT_QOS_NO_FLOW); + /** + * Presents a packet to the AQM scheduler. + * + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call + * @param network Network that the packet shall be sent over + * @param packet Packet to be sent + * @param encrypt Encrypt packet payload? (always true except for HELLO) + * @param qosBucket Which bucket the rule-system determined this packet should fall into + */ + void aqm_enqueue(void* tPtr, const SharedPtr& network, Packet& packet, bool encrypt, int qosBucket, int32_t flowId = ZT_QOS_NO_FLOW); - /** - * Performs a single AQM cycle and dequeues and transmits all eligible packets on all networks - * - * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call - */ - void aqm_dequeue(void *tPtr); + /** + * Performs a single AQM cycle and dequeues and transmits all eligible packets on all networks + * + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call + */ + void aqm_dequeue(void* tPtr); - /** - * Calls the dequeue mechanism and adjust queue state variables - * - * @param q The TX queue that is being dequeued from - * @param isNew Whether or not this queue is in the NEW list - * @param now Current time - */ - Switch::TXQueueEntry * CoDelDequeue(ManagedQueue *q, bool isNew, uint64_t now); + /** + * Calls the dequeue mechanism and adjust queue state variables + * + * @param q The TX queue that is being dequeued from + * @param isNew Whether or not this queue is in the NEW list + * @param now Current time + */ + Switch::TXQueueEntry* CoDelDequeue(ManagedQueue* q, bool isNew, uint64_t now); - /** - * Removes QoS Queues and flow state variables for a specific network. These queues are created - * automatically upon the transmission of the first packet from this peer to another peer on the - * given network. - * - * The reason for existence of queues and flow state variables specific to each network is so that - * each network's QoS rules function independently. - * - * @param nwid Network ID - */ - void removeNetworkQoSControlBlock(uint64_t nwid); + /** + * Removes QoS Queues and flow state variables for a specific network. These queues are created + * automatically upon the transmission of the first packet from this peer to another peer on the + * given network. + * + * The reason for existence of queues and flow state variables specific to each network is so that + * each network's QoS rules function independently. + * + * @param nwid Network ID + */ + void removeNetworkQoSControlBlock(uint64_t nwid); - /** - * Send a packet to a ZeroTier address (destination in packet) - * - * The packet must be fully composed with source and destination but not - * yet encrypted. If the destination peer is known the packet - * is sent immediately. Otherwise it is queued and a WHOIS is dispatched. - * - * The packet may be compressed. Compression isn't done here. - * - * Needless to say, the packet's source must be this node. Otherwise it - * won't be encrypted right. (This is not used for relaying.) - * - * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call - * @param packet Packet to send (buffer may be modified) - * @param encrypt Encrypt packet payload? (always true except for HELLO) - */ - void send(void *tPtr,Packet &packet,bool encrypt,int32_t flowId = ZT_QOS_NO_FLOW); + /** + * Send a packet to a ZeroTier address (destination in packet) + * + * The packet must be fully composed with source and destination but not + * yet encrypted. If the destination peer is known the packet + * is sent immediately. Otherwise it is queued and a WHOIS is dispatched. + * + * The packet may be compressed. Compression isn't done here. + * + * Needless to say, the packet's source must be this node. Otherwise it + * won't be encrypted right. (This is not used for relaying.) + * + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call + * @param packet Packet to send (buffer may be modified) + * @param encrypt Encrypt packet payload? (always true except for HELLO) + */ + void send(void* tPtr, Packet& packet, bool encrypt, int32_t flowId = ZT_QOS_NO_FLOW); - /** - * Request WHOIS on a given address - * - * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call - * @param now Current time - * @param addr Address to look up - */ - void requestWhois(void *tPtr,const int64_t now,const Address &addr); + /** + * Request WHOIS on a given address + * + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call + * @param now Current time + * @param addr Address to look up + */ + void requestWhois(void* tPtr, const int64_t now, const Address& addr); - /** - * Run any processes that are waiting for this peer's identity - * - * Called when we learn of a peer's identity from HELLO, OK(WHOIS), etc. - * - * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call - * @param peer New peer - */ - void doAnythingWaitingForPeer(void *tPtr,const SharedPtr &peer); + /** + * Run any processes that are waiting for this peer's identity + * + * Called when we learn of a peer's identity from HELLO, OK(WHOIS), etc. + * + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call + * @param peer New peer + */ + void doAnythingWaitingForPeer(void* tPtr, const SharedPtr& peer); - /** - * Perform retries and other periodic timer tasks - * - * This can return a very long delay if there are no pending timer - * tasks. The caller should cap this comparatively vs. other values. - * - * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call - * @param now Current time - * @return Number of milliseconds until doTimerTasks() should be run again - */ - unsigned long doTimerTasks(void *tPtr,int64_t now); + /** + * Perform retries and other periodic timer tasks + * + * This can return a very long delay if there are no pending timer + * tasks. The caller should cap this comparatively vs. other values. + * + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call + * @param now Current time + * @return Number of milliseconds until doTimerTasks() should be run again + */ + unsigned long doTimerTasks(void* tPtr, int64_t now); -private: - bool _shouldUnite(const int64_t now,const Address &source,const Address &destination); - bool _trySend(void *tPtr,Packet &packet,bool encrypt,int32_t flowId = ZT_QOS_NO_FLOW); // packet is modified if return is true - void _sendViaSpecificPath(void *tPtr,SharedPtr peer,SharedPtr viaPath,uint16_t userSpecifiedMtu, int64_t now,Packet &packet,bool encrypt,int32_t flowId); - void _recordOutgoingPacketMetrics(const Packet &p); + private: + bool _shouldUnite(const int64_t now, const Address& source, const Address& destination); + bool _trySend(void* tPtr, Packet& packet, bool encrypt, int32_t flowId = ZT_QOS_NO_FLOW); // packet is modified if return is true + void _sendViaSpecificPath(void* tPtr, SharedPtr peer, SharedPtr viaPath, uint16_t userSpecifiedMtu, int64_t now, Packet& packet, bool encrypt, int32_t flowId); + void _recordOutgoingPacketMetrics(const Packet& p); - const RuntimeEnvironment *const RR; - int64_t _lastBeaconResponse; - volatile int64_t _lastCheckedQueues; + const RuntimeEnvironment* const RR; + int64_t _lastBeaconResponse; + volatile int64_t _lastCheckedQueues; - // Time we last sent a WHOIS request for each address - Hashtable< Address,int64_t > _lastSentWhoisRequest; - Mutex _lastSentWhoisRequest_m; + // Time we last sent a WHOIS request for each address + Hashtable _lastSentWhoisRequest; + Mutex _lastSentWhoisRequest_m; - // Packets waiting for WHOIS replies or other decode info or missing fragments - struct RXQueueEntry - { - RXQueueEntry() : timestamp(0) {} - volatile int64_t timestamp; // 0 if entry is not in use - volatile uint64_t packetId; - IncomingPacket frag0; // head of packet - Packet::Fragment frags[ZT_MAX_PACKET_FRAGMENTS - 1]; // later fragments (if any) - unsigned int totalFragments; // 0 if only frag0 received, waiting for frags - uint32_t haveFragments; // bit mask, LSB to MSB - volatile bool complete; // if true, packet is complete - volatile int32_t flowId; - Mutex lock; - }; - RXQueueEntry _rxQueue[ZT_RX_QUEUE_SIZE]; - AtomicCounter _rxQueuePtr; + // Packets waiting for WHOIS replies or other decode info or missing fragments + struct RXQueueEntry { + RXQueueEntry() : timestamp(0) + { + } + volatile int64_t timestamp; // 0 if entry is not in use + volatile uint64_t packetId; + IncomingPacket frag0; // head of packet + Packet::Fragment frags[ZT_MAX_PACKET_FRAGMENTS - 1]; // later fragments (if any) + unsigned int totalFragments; // 0 if only frag0 received, waiting for frags + uint32_t haveFragments; // bit mask, LSB to MSB + volatile bool complete; // if true, packet is complete + volatile int32_t flowId; + Mutex lock; + }; + RXQueueEntry _rxQueue[ZT_RX_QUEUE_SIZE]; + AtomicCounter _rxQueuePtr; - // Returns matching or next available RX queue entry - inline RXQueueEntry *_findRXQueueEntry(uint64_t packetId) - { - const unsigned int current = static_cast(_rxQueuePtr.load()); - for(unsigned int k=1;k<=ZT_RX_QUEUE_SIZE;++k) { - RXQueueEntry *rq = &(_rxQueue[(current - k) % ZT_RX_QUEUE_SIZE]); - if ((rq->packetId == packetId)&&(rq->timestamp)) { - return rq; - } - } - ++_rxQueuePtr; - return &(_rxQueue[static_cast(current) % ZT_RX_QUEUE_SIZE]); - } + // Returns matching or next available RX queue entry + inline RXQueueEntry* _findRXQueueEntry(uint64_t packetId) + { + const unsigned int current = static_cast(_rxQueuePtr.load()); + for (unsigned int k = 1; k <= ZT_RX_QUEUE_SIZE; ++k) { + RXQueueEntry* rq = &(_rxQueue[(current - k) % ZT_RX_QUEUE_SIZE]); + if ((rq->packetId == packetId) && (rq->timestamp)) { + return rq; + } + } + ++_rxQueuePtr; + return &(_rxQueue[static_cast(current) % ZT_RX_QUEUE_SIZE]); + } - // Returns current entry in rx queue ring buffer and increments ring pointer - inline RXQueueEntry *_nextRXQueueEntry() - { - return &(_rxQueue[static_cast((++_rxQueuePtr) - 1) % ZT_RX_QUEUE_SIZE]); - } + // Returns current entry in rx queue ring buffer and increments ring pointer + inline RXQueueEntry* _nextRXQueueEntry() + { + return &(_rxQueue[static_cast((++_rxQueuePtr) - 1) % ZT_RX_QUEUE_SIZE]); + } - // ZeroTier-layer TX queue entry - struct TXQueueEntry - { - TXQueueEntry() {} - TXQueueEntry(Address d,uint64_t ct,const Packet &p,bool enc,int32_t fid) : - dest(d), - creationTime(ct), - packet(p), - encrypt(enc), - flowId(fid) {} + // ZeroTier-layer TX queue entry + struct TXQueueEntry { + TXQueueEntry() + { + } + TXQueueEntry(Address d, uint64_t ct, const Packet& p, bool enc, int32_t fid) : dest(d), creationTime(ct), packet(p), encrypt(enc), flowId(fid) + { + } - Address dest; - uint64_t creationTime; - Packet packet; // unencrypted/unMAC'd packet -- this is done at send time - bool encrypt; - int32_t flowId; - }; - std::list< TXQueueEntry > _txQueue; - Mutex _txQueue_m; - Mutex _aqm_m; + Address dest; + uint64_t creationTime; + Packet packet; // unencrypted/unMAC'd packet -- this is done at send time + bool encrypt; + int32_t flowId; + }; + std::list _txQueue; + Mutex _txQueue_m; + Mutex _aqm_m; - // Tracks sending of VERB_RENDEZVOUS to relaying peers - struct _LastUniteKey - { - _LastUniteKey() : x(0),y(0) {} - _LastUniteKey(const Address &a1,const Address &a2) - { - if (a1 > a2) { - x = a2.toInt(); - y = a1.toInt(); - } else { - x = a1.toInt(); - y = a2.toInt(); - } - } - inline unsigned long hashCode() const { return ((unsigned long)x ^ (unsigned long)y); } - inline bool operator==(const _LastUniteKey &k) const { return ((x == k.x)&&(y == k.y)); } - uint64_t x,y; - }; - Hashtable< _LastUniteKey,uint64_t > _lastUniteAttempt; // key is always sorted in ascending order, for set-like behavior - Mutex _lastUniteAttempt_m; + // Tracks sending of VERB_RENDEZVOUS to relaying peers + struct _LastUniteKey { + _LastUniteKey() : x(0), y(0) + { + } + _LastUniteKey(const Address& a1, const Address& a2) + { + if (a1 > a2) { + x = a2.toInt(); + y = a1.toInt(); + } + else { + x = a1.toInt(); + y = a2.toInt(); + } + } + inline unsigned long hashCode() const + { + return ((unsigned long)x ^ (unsigned long)y); + } + inline bool operator==(const _LastUniteKey& k) const + { + return ((x == k.x) && (y == k.y)); + } + uint64_t x, y; + }; + Hashtable<_LastUniteKey, uint64_t> _lastUniteAttempt; // key is always sorted in ascending order, for set-like behavior + Mutex _lastUniteAttempt_m; - // Queue with additional flow state variables - struct ManagedQueue - { - ManagedQueue(int id) : - id(id), - byteCredit(ZT_AQM_QUANTUM), - byteLength(0), - dropping(false) - {} - int id; - int byteCredit; - int byteLength; - uint64_t first_above_time; - uint32_t count; - uint64_t drop_next; - bool dropping; - uint64_t drop_next_time; - std::list< TXQueueEntry *> q; - }; - // To implement fq_codel we need to maintain a queue of queues - struct NetworkQoSControlBlock - { - int _currEnqueuedPackets; - std::vector newQueues; - std::vector oldQueues; - std::vector inactiveQueues; - }; - std::map _netQueueControlBlock; + // Queue with additional flow state variables + struct ManagedQueue { + ManagedQueue(int id) : id(id), byteCredit(ZT_AQM_QUANTUM), byteLength(0), dropping(false) + { + } + int id; + int byteCredit; + int byteLength; + uint64_t first_above_time; + uint32_t count; + uint64_t drop_next; + bool dropping; + uint64_t drop_next_time; + std::list q; + }; + // To implement fq_codel we need to maintain a queue of queues + struct NetworkQoSControlBlock { + int _currEnqueuedPackets; + std::vector newQueues; + std::vector oldQueues; + std::vector inactiveQueues; + }; + std::map _netQueueControlBlock; }; -} // namespace ZeroTier +} // namespace ZeroTier #endif diff --git a/node/Tag.cpp b/node/Tag.cpp index effb6907..3137d4e7 100644 --- a/node/Tag.cpp +++ b/node/Tag.cpp @@ -12,32 +12,34 @@ /****/ #include "Tag.hpp" -#include "RuntimeEnvironment.hpp" + #include "Identity.hpp" -#include "Topology.hpp" -#include "Switch.hpp" #include "Network.hpp" #include "Node.hpp" +#include "RuntimeEnvironment.hpp" +#include "Switch.hpp" +#include "Topology.hpp" namespace ZeroTier { -int Tag::verify(const RuntimeEnvironment *RR,void *tPtr) const +int Tag::verify(const RuntimeEnvironment* RR, void* tPtr) const { - if ((!_signedBy)||(_signedBy != Network::controllerFor(_networkId))) { - return -1; - } - const Identity id(RR->topology->getIdentity(tPtr,_signedBy)); - if (!id) { - RR->sw->requestWhois(tPtr,RR->node->now(),_signedBy); - return 1; - } - try { - Buffer<(sizeof(Tag) * 2)> tmp; - this->serialize(tmp,true); - return (id.verify(tmp.data(),tmp.size(),_signature) ? 0 : -1); - } catch ( ... ) { - return -1; - } + if ((! _signedBy) || (_signedBy != Network::controllerFor(_networkId))) { + return -1; + } + const Identity id(RR->topology->getIdentity(tPtr, _signedBy)); + if (! id) { + RR->sw->requestWhois(tPtr, RR->node->now(), _signedBy); + return 1; + } + try { + Buffer<(sizeof(Tag) * 2)> tmp; + this->serialize(tmp, true); + return (id.verify(tmp.data(), tmp.size(), _signature) ? 0 : -1); + } + catch (...) { + return -1; + } } -} // namespace ZeroTier +} // namespace ZeroTier diff --git a/node/Tag.hpp b/node/Tag.hpp index c3af4725..9edd1fcb 100644 --- a/node/Tag.hpp +++ b/node/Tag.hpp @@ -14,18 +14,18 @@ #ifndef ZT_TAG_HPP #define ZT_TAG_HPP +#include "Address.hpp" +#include "Buffer.hpp" +#include "Constants.hpp" +#include "Credential.hpp" +#include "ECC.hpp" +#include "Identity.hpp" + #include #include #include #include -#include "Constants.hpp" -#include "Credential.hpp" -#include "C25519.hpp" -#include "Address.hpp" -#include "Identity.hpp" -#include "Buffer.hpp" - namespace ZeroTier { class RuntimeEnvironment; @@ -47,169 +47,213 @@ class RuntimeEnvironment; * Unlike capabilities tags are signed only by the issuer and are never * transferable. */ -class Tag : public Credential -{ -public: - static inline Credential::Type credentialType() { return Credential::CREDENTIAL_TYPE_TAG; } +class Tag : public Credential { + public: + static inline Credential::Type credentialType() + { + return Credential::CREDENTIAL_TYPE_TAG; + } - Tag() : - _id(0), - _value(0), - _networkId(0), - _ts(0) - { - memset(_signature.data,0,sizeof(_signature.data)); - } + Tag() : _id(0), _value(0), _networkId(0), _ts(0) + { + memset(_signature.data, 0, sizeof(_signature.data)); + } - /** - * @param nwid Network ID - * @param ts Timestamp - * @param issuedTo Address to which this tag was issued - * @param id Tag ID - * @param value Tag value - */ - Tag(const uint64_t nwid,const int64_t ts,const Address &issuedTo,const uint32_t id,const uint32_t value) : - _id(id), - _value(value), - _networkId(nwid), - _ts(ts), - _issuedTo(issuedTo), - _signedBy() - { - memset(_signature.data,0,sizeof(_signature.data)); - } + /** + * @param nwid Network ID + * @param ts Timestamp + * @param issuedTo Address to which this tag was issued + * @param id Tag ID + * @param value Tag value + */ + Tag(const uint64_t nwid, const int64_t ts, const Address& issuedTo, const uint32_t id, const uint32_t value) : _id(id), _value(value), _networkId(nwid), _ts(ts), _issuedTo(issuedTo), _signedBy() + { + memset(_signature.data, 0, sizeof(_signature.data)); + } - inline uint32_t id() const { return _id; } - inline const uint32_t &value() const { return _value; } - inline uint64_t networkId() const { return _networkId; } - inline int64_t timestamp() const { return _ts; } - inline const Address &issuedTo() const { return _issuedTo; } - inline const Address &signedBy() const { return _signedBy; } + inline uint32_t id() const + { + return _id; + } + inline const uint32_t& value() const + { + return _value; + } + inline uint64_t networkId() const + { + return _networkId; + } + inline int64_t timestamp() const + { + return _ts; + } + inline const Address& issuedTo() const + { + return _issuedTo; + } + inline const Address& signedBy() const + { + return _signedBy; + } - /** - * Sign this tag - * - * @param signer Signing identity, must have private key - * @return True if signature was successful - */ - inline bool sign(const Identity &signer) - { - if (signer.hasPrivate()) { - Buffer tmp; - _signedBy = signer.address(); - this->serialize(tmp,true); - _signature = signer.sign(tmp.data(),tmp.size()); - return true; - } - return false; - } + /** + * Sign this tag + * + * @param signer Signing identity, must have private key + * @return True if signature was successful + */ + inline bool sign(const Identity& signer) + { + if (signer.hasPrivate()) { + Buffer tmp; + _signedBy = signer.address(); + this->serialize(tmp, true); + _signature = signer.sign(tmp.data(), tmp.size()); + return true; + } + return false; + } - /** - * Check this tag's signature - * - * @param RR Runtime environment to allow identity lookup for signedBy - * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call - * @return 0 == OK, 1 == waiting for WHOIS, -1 == BAD signature or tag - */ - int verify(const RuntimeEnvironment *RR,void *tPtr) const; + /** + * Check this tag's signature + * + * @param RR Runtime environment to allow identity lookup for signedBy + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call + * @return 0 == OK, 1 == waiting for WHOIS, -1 == BAD signature or tag + */ + int verify(const RuntimeEnvironment* RR, void* tPtr) const; - template - inline void serialize(Buffer &b,const bool forSign = false) const - { - if (forSign) { - b.append((uint64_t)0x7f7f7f7f7f7f7f7fULL); - } + template inline void serialize(Buffer& b, const bool forSign = false) const + { + if (forSign) { + b.append((uint64_t)0x7f7f7f7f7f7f7f7fULL); + } - b.append(_networkId); - b.append(_ts); - b.append(_id); - b.append(_value); + b.append(_networkId); + b.append(_ts); + b.append(_id); + b.append(_value); - _issuedTo.appendTo(b); - _signedBy.appendTo(b); - if (!forSign) { - b.append((uint8_t)1); // 1 == Ed25519 - b.append((uint16_t)ZT_C25519_SIGNATURE_LEN); // length of signature - b.append(_signature.data,ZT_C25519_SIGNATURE_LEN); - } + _issuedTo.appendTo(b); + _signedBy.appendTo(b); + if (! forSign) { + b.append((uint8_t)1); // 1 == Ed25519 + b.append((uint16_t)ZT_ECC_SIGNATURE_LEN); // length of signature + b.append(_signature.data, ZT_ECC_SIGNATURE_LEN); + } - b.append((uint16_t)0); // length of additional fields, currently 0 + b.append((uint16_t)0); // length of additional fields, currently 0 - if (forSign) { - b.append((uint64_t)0x7f7f7f7f7f7f7f7fULL); - } - } + if (forSign) { + b.append((uint64_t)0x7f7f7f7f7f7f7f7fULL); + } + } - template - inline unsigned int deserialize(const Buffer &b,unsigned int startAt = 0) - { - unsigned int p = startAt; + template inline unsigned int deserialize(const Buffer& b, unsigned int startAt = 0) + { + unsigned int p = startAt; - *this = Tag(); + *this = Tag(); - _networkId = b.template at(p); - p += 8; - _ts = b.template at(p); - p += 8; - _id = b.template at(p); - p += 4; + _networkId = b.template at(p); + p += 8; + _ts = b.template at(p); + p += 8; + _id = b.template at(p); + p += 4; - _value = b.template at(p); - p += 4; + _value = b.template at(p); + p += 4; - _issuedTo.setTo(b.field(p,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); - p += ZT_ADDRESS_LENGTH; - _signedBy.setTo(b.field(p,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); - p += ZT_ADDRESS_LENGTH; - if (b[p++] == 1) { - if (b.template at(p) != ZT_C25519_SIGNATURE_LEN) { - throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_INVALID_CRYPTOGRAPHIC_TOKEN; - } - p += 2; - memcpy(_signature.data,b.field(p,ZT_C25519_SIGNATURE_LEN),ZT_C25519_SIGNATURE_LEN); - p += ZT_C25519_SIGNATURE_LEN; - } else { - p += 2 + b.template at(p); - } + _issuedTo.setTo(b.field(p, ZT_ADDRESS_LENGTH), ZT_ADDRESS_LENGTH); + p += ZT_ADDRESS_LENGTH; + _signedBy.setTo(b.field(p, ZT_ADDRESS_LENGTH), ZT_ADDRESS_LENGTH); + p += ZT_ADDRESS_LENGTH; + if (b[p++] == 1) { + if (b.template at(p) != ZT_ECC_SIGNATURE_LEN) { + throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_INVALID_CRYPTOGRAPHIC_TOKEN; + } + p += 2; + memcpy(_signature.data, b.field(p, ZT_ECC_SIGNATURE_LEN), ZT_ECC_SIGNATURE_LEN); + p += ZT_ECC_SIGNATURE_LEN; + } + else { + p += 2 + b.template at(p); + } - p += 2 + b.template at(p); - if (p > b.size()) { - throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_OVERFLOW; - } + p += 2 + b.template at(p); + if (p > b.size()) { + throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_OVERFLOW; + } - return (p - startAt); - } + return (p - startAt); + } - // Provides natural sort order by ID - inline bool operator<(const Tag &t) const { return (_id < t._id); } + // Provides natural sort order by ID + inline bool operator<(const Tag& t) const + { + return (_id < t._id); + } - inline bool operator==(const Tag &t) const { return (memcmp(this,&t,sizeof(Tag)) == 0); } - inline bool operator!=(const Tag &t) const { return (memcmp(this,&t,sizeof(Tag)) != 0); } + inline bool operator==(const Tag& t) const + { + return (memcmp(this, &t, sizeof(Tag)) == 0); + } + inline bool operator!=(const Tag& t) const + { + return (memcmp(this, &t, sizeof(Tag)) != 0); + } - // For searching sorted arrays or lists of Tags by ID - struct IdComparePredicate - { - inline bool operator()(const Tag &a,const Tag &b) const { return (a.id() < b.id()); } - inline bool operator()(const uint32_t a,const Tag &b) const { return (a < b.id()); } - inline bool operator()(const Tag &a,const uint32_t b) const { return (a.id() < b); } - inline bool operator()(const Tag *a,const Tag *b) const { return (a->id() < b->id()); } - inline bool operator()(const Tag *a,const Tag &b) const { return (a->id() < b.id()); } - inline bool operator()(const Tag &a,const Tag *b) const { return (a.id() < b->id()); } - inline bool operator()(const uint32_t a,const Tag *b) const { return (a < b->id()); } - inline bool operator()(const Tag *a,const uint32_t b) const { return (a->id() < b); } - inline bool operator()(const uint32_t a,const uint32_t b) const { return (a < b); } - }; + // For searching sorted arrays or lists of Tags by ID + struct IdComparePredicate { + inline bool operator()(const Tag& a, const Tag& b) const + { + return (a.id() < b.id()); + } + inline bool operator()(const uint32_t a, const Tag& b) const + { + return (a < b.id()); + } + inline bool operator()(const Tag& a, const uint32_t b) const + { + return (a.id() < b); + } + inline bool operator()(const Tag* a, const Tag* b) const + { + return (a->id() < b->id()); + } + inline bool operator()(const Tag* a, const Tag& b) const + { + return (a->id() < b.id()); + } + inline bool operator()(const Tag& a, const Tag* b) const + { + return (a.id() < b->id()); + } + inline bool operator()(const uint32_t a, const Tag* b) const + { + return (a < b->id()); + } + inline bool operator()(const Tag* a, const uint32_t b) const + { + return (a->id() < b); + } + inline bool operator()(const uint32_t a, const uint32_t b) const + { + return (a < b); + } + }; -private: - uint32_t _id; - uint32_t _value; - uint64_t _networkId; - int64_t _ts; - Address _issuedTo; - Address _signedBy; - C25519::Signature _signature; + private: + uint32_t _id; + uint32_t _value; + uint64_t _networkId; + int64_t _ts; + Address _issuedTo; + Address _signedBy; + ECC::Signature _signature; }; -} // namespace ZeroTier +} // namespace ZeroTier #endif diff --git a/node/Topology.cpp b/node/Topology.cpp index fc272ce5..fecb0c40 100644 --- a/node/Topology.cpp +++ b/node/Topology.cpp @@ -11,425 +11,457 @@ */ /****/ -#include "Constants.hpp" #include "Topology.hpp" -#include "RuntimeEnvironment.hpp" -#include "Node.hpp" + +#include "Buffer.hpp" +#include "Constants.hpp" #include "Network.hpp" #include "NetworkConfig.hpp" -#include "Buffer.hpp" +#include "Node.hpp" +#include "RuntimeEnvironment.hpp" #include "Switch.hpp" namespace ZeroTier { #define ZT_DEFAULT_WORLD_LENGTH 570 -static const unsigned char ZT_DEFAULT_WORLD[ZT_DEFAULT_WORLD_LENGTH] = {0x01,0x00,0x00,0x00,0x00,0x08,0xea,0xc9,0x0a,0x00,0x00,0x01,0x7e,0xe9,0x57,0x60,0xcd,0xb8,0xb3,0x88,0xa4,0x69,0x22,0x14,0x91,0xaa,0x9a,0xcd,0x66,0xcc,0x76,0x4c,0xde,0xfd,0x56,0x03,0x9f,0x10,0x67,0xae,0x15,0xe6,0x9c,0x6f,0xb4,0x2d,0x7b,0x55,0x33,0x0e,0x3f,0xda,0xac,0x52,0x9c,0x07,0x92,0xfd,0x73,0x40,0xa6,0xaa,0x21,0xab,0xa8,0xa4,0x89,0xfd,0xae,0xa4,0x4a,0x39,0xbf,0x2d,0x00,0x65,0x9a,0xc9,0xc8,0x18,0xeb,0x36,0x00,0x92,0x76,0x37,0xef,0x4d,0x14,0x04,0xa4,0x4d,0x54,0x46,0x84,0x85,0x13,0x79,0x75,0x1f,0xaa,0x79,0xb4,0xc4,0xea,0x85,0x04,0x01,0x75,0xea,0x06,0x58,0x60,0x48,0x24,0x02,0xe1,0xeb,0x34,0x20,0x52,0x00,0x0e,0x62,0x90,0x06,0x1a,0x9b,0xe0,0xcd,0x29,0x3c,0x8b,0x55,0xf1,0xc3,0xd2,0x52,0x48,0x08,0xaf,0xc5,0x49,0x22,0x08,0x0e,0x35,0x39,0xa7,0x5a,0xdd,0xc3,0xce,0xf0,0xf6,0xad,0x26,0x0d,0x58,0x82,0x93,0xbb,0x77,0x86,0xe7,0x1e,0xfa,0x4b,0x90,0x57,0xda,0xd9,0x86,0x7a,0xfe,0x12,0xdd,0x04,0xca,0xfe,0x9e,0xfe,0xb9,0x00,0xcc,0xde,0xf7,0x6b,0xc7,0xb9,0x7d,0xed,0x90,0x4e,0xab,0xc5,0xdf,0x09,0x88,0x6d,0x9c,0x15,0x14,0xa6,0x10,0x03,0x6c,0xb9,0x13,0x9c,0xc2,0x14,0x00,0x1a,0x29,0x58,0x97,0x8e,0xfc,0xec,0x15,0x71,0x2d,0xd3,0x94,0x8c,0x6e,0x6b,0x3a,0x8e,0x89,0x3d,0xf0,0x1f,0xf4,0x93,0xd1,0xf8,0xd9,0x80,0x6a,0x86,0x0c,0x54,0x20,0x57,0x1b,0xf0,0x00,0x02,0x04,0x68,0xc2,0x08,0x86,0x27,0x09,0x06,0x26,0x05,0x98,0x80,0x02,0x00,0x12,0x00,0x00,0x30,0x05,0x71,0x0e,0x34,0x00,0x51,0x27,0x09,0x77,0x8c,0xde,0x71,0x90,0x00,0x3f,0x66,0x81,0xa9,0x9e,0x5a,0xd1,0x89,0x5e,0x9f,0xba,0x33,0xe6,0x21,0x2d,0x44,0x54,0xe1,0x68,0xbc,0xec,0x71,0x12,0x10,0x1b,0xf0,0x00,0x95,0x6e,0xd8,0xe9,0x2e,0x42,0x89,0x2c,0xb6,0xf2,0xec,0x41,0x08,0x81,0xa8,0x4a,0xb1,0x9d,0xa5,0x0e,0x12,0x87,0xba,0x3d,0x92,0x6c,0x3a,0x1f,0x75,0x5c,0xcc,0xf2,0x99,0xa1,0x20,0x70,0x55,0x00,0x02,0x04,0x67,0xc3,0x67,0x42,0x27,0x09,0x06,0x26,0x05,0x98,0x80,0x04,0x00,0x00,0xc3,0x02,0x54,0xf2,0xbc,0xa1,0xf7,0x00,0x19,0x27,0x09,0x62,0xf8,0x65,0xae,0x71,0x00,0xe2,0x07,0x6c,0x57,0xde,0x87,0x0e,0x62,0x88,0xd7,0xd5,0xe7,0x40,0x44,0x08,0xb1,0x54,0x5e,0xfc,0xa3,0x7d,0x67,0xf7,0x7b,0x87,0xe9,0xe5,0x41,0x68,0xc2,0x5d,0x3e,0xf1,0xa9,0xab,0xf2,0x90,0x5e,0xa5,0xe7,0x85,0xc0,0x1d,0xff,0x23,0x88,0x7a,0xd4,0x23,0x2d,0x95,0xc7,0xa8,0xfd,0x2c,0x27,0x11,0x1a,0x72,0xbd,0x15,0x93,0x22,0xdc,0x00,0x02,0x04,0x32,0x07,0xfc,0x8a,0x27,0x09,0x06,0x20,0x01,0x49,0xf0,0xd0,0xdb,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x27,0x09,0xca,0xfe,0x04,0xeb,0xa9,0x00,0x6c,0x6a,0x9d,0x1d,0xea,0x55,0xc1,0x61,0x6b,0xfe,0x2a,0x2b,0x8f,0x0f,0xf9,0xa8,0xca,0xca,0xf7,0x03,0x74,0xfb,0x1f,0x39,0xe3,0xbe,0xf8,0x1c,0xbf,0xeb,0xef,0x17,0xb7,0x22,0x82,0x68,0xa0,0xa2,0xa2,0x9d,0x34,0x88,0xc7,0x52,0x56,0x5c,0x6c,0x96,0x5c,0xbd,0x65,0x06,0xec,0x24,0x39,0x7c,0xc8,0xa5,0xd9,0xd1,0x52,0x85,0xa8,0x7f,0x00,0x02,0x04,0x54,0x11,0x35,0x9b,0x27,0x09,0x06,0x2a,0x02,0x6e,0xa0,0xd4,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x99,0x93,0x27,0x09}; +static const unsigned char ZT_DEFAULT_WORLD[ZT_DEFAULT_WORLD_LENGTH] = { + 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0xea, 0xc9, 0x0a, 0x00, 0x00, 0x01, 0x7e, 0xe9, 0x57, 0x60, 0xcd, 0xb8, 0xb3, 0x88, 0xa4, 0x69, 0x22, 0x14, 0x91, 0xaa, 0x9a, 0xcd, 0x66, 0xcc, 0x76, 0x4c, 0xde, 0xfd, 0x56, 0x03, 0x9f, 0x10, + 0x67, 0xae, 0x15, 0xe6, 0x9c, 0x6f, 0xb4, 0x2d, 0x7b, 0x55, 0x33, 0x0e, 0x3f, 0xda, 0xac, 0x52, 0x9c, 0x07, 0x92, 0xfd, 0x73, 0x40, 0xa6, 0xaa, 0x21, 0xab, 0xa8, 0xa4, 0x89, 0xfd, 0xae, 0xa4, 0x4a, 0x39, 0xbf, 0x2d, 0x00, 0x65, + 0x9a, 0xc9, 0xc8, 0x18, 0xeb, 0x36, 0x00, 0x92, 0x76, 0x37, 0xef, 0x4d, 0x14, 0x04, 0xa4, 0x4d, 0x54, 0x46, 0x84, 0x85, 0x13, 0x79, 0x75, 0x1f, 0xaa, 0x79, 0xb4, 0xc4, 0xea, 0x85, 0x04, 0x01, 0x75, 0xea, 0x06, 0x58, 0x60, 0x48, + 0x24, 0x02, 0xe1, 0xeb, 0x34, 0x20, 0x52, 0x00, 0x0e, 0x62, 0x90, 0x06, 0x1a, 0x9b, 0xe0, 0xcd, 0x29, 0x3c, 0x8b, 0x55, 0xf1, 0xc3, 0xd2, 0x52, 0x48, 0x08, 0xaf, 0xc5, 0x49, 0x22, 0x08, 0x0e, 0x35, 0x39, 0xa7, 0x5a, 0xdd, 0xc3, + 0xce, 0xf0, 0xf6, 0xad, 0x26, 0x0d, 0x58, 0x82, 0x93, 0xbb, 0x77, 0x86, 0xe7, 0x1e, 0xfa, 0x4b, 0x90, 0x57, 0xda, 0xd9, 0x86, 0x7a, 0xfe, 0x12, 0xdd, 0x04, 0xca, 0xfe, 0x9e, 0xfe, 0xb9, 0x00, 0xcc, 0xde, 0xf7, 0x6b, 0xc7, 0xb9, + 0x7d, 0xed, 0x90, 0x4e, 0xab, 0xc5, 0xdf, 0x09, 0x88, 0x6d, 0x9c, 0x15, 0x14, 0xa6, 0x10, 0x03, 0x6c, 0xb9, 0x13, 0x9c, 0xc2, 0x14, 0x00, 0x1a, 0x29, 0x58, 0x97, 0x8e, 0xfc, 0xec, 0x15, 0x71, 0x2d, 0xd3, 0x94, 0x8c, 0x6e, 0x6b, + 0x3a, 0x8e, 0x89, 0x3d, 0xf0, 0x1f, 0xf4, 0x93, 0xd1, 0xf8, 0xd9, 0x80, 0x6a, 0x86, 0x0c, 0x54, 0x20, 0x57, 0x1b, 0xf0, 0x00, 0x02, 0x04, 0x68, 0xc2, 0x08, 0x86, 0x27, 0x09, 0x06, 0x26, 0x05, 0x98, 0x80, 0x02, 0x00, 0x12, 0x00, + 0x00, 0x30, 0x05, 0x71, 0x0e, 0x34, 0x00, 0x51, 0x27, 0x09, 0x77, 0x8c, 0xde, 0x71, 0x90, 0x00, 0x3f, 0x66, 0x81, 0xa9, 0x9e, 0x5a, 0xd1, 0x89, 0x5e, 0x9f, 0xba, 0x33, 0xe6, 0x21, 0x2d, 0x44, 0x54, 0xe1, 0x68, 0xbc, 0xec, 0x71, + 0x12, 0x10, 0x1b, 0xf0, 0x00, 0x95, 0x6e, 0xd8, 0xe9, 0x2e, 0x42, 0x89, 0x2c, 0xb6, 0xf2, 0xec, 0x41, 0x08, 0x81, 0xa8, 0x4a, 0xb1, 0x9d, 0xa5, 0x0e, 0x12, 0x87, 0xba, 0x3d, 0x92, 0x6c, 0x3a, 0x1f, 0x75, 0x5c, 0xcc, 0xf2, 0x99, + 0xa1, 0x20, 0x70, 0x55, 0x00, 0x02, 0x04, 0x67, 0xc3, 0x67, 0x42, 0x27, 0x09, 0x06, 0x26, 0x05, 0x98, 0x80, 0x04, 0x00, 0x00, 0xc3, 0x02, 0x54, 0xf2, 0xbc, 0xa1, 0xf7, 0x00, 0x19, 0x27, 0x09, 0x62, 0xf8, 0x65, 0xae, 0x71, 0x00, + 0xe2, 0x07, 0x6c, 0x57, 0xde, 0x87, 0x0e, 0x62, 0x88, 0xd7, 0xd5, 0xe7, 0x40, 0x44, 0x08, 0xb1, 0x54, 0x5e, 0xfc, 0xa3, 0x7d, 0x67, 0xf7, 0x7b, 0x87, 0xe9, 0xe5, 0x41, 0x68, 0xc2, 0x5d, 0x3e, 0xf1, 0xa9, 0xab, 0xf2, 0x90, 0x5e, + 0xa5, 0xe7, 0x85, 0xc0, 0x1d, 0xff, 0x23, 0x88, 0x7a, 0xd4, 0x23, 0x2d, 0x95, 0xc7, 0xa8, 0xfd, 0x2c, 0x27, 0x11, 0x1a, 0x72, 0xbd, 0x15, 0x93, 0x22, 0xdc, 0x00, 0x02, 0x04, 0x32, 0x07, 0xfc, 0x8a, 0x27, 0x09, 0x06, 0x20, 0x01, + 0x49, 0xf0, 0xd0, 0xdb, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x27, 0x09, 0xca, 0xfe, 0x04, 0xeb, 0xa9, 0x00, 0x6c, 0x6a, 0x9d, 0x1d, 0xea, 0x55, 0xc1, 0x61, 0x6b, 0xfe, 0x2a, 0x2b, 0x8f, 0x0f, 0xf9, 0xa8, + 0xca, 0xca, 0xf7, 0x03, 0x74, 0xfb, 0x1f, 0x39, 0xe3, 0xbe, 0xf8, 0x1c, 0xbf, 0xeb, 0xef, 0x17, 0xb7, 0x22, 0x82, 0x68, 0xa0, 0xa2, 0xa2, 0x9d, 0x34, 0x88, 0xc7, 0x52, 0x56, 0x5c, 0x6c, 0x96, 0x5c, 0xbd, 0x65, 0x06, 0xec, 0x24, + 0x39, 0x7c, 0xc8, 0xa5, 0xd9, 0xd1, 0x52, 0x85, 0xa8, 0x7f, 0x00, 0x02, 0x04, 0x54, 0x11, 0x35, 0x9b, 0x27, 0x09, 0x06, 0x2a, 0x02, 0x6e, 0xa0, 0xd4, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99, 0x93, 0x27, 0x09 +}; -Topology::Topology(const RuntimeEnvironment *renv,void *tPtr) : - RR(renv), - _numConfiguredPhysicalPaths(0), - _amUpstream(false) +Topology::Topology(const RuntimeEnvironment* renv, void* tPtr) : RR(renv), _numConfiguredPhysicalPaths(0), _amUpstream(false) { - uint8_t tmp[ZT_WORLD_MAX_SERIALIZED_LENGTH]; - uint64_t idtmp[2]; - idtmp[0] = 0; - idtmp[1] = 0; - int n = RR->node->stateObjectGet(tPtr,ZT_STATE_OBJECT_PLANET,idtmp,tmp,sizeof(tmp)); - if (n > 0) { - try { - World cachedPlanet; - cachedPlanet.deserialize(Buffer(tmp,(unsigned int)n),0); - addWorld(tPtr,cachedPlanet,false); - } catch ( ... ) {} // ignore invalid cached planets - } + uint8_t tmp[ZT_WORLD_MAX_SERIALIZED_LENGTH]; + uint64_t idtmp[2]; + idtmp[0] = 0; + idtmp[1] = 0; + int n = RR->node->stateObjectGet(tPtr, ZT_STATE_OBJECT_PLANET, idtmp, tmp, sizeof(tmp)); + if (n > 0) { + try { + World cachedPlanet; + cachedPlanet.deserialize(Buffer(tmp, (unsigned int)n), 0); + addWorld(tPtr, cachedPlanet, false); + } + catch (...) { + } // ignore invalid cached planets + } - World defaultPlanet; - { - Buffer wtmp(ZT_DEFAULT_WORLD,ZT_DEFAULT_WORLD_LENGTH); - defaultPlanet.deserialize(wtmp,0); // throws on error, which would indicate a bad static variable up top - } - addWorld(tPtr,defaultPlanet,false); + World defaultPlanet; + { + Buffer wtmp(ZT_DEFAULT_WORLD, ZT_DEFAULT_WORLD_LENGTH); + defaultPlanet.deserialize(wtmp, 0); // throws on error, which would indicate a bad static variable up top + } + addWorld(tPtr, defaultPlanet, false); } Topology::~Topology() { - Hashtable< Address,SharedPtr >::Iterator i(_peers); - Address *a = (Address *)0; - SharedPtr *p = (SharedPtr *)0; - while (i.next(a,p)) { - _savePeer((void *)0,*p); - } + Hashtable >::Iterator i(_peers); + Address* a = (Address*)0; + SharedPtr* p = (SharedPtr*)0; + while (i.next(a, p)) { + _savePeer((void*)0, *p); + } } -SharedPtr Topology::addPeer(void *tPtr,const SharedPtr &peer) +SharedPtr Topology::addPeer(void* tPtr, const SharedPtr& peer) { - SharedPtr np; - { - Mutex::Lock _l(_peers_m); - SharedPtr &hp = _peers[peer->address()]; - if (!hp) { - hp = peer; - } - np = hp; - } - return np; + SharedPtr np; + { + Mutex::Lock _l(_peers_m); + SharedPtr& hp = _peers[peer->address()]; + if (! hp) { + hp = peer; + } + np = hp; + } + return np; } -SharedPtr Topology::getPeer(void *tPtr,const Address &zta) +SharedPtr Topology::getPeer(void* tPtr, const Address& zta) { - if (zta == RR->identity.address()) { - return SharedPtr(); - } + if (zta == RR->identity.address()) { + return SharedPtr(); + } - { - Mutex::Lock _l(_peers_m); - const SharedPtr *const ap = _peers.get(zta); - if (ap) { - return *ap; - } - } + { + Mutex::Lock _l(_peers_m); + const SharedPtr* const ap = _peers.get(zta); + if (ap) { + return *ap; + } + } - try { - Buffer buf; - uint64_t idbuf[2]; - idbuf[0] = zta.toInt(); - idbuf[1] = 0; - int len = RR->node->stateObjectGet(tPtr,ZT_STATE_OBJECT_PEER,idbuf,buf.unsafeData(),ZT_PEER_MAX_SERIALIZED_STATE_SIZE); - if (len > 0) { - buf.setSize(len); - Mutex::Lock _l(_peers_m); - SharedPtr &ap = _peers[zta]; - if (ap) { - return ap; - } - ap = Peer::deserializeFromCache(RR->node->now(),tPtr,buf,RR); - if (!ap) { - _peers.erase(zta); - } - return SharedPtr(); - } - } catch ( ... ) {} // ignore invalid identities or other strange failures + try { + Buffer buf; + uint64_t idbuf[2]; + idbuf[0] = zta.toInt(); + idbuf[1] = 0; + int len = RR->node->stateObjectGet(tPtr, ZT_STATE_OBJECT_PEER, idbuf, buf.unsafeData(), ZT_PEER_MAX_SERIALIZED_STATE_SIZE); + if (len > 0) { + buf.setSize(len); + Mutex::Lock _l(_peers_m); + SharedPtr& ap = _peers[zta]; + if (ap) { + return ap; + } + ap = Peer::deserializeFromCache(RR->node->now(), tPtr, buf, RR); + if (! ap) { + _peers.erase(zta); + } + return SharedPtr(); + } + } + catch (...) { + } // ignore invalid identities or other strange failures - return SharedPtr(); + return SharedPtr(); } -Identity Topology::getIdentity(void *tPtr,const Address &zta) +Identity Topology::getIdentity(void* tPtr, const Address& zta) { - if (zta == RR->identity.address()) { - return RR->identity; - } else { - Mutex::Lock _l(_peers_m); - const SharedPtr *const ap = _peers.get(zta); - if (ap) { - return (*ap)->identity(); - } - } - return Identity(); + if (zta == RR->identity.address()) { + return RR->identity; + } + else { + Mutex::Lock _l(_peers_m); + const SharedPtr* const ap = _peers.get(zta); + if (ap) { + return (*ap)->identity(); + } + } + return Identity(); } SharedPtr Topology::getUpstreamPeer() { - const int64_t now = RR->node->now(); - unsigned int bestq = ~((unsigned int)0); - const SharedPtr *best = (const SharedPtr *)0; + const int64_t now = RR->node->now(); + unsigned int bestq = ~((unsigned int)0); + const SharedPtr* best = (const SharedPtr*)0; - Mutex::Lock _l2(_peers_m); - Mutex::Lock _l1(_upstreams_m); + Mutex::Lock _l2(_peers_m); + Mutex::Lock _l1(_upstreams_m); - for(std::vector
::const_iterator a(_upstreamAddresses.begin());a!=_upstreamAddresses.end();++a) { - const SharedPtr *p = _peers.get(*a); - if (p) { - const unsigned int q = (*p)->relayQuality(now); - if (q <= bestq) { - bestq = q; - best = p; - } - } - } + for (std::vector
::const_iterator a(_upstreamAddresses.begin()); a != _upstreamAddresses.end(); ++a) { + const SharedPtr* p = _peers.get(*a); + if (p) { + const unsigned int q = (*p)->relayQuality(now); + if (q <= bestq) { + bestq = q; + best = p; + } + } + } - if (!best) { - return SharedPtr(); - } - return *best; + if (! best) { + return SharedPtr(); + } + return *best; } -bool Topology::isUpstream(const Identity &id) const +bool Topology::isUpstream(const Identity& id) const { - Mutex::Lock _l(_upstreams_m); - return (std::find(_upstreamAddresses.begin(),_upstreamAddresses.end(),id.address()) != _upstreamAddresses.end()); + Mutex::Lock _l(_upstreams_m); + return (std::find(_upstreamAddresses.begin(), _upstreamAddresses.end(), id.address()) != _upstreamAddresses.end()); } -bool Topology::shouldAcceptWorldUpdateFrom(const Address &addr) const +bool Topology::shouldAcceptWorldUpdateFrom(const Address& addr) const { - Mutex::Lock _l(_upstreams_m); - if (std::find(_upstreamAddresses.begin(),_upstreamAddresses.end(),addr) != _upstreamAddresses.end()) { - return true; - } - for(std::vector< std::pair< uint64_t,Address> >::const_iterator s(_moonSeeds.begin());s!=_moonSeeds.end();++s) { - if (s->second == addr) { - return true; - } - } - return false; + Mutex::Lock _l(_upstreams_m); + if (std::find(_upstreamAddresses.begin(), _upstreamAddresses.end(), addr) != _upstreamAddresses.end()) { + return true; + } + for (std::vector >::const_iterator s(_moonSeeds.begin()); s != _moonSeeds.end(); ++s) { + if (s->second == addr) { + return true; + } + } + return false; } -ZT_PeerRole Topology::role(const Address &ztaddr) const +ZT_PeerRole Topology::role(const Address& ztaddr) const { - Mutex::Lock _l(_upstreams_m); - if (std::find(_upstreamAddresses.begin(),_upstreamAddresses.end(),ztaddr) != _upstreamAddresses.end()) { - for(std::vector::const_iterator i(_planet.roots().begin());i!=_planet.roots().end();++i) { - if (i->identity.address() == ztaddr) { - return ZT_PEER_ROLE_PLANET; - } - } - return ZT_PEER_ROLE_MOON; - } - return ZT_PEER_ROLE_LEAF; + Mutex::Lock _l(_upstreams_m); + if (std::find(_upstreamAddresses.begin(), _upstreamAddresses.end(), ztaddr) != _upstreamAddresses.end()) { + for (std::vector::const_iterator i(_planet.roots().begin()); i != _planet.roots().end(); ++i) { + if (i->identity.address() == ztaddr) { + return ZT_PEER_ROLE_PLANET; + } + } + return ZT_PEER_ROLE_MOON; + } + return ZT_PEER_ROLE_LEAF; } -bool Topology::isProhibitedEndpoint(const Address &ztaddr,const InetAddress &ipaddr) const +bool Topology::isProhibitedEndpoint(const Address& ztaddr, const InetAddress& ipaddr) const { - Mutex::Lock _l(_upstreams_m); + Mutex::Lock _l(_upstreams_m); - // For roots the only permitted addresses are those defined. This adds just a little - // bit of extra security against spoofing, replaying, etc. - if (std::find(_upstreamAddresses.begin(),_upstreamAddresses.end(),ztaddr) != _upstreamAddresses.end()) { - for(std::vector::const_iterator r(_planet.roots().begin());r!=_planet.roots().end();++r) { - if (r->identity.address() == ztaddr) { - if (r->stableEndpoints.empty()) { - return false; // no stable endpoints specified, so allow dynamic paths - } - for(std::vector::const_iterator e(r->stableEndpoints.begin());e!=r->stableEndpoints.end();++e) { - if (ipaddr.ipsEqual(*e)) { - return false; - } - } - } - } - for(std::vector::const_iterator m(_moons.begin());m!=_moons.end();++m) { - for(std::vector::const_iterator r(m->roots().begin());r!=m->roots().end();++r) { - if (r->identity.address() == ztaddr) { - if (r->stableEndpoints.empty()) { - return false; // no stable endpoints specified, so allow dynamic paths - } - for(std::vector::const_iterator e(r->stableEndpoints.begin());e!=r->stableEndpoints.end();++e) { - if (ipaddr.ipsEqual(*e)) { - return false; - } - } - } - } - } - return true; - } + // For roots the only permitted addresses are those defined. This adds just a little + // bit of extra security against spoofing, replaying, etc. + if (std::find(_upstreamAddresses.begin(), _upstreamAddresses.end(), ztaddr) != _upstreamAddresses.end()) { + for (std::vector::const_iterator r(_planet.roots().begin()); r != _planet.roots().end(); ++r) { + if (r->identity.address() == ztaddr) { + if (r->stableEndpoints.empty()) { + return false; // no stable endpoints specified, so allow dynamic paths + } + for (std::vector::const_iterator e(r->stableEndpoints.begin()); e != r->stableEndpoints.end(); ++e) { + if (ipaddr.ipsEqual(*e)) { + return false; + } + } + } + } + for (std::vector::const_iterator m(_moons.begin()); m != _moons.end(); ++m) { + for (std::vector::const_iterator r(m->roots().begin()); r != m->roots().end(); ++r) { + if (r->identity.address() == ztaddr) { + if (r->stableEndpoints.empty()) { + return false; // no stable endpoints specified, so allow dynamic paths + } + for (std::vector::const_iterator e(r->stableEndpoints.begin()); e != r->stableEndpoints.end(); ++e) { + if (ipaddr.ipsEqual(*e)) { + return false; + } + } + } + } + } + return true; + } - return false; + return false; } -bool Topology::addWorld(void *tPtr,const World &newWorld,bool alwaysAcceptNew) +bool Topology::addWorld(void* tPtr, const World& newWorld, bool alwaysAcceptNew) { - if ((newWorld.type() != World::TYPE_PLANET)&&(newWorld.type() != World::TYPE_MOON)) { - return false; - } + if ((newWorld.type() != World::TYPE_PLANET) && (newWorld.type() != World::TYPE_MOON)) { + return false; + } - Mutex::Lock _l2(_peers_m); - Mutex::Lock _l1(_upstreams_m); + Mutex::Lock _l2(_peers_m); + Mutex::Lock _l1(_upstreams_m); - World *existing = (World *)0; - switch(newWorld.type()) { - case World::TYPE_PLANET: - existing = &_planet; - break; - case World::TYPE_MOON: - for(std::vector< World >::iterator m(_moons.begin());m!=_moons.end();++m) { - if (m->id() == newWorld.id()) { - existing = &(*m); - break; - } - } - break; - default: - return false; - } + World* existing = (World*)0; + switch (newWorld.type()) { + case World::TYPE_PLANET: + existing = &_planet; + break; + case World::TYPE_MOON: + for (std::vector::iterator m(_moons.begin()); m != _moons.end(); ++m) { + if (m->id() == newWorld.id()) { + existing = &(*m); + break; + } + } + break; + default: + return false; + } - if (existing) { - if (existing->shouldBeReplacedBy(newWorld)) { - *existing = newWorld; - } else { - return false; - } - } else if (newWorld.type() == World::TYPE_MOON) { - if (alwaysAcceptNew) { - _moons.push_back(newWorld); - existing = &(_moons.back()); - } else { - for(std::vector< std::pair >::iterator m(_moonSeeds.begin());m!=_moonSeeds.end();++m) { - if (m->first == newWorld.id()) { - for(std::vector::const_iterator r(newWorld.roots().begin());r!=newWorld.roots().end();++r) { - if (r->identity.address() == m->second) { - _moonSeeds.erase(m); - _moons.push_back(newWorld); - existing = &(_moons.back()); - break; - } - } - if (existing) { - break; - } - } - } - } - if (!existing) { - return false; - } - } else { - return false; - } + if (existing) { + if (existing->shouldBeReplacedBy(newWorld)) { + *existing = newWorld; + } + else { + return false; + } + } + else if (newWorld.type() == World::TYPE_MOON) { + if (alwaysAcceptNew) { + _moons.push_back(newWorld); + existing = &(_moons.back()); + } + else { + for (std::vector >::iterator m(_moonSeeds.begin()); m != _moonSeeds.end(); ++m) { + if (m->first == newWorld.id()) { + for (std::vector::const_iterator r(newWorld.roots().begin()); r != newWorld.roots().end(); ++r) { + if (r->identity.address() == m->second) { + _moonSeeds.erase(m); + _moons.push_back(newWorld); + existing = &(_moons.back()); + break; + } + } + if (existing) { + break; + } + } + } + } + if (! existing) { + return false; + } + } + else { + return false; + } - try { - Buffer sbuf; - existing->serialize(sbuf,false); - uint64_t idtmp[2]; - idtmp[0] = existing->id(); - idtmp[1] = 0; - RR->node->stateObjectPut(tPtr,(existing->type() == World::TYPE_PLANET) ? ZT_STATE_OBJECT_PLANET : ZT_STATE_OBJECT_MOON,idtmp,sbuf.data(),sbuf.size()); - } catch ( ... ) {} + try { + Buffer sbuf; + existing->serialize(sbuf, false); + uint64_t idtmp[2]; + idtmp[0] = existing->id(); + idtmp[1] = 0; + RR->node->stateObjectPut(tPtr, (existing->type() == World::TYPE_PLANET) ? ZT_STATE_OBJECT_PLANET : ZT_STATE_OBJECT_MOON, idtmp, sbuf.data(), sbuf.size()); + } + catch (...) { + } - _memoizeUpstreams(tPtr); + _memoizeUpstreams(tPtr); - return true; + return true; } -void Topology::addMoon(void *tPtr,const uint64_t id,const Address &seed) +void Topology::addMoon(void* tPtr, const uint64_t id, const Address& seed) { - char tmp[ZT_WORLD_MAX_SERIALIZED_LENGTH]; - uint64_t idtmp[2]; - idtmp[0] = id; - idtmp[1] = 0; - int n = RR->node->stateObjectGet(tPtr,ZT_STATE_OBJECT_MOON,idtmp,tmp,sizeof(tmp)); - if (n > 0) { - try { - World w; - w.deserialize(Buffer(tmp,(unsigned int)n)); - if ((w.type() == World::TYPE_MOON)&&(w.id() == id)) { - addWorld(tPtr,w,true); - return; - } - } catch ( ... ) {} - } + char tmp[ZT_WORLD_MAX_SERIALIZED_LENGTH]; + uint64_t idtmp[2]; + idtmp[0] = id; + idtmp[1] = 0; + int n = RR->node->stateObjectGet(tPtr, ZT_STATE_OBJECT_MOON, idtmp, tmp, sizeof(tmp)); + if (n > 0) { + try { + World w; + w.deserialize(Buffer(tmp, (unsigned int)n)); + if ((w.type() == World::TYPE_MOON) && (w.id() == id)) { + addWorld(tPtr, w, true); + return; + } + } + catch (...) { + } + } - if (seed) { - Mutex::Lock _l(_upstreams_m); - if (std::find(_moonSeeds.begin(),_moonSeeds.end(),std::pair(id,seed)) == _moonSeeds.end()) { - _moonSeeds.push_back(std::pair(id,seed)); - } - } + if (seed) { + Mutex::Lock _l(_upstreams_m); + if (std::find(_moonSeeds.begin(), _moonSeeds.end(), std::pair(id, seed)) == _moonSeeds.end()) { + _moonSeeds.push_back(std::pair(id, seed)); + } + } } -void Topology::removeMoon(void *tPtr,const uint64_t id) +void Topology::removeMoon(void* tPtr, const uint64_t id) { - Mutex::Lock _l2(_peers_m); - Mutex::Lock _l1(_upstreams_m); + Mutex::Lock _l2(_peers_m); + Mutex::Lock _l1(_upstreams_m); - std::vector nm; - for(std::vector::const_iterator m(_moons.begin());m!=_moons.end();++m) { - if (m->id() != id) { - nm.push_back(*m); - } else { - uint64_t idtmp[2]; - idtmp[0] = id; - idtmp[1] = 0; - RR->node->stateObjectDelete(tPtr,ZT_STATE_OBJECT_MOON,idtmp); - } - } - _moons.swap(nm); + std::vector nm; + for (std::vector::const_iterator m(_moons.begin()); m != _moons.end(); ++m) { + if (m->id() != id) { + nm.push_back(*m); + } + else { + uint64_t idtmp[2]; + idtmp[0] = id; + idtmp[1] = 0; + RR->node->stateObjectDelete(tPtr, ZT_STATE_OBJECT_MOON, idtmp); + } + } + _moons.swap(nm); - std::vector< std::pair > cm; - for(std::vector< std::pair >::const_iterator m(_moonSeeds.begin());m!=_moonSeeds.end();++m) { - if (m->first != id) { - cm.push_back(*m); - } - } - _moonSeeds.swap(cm); + std::vector > cm; + for (std::vector >::const_iterator m(_moonSeeds.begin()); m != _moonSeeds.end(); ++m) { + if (m->first != id) { + cm.push_back(*m); + } + } + _moonSeeds.swap(cm); - _memoizeUpstreams(tPtr); + _memoizeUpstreams(tPtr); } -void Topology::doPeriodicTasks(void *tPtr,int64_t now) +void Topology::doPeriodicTasks(void* tPtr, int64_t now) { - { - Mutex::Lock _l1(_peers_m); - Mutex::Lock _l2(_upstreams_m); - Hashtable< Address,SharedPtr >::Iterator i(_peers); - Address *a = (Address *)0; - SharedPtr *p = (SharedPtr *)0; - while (i.next(a,p)) { - if ( (!(*p)->isAlive(now)) && (std::find(_upstreamAddresses.begin(),_upstreamAddresses.end(),*a) == _upstreamAddresses.end()) ) { - _savePeer(tPtr,*p); - _peers.erase(*a); - } - } - } + { + Mutex::Lock _l1(_peers_m); + Mutex::Lock _l2(_upstreams_m); + Hashtable >::Iterator i(_peers); + Address* a = (Address*)0; + SharedPtr* p = (SharedPtr*)0; + while (i.next(a, p)) { + if ((! (*p)->isAlive(now)) && (std::find(_upstreamAddresses.begin(), _upstreamAddresses.end(), *a) == _upstreamAddresses.end())) { + _savePeer(tPtr, *p); + _peers.erase(*a); + } + } + } - { - Mutex::Lock _l(_paths_m); - Hashtable< Path::HashKey,SharedPtr >::Iterator i(_paths); - Path::HashKey *k = (Path::HashKey *)0; - SharedPtr *p = (SharedPtr *)0; - while (i.next(k,p)) { - if (p->references() <= 1) { - _paths.erase(*k); - } - } - } + { + Mutex::Lock _l(_paths_m); + Hashtable >::Iterator i(_paths); + Path::HashKey* k = (Path::HashKey*)0; + SharedPtr* p = (SharedPtr*)0; + while (i.next(k, p)) { + if (p->references() <= 1) { + _paths.erase(*k); + } + } + } } -void Topology::_memoizeUpstreams(void *tPtr) +void Topology::_memoizeUpstreams(void* tPtr) { - // assumes _upstreams_m and _peers_m are locked - _upstreamAddresses.clear(); - _amUpstream = false; + // assumes _upstreams_m and _peers_m are locked + _upstreamAddresses.clear(); + _amUpstream = false; - for(std::vector::const_iterator i(_planet.roots().begin());i!=_planet.roots().end();++i) { - const Identity &id = i->identity; - if (id == RR->identity) { - _amUpstream = true; - } else if (std::find(_upstreamAddresses.begin(),_upstreamAddresses.end(),id.address()) == _upstreamAddresses.end()) { - _upstreamAddresses.push_back(id.address()); - SharedPtr &hp = _peers[id.address()]; - if (!hp) { - hp = new Peer(RR,RR->identity,id); - } - } - } + for (std::vector::const_iterator i(_planet.roots().begin()); i != _planet.roots().end(); ++i) { + const Identity& id = i->identity; + if (id == RR->identity) { + _amUpstream = true; + } + else if (std::find(_upstreamAddresses.begin(), _upstreamAddresses.end(), id.address()) == _upstreamAddresses.end()) { + _upstreamAddresses.push_back(id.address()); + SharedPtr& hp = _peers[id.address()]; + if (! hp) { + hp = new Peer(RR, RR->identity, id); + } + } + } - for(std::vector::const_iterator m(_moons.begin());m!=_moons.end();++m) { - for(std::vector::const_iterator i(m->roots().begin());i!=m->roots().end();++i) { - if (i->identity == RR->identity) { - _amUpstream = true; - } else if (std::find(_upstreamAddresses.begin(),_upstreamAddresses.end(),i->identity.address()) == _upstreamAddresses.end()) { - _upstreamAddresses.push_back(i->identity.address()); - SharedPtr &hp = _peers[i->identity.address()]; - if (!hp) { - hp = new Peer(RR,RR->identity,i->identity); - } - } - } - } + for (std::vector::const_iterator m(_moons.begin()); m != _moons.end(); ++m) { + for (std::vector::const_iterator i(m->roots().begin()); i != m->roots().end(); ++i) { + if (i->identity == RR->identity) { + _amUpstream = true; + } + else if (std::find(_upstreamAddresses.begin(), _upstreamAddresses.end(), i->identity.address()) == _upstreamAddresses.end()) { + _upstreamAddresses.push_back(i->identity.address()); + SharedPtr& hp = _peers[i->identity.address()]; + if (! hp) { + hp = new Peer(RR, RR->identity, i->identity); + } + } + } + } - std::sort(_upstreamAddresses.begin(),_upstreamAddresses.end()); + std::sort(_upstreamAddresses.begin(), _upstreamAddresses.end()); } -void Topology::_savePeer(void *tPtr,const SharedPtr &peer) +void Topology::_savePeer(void* tPtr, const SharedPtr& peer) { - try { - Buffer buf; - peer->serializeForCache(buf); - uint64_t tmpid[2]; - tmpid[0] = peer->address().toInt(); - tmpid[1] = 0; - RR->node->stateObjectPut(tPtr,ZT_STATE_OBJECT_PEER,tmpid,buf.data(),buf.size()); - } catch ( ... ) {} // sanity check, discard invalid entries + try { + Buffer buf; + peer->serializeForCache(buf); + uint64_t tmpid[2]; + tmpid[0] = peer->address().toInt(); + tmpid[1] = 0; + RR->node->stateObjectPut(tPtr, ZT_STATE_OBJECT_PEER, tmpid, buf.data(), buf.size()); + } + catch (...) { + } // sanity check, discard invalid entries } -} // namespace ZeroTier +} // namespace ZeroTier diff --git a/node/Topology.hpp b/node/Topology.hpp index 53c2b6d5..59fbfc43 100644 --- a/node/Topology.hpp +++ b/node/Topology.hpp @@ -14,25 +14,23 @@ #ifndef ZT_TOPOLOGY_HPP #define ZT_TOPOLOGY_HPP +#include "../include/ZeroTierOne.h" +#include "Address.hpp" +#include "Constants.hpp" +#include "Hashtable.hpp" +#include "Identity.hpp" +#include "InetAddress.hpp" +#include "Mutex.hpp" +#include "Path.hpp" +#include "Peer.hpp" +#include "World.hpp" + +#include +#include #include #include - -#include -#include -#include #include - -#include "Constants.hpp" -#include "../include/ZeroTierOne.h" - -#include "Address.hpp" -#include "Identity.hpp" -#include "Peer.hpp" -#include "Path.hpp" -#include "Mutex.hpp" -#include "InetAddress.hpp" -#include "Hashtable.hpp" -#include "World.hpp" +#include namespace ZeroTier { @@ -41,428 +39,433 @@ class RuntimeEnvironment; /** * Database of network topology */ -class Topology -{ -public: - Topology(const RuntimeEnvironment *renv,void *tPtr); - ~Topology(); +class Topology { + public: + Topology(const RuntimeEnvironment* renv, void* tPtr); + ~Topology(); - /** - * Add a peer to database - * - * This will not replace existing peers. In that case the existing peer - * record is returned. - * - * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call - * @param peer Peer to add - * @return New or existing peer (should replace 'peer') - */ - SharedPtr addPeer(void *tPtr,const SharedPtr &peer); + /** + * Add a peer to database + * + * This will not replace existing peers. In that case the existing peer + * record is returned. + * + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call + * @param peer Peer to add + * @return New or existing peer (should replace 'peer') + */ + SharedPtr addPeer(void* tPtr, const SharedPtr& peer); - /** - * Get a peer from its address - * - * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call - * @param zta ZeroTier address of peer - * @return Peer or NULL if not found - */ - SharedPtr getPeer(void *tPtr,const Address &zta); + /** + * Get a peer from its address + * + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call + * @param zta ZeroTier address of peer + * @return Peer or NULL if not found + */ + SharedPtr getPeer(void* tPtr, const Address& zta); - /** - * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call - * @param zta ZeroTier address of peer - * @return Identity or NULL identity if not found - */ - Identity getIdentity(void *tPtr,const Address &zta); + /** + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call + * @param zta ZeroTier address of peer + * @return Identity or NULL identity if not found + */ + Identity getIdentity(void* tPtr, const Address& zta); - /** - * Get a peer only if it is presently in memory (no disk cache) - * - * This also does not update the lastUsed() time for peers, which means - * that it won't prevent them from falling out of RAM. This is currently - * used in the Cluster code to update peer info without forcing all peers - * across the entire cluster to remain in memory cache. - * - * @param zta ZeroTier address - */ - inline SharedPtr getPeerNoCache(const Address &zta) - { - Mutex::Lock _l(_peers_m); - const SharedPtr *const ap = _peers.get(zta); - if (ap) { - return *ap; - } - return SharedPtr(); - } + /** + * Get a peer only if it is presently in memory (no disk cache) + * + * This also does not update the lastUsed() time for peers, which means + * that it won't prevent them from falling out of RAM. This is currently + * used in the Cluster code to update peer info without forcing all peers + * across the entire cluster to remain in memory cache. + * + * @param zta ZeroTier address + */ + inline SharedPtr getPeerNoCache(const Address& zta) + { + Mutex::Lock _l(_peers_m); + const SharedPtr* const ap = _peers.get(zta); + if (ap) { + return *ap; + } + return SharedPtr(); + } - /** - * Get a Path object for a given local and remote physical address, creating if needed - * - * @param l Local socket - * @param r Remote address - * @return Pointer to canonicalized Path object - */ - inline SharedPtr getPath(const int64_t l,const InetAddress &r) - { - Mutex::Lock _l(_paths_m); - SharedPtr &p = _paths[Path::HashKey(l,r)]; - if (!p) { - p.set(new Path(l,r)); - } - return p; - } + /** + * Get a Path object for a given local and remote physical address, creating if needed + * + * @param l Local socket + * @param r Remote address + * @return Pointer to canonicalized Path object + */ + inline SharedPtr getPath(const int64_t l, const InetAddress& r) + { + Mutex::Lock _l(_paths_m); + SharedPtr& p = _paths[Path::HashKey(l, r)]; + if (! p) { + p.set(new Path(l, r)); + } + return p; + } - /** - * Get the current best upstream peer - * - * @return Upstream or NULL if none available - */ - SharedPtr getUpstreamPeer(); + /** + * Get the current best upstream peer + * + * @return Upstream or NULL if none available + */ + SharedPtr getUpstreamPeer(); - /** - * @param id Identity to check - * @return True if this is a root server or a network preferred relay from one of our networks - */ - bool isUpstream(const Identity &id) const; + /** + * @param id Identity to check + * @return True if this is a root server or a network preferred relay from one of our networks + */ + bool isUpstream(const Identity& id) const; - /** - * @param addr Address to check - * @return True if we should accept a world update from this address - */ - bool shouldAcceptWorldUpdateFrom(const Address &addr) const; + /** + * @param addr Address to check + * @return True if we should accept a world update from this address + */ + bool shouldAcceptWorldUpdateFrom(const Address& addr) const; - /** - * @param ztaddr ZeroTier address - * @return Peer role for this device - */ - ZT_PeerRole role(const Address &ztaddr) const; + /** + * @param ztaddr ZeroTier address + * @return Peer role for this device + */ + ZT_PeerRole role(const Address& ztaddr) const; - /** - * Check for prohibited endpoints - * - * Right now this returns true if the designated ZT address is a root and if - * the IP (IP only, not port) does not equal any of the IPs defined in the - * current World. This is an extra little security feature in case root keys - * get appropriated or something. - * - * Otherwise it returns false. - * - * @param ztaddr ZeroTier address - * @param ipaddr IP address - * @return True if this ZT/IP pair should not be allowed to be used - */ - bool isProhibitedEndpoint(const Address &ztaddr,const InetAddress &ipaddr) const; + /** + * Check for prohibited endpoints + * + * Right now this returns true if the designated ZT address is a root and if + * the IP (IP only, not port) does not equal any of the IPs defined in the + * current World. This is an extra little security feature in case root keys + * get appropriated or something. + * + * Otherwise it returns false. + * + * @param ztaddr ZeroTier address + * @param ipaddr IP address + * @return True if this ZT/IP pair should not be allowed to be used + */ + bool isProhibitedEndpoint(const Address& ztaddr, const InetAddress& ipaddr) const; - /** - * Gets upstreams to contact and their stable endpoints (if known) - * - * @param eps Hash table to fill with addresses and their stable endpoints - */ - inline void getUpstreamsToContact(Hashtable< Address,std::vector > &eps) const - { - Mutex::Lock _l(_upstreams_m); - for(std::vector::const_iterator i(_planet.roots().begin());i!=_planet.roots().end();++i) { - if (i->identity != RR->identity) { - std::vector &ips = eps[i->identity.address()]; - for(std::vector::const_iterator j(i->stableEndpoints.begin());j!=i->stableEndpoints.end();++j) { - if (std::find(ips.begin(),ips.end(),*j) == ips.end()) { - ips.push_back(*j); - } - } - } - } - for(std::vector::const_iterator m(_moons.begin());m!=_moons.end();++m) { - for(std::vector::const_iterator i(m->roots().begin());i!=m->roots().end();++i) { - if (i->identity != RR->identity) { - std::vector &ips = eps[i->identity.address()]; - for(std::vector::const_iterator j(i->stableEndpoints.begin());j!=i->stableEndpoints.end();++j) { - if (std::find(ips.begin(),ips.end(),*j) == ips.end()) { - ips.push_back(*j); - } - } - } - } - } - for(std::vector< std::pair >::const_iterator m(_moonSeeds.begin());m!=_moonSeeds.end();++m) { - eps[m->second]; - } - } + /** + * Gets upstreams to contact and their stable endpoints (if known) + * + * @param eps Hash table to fill with addresses and their stable endpoints + */ + inline void getUpstreamsToContact(Hashtable >& eps) const + { + Mutex::Lock _l(_upstreams_m); + for (std::vector::const_iterator i(_planet.roots().begin()); i != _planet.roots().end(); ++i) { + if (i->identity != RR->identity) { + std::vector& ips = eps[i->identity.address()]; + for (std::vector::const_iterator j(i->stableEndpoints.begin()); j != i->stableEndpoints.end(); ++j) { + if (std::find(ips.begin(), ips.end(), *j) == ips.end()) { + ips.push_back(*j); + } + } + } + } + for (std::vector::const_iterator m(_moons.begin()); m != _moons.end(); ++m) { + for (std::vector::const_iterator i(m->roots().begin()); i != m->roots().end(); ++i) { + if (i->identity != RR->identity) { + std::vector& ips = eps[i->identity.address()]; + for (std::vector::const_iterator j(i->stableEndpoints.begin()); j != i->stableEndpoints.end(); ++j) { + if (std::find(ips.begin(), ips.end(), *j) == ips.end()) { + ips.push_back(*j); + } + } + } + } + } + for (std::vector >::const_iterator m(_moonSeeds.begin()); m != _moonSeeds.end(); ++m) { + eps[m->second]; + } + } - /** - * @return Vector of active upstream addresses (including roots) - */ - inline std::vector
upstreamAddresses() const - { - Mutex::Lock _l(_upstreams_m); - return _upstreamAddresses; - } + /** + * @return Vector of active upstream addresses (including roots) + */ + inline std::vector
upstreamAddresses() const + { + Mutex::Lock _l(_upstreams_m); + return _upstreamAddresses; + } - /** - * @return Current moons - */ - inline std::vector moons() const - { - Mutex::Lock _l(_upstreams_m); - return _moons; - } + /** + * @return Current moons + */ + inline std::vector moons() const + { + Mutex::Lock _l(_upstreams_m); + return _moons; + } - /** - * @return Moon IDs we are waiting for from seeds - */ - inline std::vector moonsWanted() const - { - Mutex::Lock _l(_upstreams_m); - std::vector mw; - for(std::vector< std::pair >::const_iterator s(_moonSeeds.begin());s!=_moonSeeds.end();++s) { - if (std::find(mw.begin(),mw.end(),s->first) == mw.end()) { - mw.push_back(s->first); - } - } - return mw; - } + /** + * @return Moon IDs we are waiting for from seeds + */ + inline std::vector moonsWanted() const + { + Mutex::Lock _l(_upstreams_m); + std::vector mw; + for (std::vector >::const_iterator s(_moonSeeds.begin()); s != _moonSeeds.end(); ++s) { + if (std::find(mw.begin(), mw.end(), s->first) == mw.end()) { + mw.push_back(s->first); + } + } + return mw; + } - /** - * @return Current planet - */ - inline World planet() const - { - Mutex::Lock _l(_upstreams_m); - return _planet; - } + /** + * @return Current planet + */ + inline World planet() const + { + Mutex::Lock _l(_upstreams_m); + return _planet; + } - /** - * @return Current planet's world ID - */ - inline uint64_t planetWorldId() const - { - return _planet.id(); // safe to read without lock, and used from within eachPeer() so don't lock - } + /** + * @return Current planet's world ID + */ + inline uint64_t planetWorldId() const + { + return _planet.id(); // safe to read without lock, and used from within eachPeer() so don't lock + } - /** - * @return Current planet's world timestamp - */ - inline uint64_t planetWorldTimestamp() const - { - return _planet.timestamp(); // safe to read without lock, and used from within eachPeer() so don't lock - } + /** + * @return Current planet's world timestamp + */ + inline uint64_t planetWorldTimestamp() const + { + return _planet.timestamp(); // safe to read without lock, and used from within eachPeer() so don't lock + } - /** - * Validate new world and update if newer and signature is okay - * - * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call - * @param newWorld A new or updated planet or moon to learn - * @param alwaysAcceptNew If true, always accept new moons even if we're not waiting for one - * @return True if it was valid and newer than current (or totally new for moons) - */ - bool addWorld(void *tPtr,const World &newWorld,bool alwaysAcceptNew); + /** + * Validate new world and update if newer and signature is okay + * + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call + * @param newWorld A new or updated planet or moon to learn + * @param alwaysAcceptNew If true, always accept new moons even if we're not waiting for one + * @return True if it was valid and newer than current (or totally new for moons) + */ + bool addWorld(void* tPtr, const World& newWorld, bool alwaysAcceptNew); - /** - * Add a moon - * - * This loads it from moons.d if present, and if not adds it to - * a list of moons that we want to contact. - * - * @param id Moon ID - * @param seed If non-NULL, an address of any member of the moon to contact - */ - void addMoon(void *tPtr,const uint64_t id,const Address &seed); + /** + * Add a moon + * + * This loads it from moons.d if present, and if not adds it to + * a list of moons that we want to contact. + * + * @param id Moon ID + * @param seed If non-NULL, an address of any member of the moon to contact + */ + void addMoon(void* tPtr, const uint64_t id, const Address& seed); - /** - * Remove a moon - * - * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call - * @param id Moon's world ID - */ - void removeMoon(void *tPtr,const uint64_t id); + /** + * Remove a moon + * + * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call + * @param id Moon's world ID + */ + void removeMoon(void* tPtr, const uint64_t id); - /** - * Clean and flush database - */ - void doPeriodicTasks(void *tPtr,int64_t now); + /** + * Clean and flush database + */ + void doPeriodicTasks(void* tPtr, int64_t now); - /** - * @param now Current time - * @return Number of peers with active direct paths - */ - inline unsigned long countActive(int64_t now) const - { - unsigned long cnt = 0; - Mutex::Lock _l(_peers_m); - Hashtable< Address,SharedPtr >::Iterator i(const_cast(this)->_peers); - Address *a = (Address *)0; - SharedPtr *p = (SharedPtr *)0; - while (i.next(a,p)) { - const SharedPtr pp((*p)->getAppropriatePath(now,false)); - if (pp) { - ++cnt; - } - } - return cnt; - } + /** + * @param now Current time + * @return Number of peers with active direct paths + */ + inline unsigned long countActive(int64_t now) const + { + unsigned long cnt = 0; + Mutex::Lock _l(_peers_m); + Hashtable >::Iterator i(const_cast(this)->_peers); + Address* a = (Address*)0; + SharedPtr* p = (SharedPtr*)0; + while (i.next(a, p)) { + const SharedPtr pp((*p)->getAppropriatePath(now, false)); + if (pp) { + ++cnt; + } + } + return cnt; + } - /** - * Apply a function or function object to all peers - * - * @param f Function to apply - * @tparam F Function or function object type - */ - template - inline void eachPeer(F f) - { - Mutex::Lock _l(_peers_m); - Hashtable< Address,SharedPtr >::Iterator i(_peers); - Address *a = (Address *)0; - SharedPtr *p = (SharedPtr *)0; - while (i.next(a,p)) { - f(*this,*((const SharedPtr *)p)); - } - } + /** + * Apply a function or function object to all peers + * + * @param f Function to apply + * @tparam F Function or function object type + */ + template inline void eachPeer(F f) + { + Mutex::Lock _l(_peers_m); + Hashtable >::Iterator i(_peers); + Address* a = (Address*)0; + SharedPtr* p = (SharedPtr*)0; + while (i.next(a, p)) { + f(*this, *((const SharedPtr*)p)); + } + } - /** - * @return All currently active peers by address (unsorted) - */ - inline std::vector< std::pair< Address,SharedPtr > > allPeers() const - { - Mutex::Lock _l(_peers_m); - return _peers.entries(); - } + /** + * @return All currently active peers by address (unsorted) + */ + inline std::vector > > allPeers() const + { + Mutex::Lock _l(_peers_m); + return _peers.entries(); + } - /** - * @return True if I am a root server in a planet or moon - */ - inline bool amUpstream() const { return _amUpstream; } + /** + * @return True if I am a root server in a planet or moon + */ + inline bool amUpstream() const + { + return _amUpstream; + } - /** - * Get info about a path - * - * The supplied result variables are not modified if no special config info is found. - * - * @param physicalAddress Physical endpoint address - * @param mtu Variable set to MTU - * @param trustedPathId Variable set to trusted path ID - */ - inline void getOutboundPathInfo(const InetAddress &physicalAddress,unsigned int &mtu,uint64_t &trustedPathId) - { - for(unsigned int i=0,j=_numConfiguredPhysicalPaths;i cpaths; - for(unsigned int i=0,j=_numConfiguredPhysicalPaths;i cpaths; + for (unsigned int i = 0, j = _numConfiguredPhysicalPaths; i < j; ++i) { + cpaths[_physicalPathConfig[i].first] = _physicalPathConfig[i].second; + } - if (pathConfig) { - ZT_PhysicalPathConfiguration pc(*pathConfig); + if (pathConfig) { + ZT_PhysicalPathConfiguration pc(*pathConfig); - if (pc.mtu <= 0) { - pc.mtu = ZT_DEFAULT_PHYSMTU; - } else if (pc.mtu < ZT_MIN_PHYSMTU) { - pc.mtu = ZT_MIN_PHYSMTU; - } else if (pc.mtu > ZT_MAX_PHYSMTU) { - pc.mtu = ZT_MAX_PHYSMTU; - } + if (pc.mtu <= 0) { + pc.mtu = ZT_DEFAULT_PHYSMTU; + } + else if (pc.mtu < ZT_MIN_PHYSMTU) { + pc.mtu = ZT_MIN_PHYSMTU; + } + else if (pc.mtu > ZT_MAX_PHYSMTU) { + pc.mtu = ZT_MAX_PHYSMTU; + } - cpaths[*(reinterpret_cast(pathNetwork))] = pc; - } else { - cpaths.erase(*(reinterpret_cast(pathNetwork))); - } + cpaths[*(reinterpret_cast(pathNetwork))] = pc; + } + else { + cpaths.erase(*(reinterpret_cast(pathNetwork))); + } - unsigned int cnt = 0; - for(std::map::const_iterator i(cpaths.begin());((i!=cpaths.end())&&(cntfirst; - _physicalPathConfig[cnt].second = i->second; - ++cnt; - } - _numConfiguredPhysicalPaths = cnt; - } - } + unsigned int cnt = 0; + for (std::map::const_iterator i(cpaths.begin()); ((i != cpaths.end()) && (cnt < ZT_MAX_CONFIGURABLE_PATHS)); ++i) { + _physicalPathConfig[cnt].first = i->first; + _physicalPathConfig[cnt].second = i->second; + ++cnt; + } + _numConfiguredPhysicalPaths = cnt; + } + } -private: - Identity _getIdentity(void *tPtr,const Address &zta); - void _memoizeUpstreams(void *tPtr); - void _savePeer(void *tPtr,const SharedPtr &peer); + private: + Identity _getIdentity(void* tPtr, const Address& zta); + void _memoizeUpstreams(void* tPtr); + void _savePeer(void* tPtr, const SharedPtr& peer); - const RuntimeEnvironment *const RR; + const RuntimeEnvironment* const RR; - std::pair _physicalPathConfig[ZT_MAX_CONFIGURABLE_PATHS]; - volatile unsigned int _numConfiguredPhysicalPaths; + std::pair _physicalPathConfig[ZT_MAX_CONFIGURABLE_PATHS]; + volatile unsigned int _numConfiguredPhysicalPaths; - Hashtable< Address,SharedPtr > _peers; - Mutex _peers_m; + Hashtable > _peers; + Mutex _peers_m; - Hashtable< Path::HashKey,SharedPtr > _paths; - Mutex _paths_m; + Hashtable > _paths; + Mutex _paths_m; - World _planet; - std::vector _moons; - std::vector< std::pair > _moonSeeds; - std::vector
_upstreamAddresses; - bool _amUpstream; - Mutex _upstreams_m; // locks worlds, upstream info, moon info, etc. + World _planet; + std::vector _moons; + std::vector > _moonSeeds; + std::vector
_upstreamAddresses; + bool _amUpstream; + Mutex _upstreams_m; // locks worlds, upstream info, moon info, etc. }; -} // namespace ZeroTier +} // namespace ZeroTier #endif diff --git a/node/Trace.cpp b/node/Trace.cpp index b6e72e31..69b064a5 100644 --- a/node/Trace.cpp +++ b/node/Trace.cpp @@ -11,601 +11,641 @@ */ /****/ -//#define ZT_TRACE - -#include -#include +// #define ZT_TRACE #include "Trace.hpp" -#include "RuntimeEnvironment.hpp" -#include "Switch.hpp" -#include "Node.hpp" -#include "Utils.hpp" -#include "Dictionary.hpp" + +#include "../include/ZeroTierDebug.h" +#include "Capability.hpp" #include "CertificateOfMembership.hpp" #include "CertificateOfOwnership.hpp" -#include "Tag.hpp" -#include "Capability.hpp" +#include "Dictionary.hpp" +#include "Node.hpp" #include "Revocation.hpp" -#include "../include/ZeroTierDebug.h" +#include "RuntimeEnvironment.hpp" +#include "Switch.hpp" +#include "Tag.hpp" +#include "Utils.hpp" + +#include +#include namespace ZeroTier { #ifdef ZT_TRACE -static void ZT_LOCAL_TRACE(void *const tPtr,const RuntimeEnvironment *const RR,const char *const fmt,...) +static void ZT_LOCAL_TRACE(void* const tPtr, const RuntimeEnvironment* const RR, const char* const fmt, ...) { - char traceMsgBuf[1024]; - va_list ap; - va_start(ap,fmt); - vsnprintf(traceMsgBuf,sizeof(traceMsgBuf),fmt,ap); - va_end(ap); - traceMsgBuf[sizeof(traceMsgBuf) - 1] = (char)0; - RR->node->postEvent(tPtr,ZT_EVENT_TRACE,traceMsgBuf); + char traceMsgBuf[1024]; + va_list ap; + va_start(ap, fmt); + vsnprintf(traceMsgBuf, sizeof(traceMsgBuf), fmt, ap); + va_end(ap); + traceMsgBuf[sizeof(traceMsgBuf) - 1] = (char)0; + RR->node->postEvent(tPtr, ZT_EVENT_TRACE, traceMsgBuf); } #else #define ZT_LOCAL_TRACE(...) #endif -void Trace::resettingPathsInScope(void *const tPtr,const Address &reporter,const InetAddress &reporterPhysicalAddress,const InetAddress &myPhysicalAddress,const InetAddress::IpScope scope) +void Trace::resettingPathsInScope(void* const tPtr, const Address& reporter, const InetAddress& reporterPhysicalAddress, const InetAddress& myPhysicalAddress, const InetAddress::IpScope scope) { - char tmp[128]; + char tmp[128]; - ZT_LOCAL_TRACE(tPtr,RR,"RESET and revalidate paths in scope %d; new phy address %s reported by trusted peer %.10llx",(int)scope,myPhysicalAddress.toIpString(tmp),reporter.toInt()); + ZT_LOCAL_TRACE(tPtr, RR, "RESET and revalidate paths in scope %d; new phy address %s reported by trusted peer %.10llx", (int)scope, myPhysicalAddress.toIpString(tmp), reporter.toInt()); - Dictionary d; - d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__RESETTING_PATHS_IN_SCOPE_S); - d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_ZTADDR,reporter); - d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_PHYADDR,reporterPhysicalAddress.toString(tmp)); - d.add(ZT_REMOTE_TRACE_FIELD__LOCAL_PHYADDR,myPhysicalAddress.toString(tmp)); - d.add(ZT_REMOTE_TRACE_FIELD__IP_SCOPE,(uint64_t)scope); + Dictionary d; + d.add(ZT_REMOTE_TRACE_FIELD__EVENT, ZT_REMOTE_TRACE_EVENT__RESETTING_PATHS_IN_SCOPE_S); + d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_ZTADDR, reporter); + d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_PHYADDR, reporterPhysicalAddress.toString(tmp)); + d.add(ZT_REMOTE_TRACE_FIELD__LOCAL_PHYADDR, myPhysicalAddress.toString(tmp)); + d.add(ZT_REMOTE_TRACE_FIELD__IP_SCOPE, (uint64_t)scope); - if (_globalTarget) { - _send(tPtr,d,_globalTarget); - } - _spamToAllNetworks(tPtr,d,Trace::LEVEL_NORMAL); + if (_globalTarget) { + _send(tPtr, d, _globalTarget); + } + _spamToAllNetworks(tPtr, d, Trace::LEVEL_NORMAL); } -void Trace::peerConfirmingUnknownPath(void *const tPtr,const uint64_t networkId,Peer &peer,const SharedPtr &path,const uint64_t packetId,const Packet::Verb verb) +void Trace::peerConfirmingUnknownPath(void* const tPtr, const uint64_t networkId, Peer& peer, const SharedPtr& path, const uint64_t packetId, const Packet::Verb verb) { - char tmp[128]; - if (!path) { - return; // sanity check - } + char tmp[128]; + if (! path) { + return; // sanity check + } - ZT_LOCAL_TRACE(tPtr,RR,"trying unknown path %s to %.10llx (packet %.16llx verb %d local socket %lld network %.16llx)",path->address().toString(tmp),peer.address().toInt(),packetId,verb,path->localSocket(),networkId); + ZT_LOCAL_TRACE(tPtr, RR, "trying unknown path %s to %.10llx (packet %.16llx verb %d local socket %lld network %.16llx)", path->address().toString(tmp), peer.address().toInt(), packetId, verb, path->localSocket(), networkId); - std::pair byn; - if (networkId) { - Mutex::Lock l(_byNet_m); - _byNet.get(networkId,byn); - } + std::pair byn; + if (networkId) { + Mutex::Lock l(_byNet_m); + _byNet.get(networkId, byn); + } - if ((_globalTarget)||(byn.first)) { - Dictionary d; - d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__PEER_CONFIRMING_UNKNOWN_PATH_S); - d.add(ZT_REMOTE_TRACE_FIELD__PACKET_ID,packetId); - d.add(ZT_REMOTE_TRACE_FIELD__PACKET_VERB,(uint64_t)verb); - if (networkId) { - d.add(ZT_REMOTE_TRACE_FIELD__NETWORK_ID,networkId); - } - d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_ZTADDR,peer.address()); - if (path) { - d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_PHYADDR,path->address().toString(tmp)); - d.add(ZT_REMOTE_TRACE_FIELD__LOCAL_SOCKET,path->localSocket()); - } + if ((_globalTarget) || (byn.first)) { + Dictionary d; + d.add(ZT_REMOTE_TRACE_FIELD__EVENT, ZT_REMOTE_TRACE_EVENT__PEER_CONFIRMING_UNKNOWN_PATH_S); + d.add(ZT_REMOTE_TRACE_FIELD__PACKET_ID, packetId); + d.add(ZT_REMOTE_TRACE_FIELD__PACKET_VERB, (uint64_t)verb); + if (networkId) { + d.add(ZT_REMOTE_TRACE_FIELD__NETWORK_ID, networkId); + } + d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_ZTADDR, peer.address()); + if (path) { + d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_PHYADDR, path->address().toString(tmp)); + d.add(ZT_REMOTE_TRACE_FIELD__LOCAL_SOCKET, path->localSocket()); + } - if (_globalTarget) { - _send(tPtr,d,_globalTarget); - } - if (byn.first) { - _send(tPtr,d,byn.first); - } - } + if (_globalTarget) { + _send(tPtr, d, _globalTarget); + } + if (byn.first) { + _send(tPtr, d, byn.first); + } + } } -void Trace::bondStateMessage(void *const tPtr,char *msg) +void Trace::bondStateMessage(void* const tPtr, char* msg) { - ZT_LOCAL_TRACE(tPtr,RR,"%s",msg); + ZT_LOCAL_TRACE(tPtr, RR, "%s", msg); } -void Trace::peerLearnedNewPath(void *const tPtr,const uint64_t networkId,Peer &peer,const SharedPtr &newPath,const uint64_t packetId) +void Trace::peerLearnedNewPath(void* const tPtr, const uint64_t networkId, Peer& peer, const SharedPtr& newPath, const uint64_t packetId) { - char tmp[128]; - if (!newPath) { - return; // sanity check - } + char tmp[128]; + if (! newPath) { + return; // sanity check + } - ZT_LOCAL_TRACE(tPtr,RR,"learned new path %s to %.10llx (packet %.16llx local socket %lld network %.16llx)",newPath->address().toString(tmp),peer.address().toInt(),packetId,newPath->localSocket(),networkId); + ZT_LOCAL_TRACE(tPtr, RR, "learned new path %s to %.10llx (packet %.16llx local socket %lld network %.16llx)", newPath->address().toString(tmp), peer.address().toInt(), packetId, newPath->localSocket(), networkId); - std::pair byn; - if (networkId) { - Mutex::Lock l(_byNet_m); - _byNet.get(networkId,byn); - } + std::pair byn; + if (networkId) { + Mutex::Lock l(_byNet_m); + _byNet.get(networkId, byn); + } - if ((_globalTarget)||(byn.first)) { - Dictionary d; - d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__PEER_LEARNED_NEW_PATH_S); - d.add(ZT_REMOTE_TRACE_FIELD__PACKET_ID,packetId); - if (networkId) { - d.add(ZT_REMOTE_TRACE_FIELD__NETWORK_ID, networkId); - } - d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_ZTADDR,peer.address()); - d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_PHYADDR,newPath->address().toString(tmp)); - d.add(ZT_REMOTE_TRACE_FIELD__LOCAL_SOCKET,newPath->localSocket()); + if ((_globalTarget) || (byn.first)) { + Dictionary d; + d.add(ZT_REMOTE_TRACE_FIELD__EVENT, ZT_REMOTE_TRACE_EVENT__PEER_LEARNED_NEW_PATH_S); + d.add(ZT_REMOTE_TRACE_FIELD__PACKET_ID, packetId); + if (networkId) { + d.add(ZT_REMOTE_TRACE_FIELD__NETWORK_ID, networkId); + } + d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_ZTADDR, peer.address()); + d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_PHYADDR, newPath->address().toString(tmp)); + d.add(ZT_REMOTE_TRACE_FIELD__LOCAL_SOCKET, newPath->localSocket()); - if (_globalTarget) { - _send(tPtr,d,_globalTarget); - } - if (byn.first) { - _send(tPtr,d,byn.first); - } - } + if (_globalTarget) { + _send(tPtr, d, _globalTarget); + } + if (byn.first) { + _send(tPtr, d, byn.first); + } + } } -void Trace::peerRedirected(void *const tPtr,const uint64_t networkId,Peer &peer,const SharedPtr &newPath) +void Trace::peerRedirected(void* const tPtr, const uint64_t networkId, Peer& peer, const SharedPtr& newPath) { - char tmp[128]; - if (!newPath) { - return; // sanity check - } + char tmp[128]; + if (! newPath) { + return; // sanity check + } - ZT_LOCAL_TRACE(tPtr,RR,"explicit redirect from %.10llx to path %s",peer.address().toInt(),newPath->address().toString(tmp)); + ZT_LOCAL_TRACE(tPtr, RR, "explicit redirect from %.10llx to path %s", peer.address().toInt(), newPath->address().toString(tmp)); - std::pair byn; - if (networkId) { - Mutex::Lock l(_byNet_m); - _byNet.get(networkId,byn); - } + std::pair byn; + if (networkId) { + Mutex::Lock l(_byNet_m); + _byNet.get(networkId, byn); + } - if ((_globalTarget)||(byn.first)) { - Dictionary d; - d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__PEER_REDIRECTED_S); - if (networkId) { - d.add(ZT_REMOTE_TRACE_FIELD__NETWORK_ID,networkId); - } - d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_ZTADDR,peer.address()); - d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_PHYADDR,newPath->address().toString(tmp)); - d.add(ZT_REMOTE_TRACE_FIELD__LOCAL_SOCKET,newPath->localSocket()); + if ((_globalTarget) || (byn.first)) { + Dictionary d; + d.add(ZT_REMOTE_TRACE_FIELD__EVENT, ZT_REMOTE_TRACE_EVENT__PEER_REDIRECTED_S); + if (networkId) { + d.add(ZT_REMOTE_TRACE_FIELD__NETWORK_ID, networkId); + } + d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_ZTADDR, peer.address()); + d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_PHYADDR, newPath->address().toString(tmp)); + d.add(ZT_REMOTE_TRACE_FIELD__LOCAL_SOCKET, newPath->localSocket()); - if (_globalTarget) { - _send(tPtr,d,_globalTarget); - } - if (byn.first) { - _send(tPtr,d,byn.first); - } - } + if (_globalTarget) { + _send(tPtr, d, _globalTarget); + } + if (byn.first) { + _send(tPtr, d, byn.first); + } + } } -void Trace::outgoingNetworkFrameDropped(void *const tPtr,const SharedPtr &network,const MAC &sourceMac,const MAC &destMac,const unsigned int etherType,const unsigned int vlanId,const unsigned int frameLen,const char *reason) +void Trace::outgoingNetworkFrameDropped(void* const tPtr, const SharedPtr& network, const MAC& sourceMac, const MAC& destMac, const unsigned int etherType, const unsigned int vlanId, const unsigned int frameLen, const char* reason) { #ifdef ZT_TRACE - char tmp[128],tmp2[128]; + char tmp[128], tmp2[128]; #endif - if (!network) { - return; // sanity check - } + if (! network) { + return; // sanity check + } - ZT_LOCAL_TRACE(tPtr,RR,"%.16llx DROP frame %s -> %s etherType %.4x size %u (%s)",network->id(),sourceMac.toString(tmp),destMac.toString(tmp2),etherType,frameLen,(reason) ? reason : "unknown reason"); + ZT_LOCAL_TRACE(tPtr, RR, "%.16llx DROP frame %s -> %s etherType %.4x size %u (%s)", network->id(), sourceMac.toString(tmp), destMac.toString(tmp2), etherType, frameLen, (reason) ? reason : "unknown reason"); - std::pair byn; - { Mutex::Lock l(_byNet_m); _byNet.get(network->id(),byn); } + std::pair byn; + { + Mutex::Lock l(_byNet_m); + _byNet.get(network->id(), byn); + } - if ( ((_globalTarget)&&((int)_globalLevel >= (int)Trace::LEVEL_VERBOSE)) || ((byn.first)&&((int)byn.second >= (int)Trace::LEVEL_VERBOSE)) ) { - Dictionary d; - d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__OUTGOING_NETWORK_FRAME_DROPPED_S); - d.add(ZT_REMOTE_TRACE_FIELD__NETWORK_ID,network->id()); - d.add(ZT_REMOTE_TRACE_FIELD__SOURCE_MAC,sourceMac.toInt()); - d.add(ZT_REMOTE_TRACE_FIELD__DEST_MAC,destMac.toInt()); - d.add(ZT_REMOTE_TRACE_FIELD__ETHERTYPE,(uint64_t)etherType); - d.add(ZT_REMOTE_TRACE_FIELD__VLAN_ID,(uint64_t)vlanId); - d.add(ZT_REMOTE_TRACE_FIELD__FRAME_LENGTH,(uint64_t)frameLen); - if (reason) { - d.add(ZT_REMOTE_TRACE_FIELD__REASON,reason); - } + if (((_globalTarget) && ((int)_globalLevel >= (int)Trace::LEVEL_VERBOSE)) || ((byn.first) && ((int)byn.second >= (int)Trace::LEVEL_VERBOSE))) { + Dictionary d; + d.add(ZT_REMOTE_TRACE_FIELD__EVENT, ZT_REMOTE_TRACE_EVENT__OUTGOING_NETWORK_FRAME_DROPPED_S); + d.add(ZT_REMOTE_TRACE_FIELD__NETWORK_ID, network->id()); + d.add(ZT_REMOTE_TRACE_FIELD__SOURCE_MAC, sourceMac.toInt()); + d.add(ZT_REMOTE_TRACE_FIELD__DEST_MAC, destMac.toInt()); + d.add(ZT_REMOTE_TRACE_FIELD__ETHERTYPE, (uint64_t)etherType); + d.add(ZT_REMOTE_TRACE_FIELD__VLAN_ID, (uint64_t)vlanId); + d.add(ZT_REMOTE_TRACE_FIELD__FRAME_LENGTH, (uint64_t)frameLen); + if (reason) { + d.add(ZT_REMOTE_TRACE_FIELD__REASON, reason); + } - if ((_globalTarget)&&((int)_globalLevel >= (int)Trace::LEVEL_VERBOSE)) { - _send(tPtr,d,_globalTarget); - } - if ((byn.first)&&((int)byn.second >= (int)Trace::LEVEL_VERBOSE)) { - _send(tPtr,d,byn.first); - } - } + if ((_globalTarget) && ((int)_globalLevel >= (int)Trace::LEVEL_VERBOSE)) { + _send(tPtr, d, _globalTarget); + } + if ((byn.first) && ((int)byn.second >= (int)Trace::LEVEL_VERBOSE)) { + _send(tPtr, d, byn.first); + } + } } -void Trace::incomingNetworkAccessDenied(void *const tPtr,const SharedPtr &network,const SharedPtr &path,const uint64_t packetId,const unsigned int packetLength,const Address &source,const Packet::Verb verb,bool credentialsRequested) +void Trace::incomingNetworkAccessDenied( + void* const tPtr, + const SharedPtr& network, + const SharedPtr& path, + const uint64_t packetId, + const unsigned int packetLength, + const Address& source, + const Packet::Verb verb, + bool credentialsRequested) { - char tmp[128]; - if (!network) { - return; // sanity check - } + char tmp[128]; + if (! network) { + return; // sanity check + } - ZT_LOCAL_TRACE(tPtr,RR,"%.16llx DENIED packet from %.10llx(%s) verb %d size %u%s",network->id(),source.toInt(),(path) ? (path->address().toString(tmp)) : "???",(int)verb,packetLength,credentialsRequested ? " (credentials requested)" : " (credentials not requested)"); + ZT_LOCAL_TRACE( + tPtr, + RR, + "%.16llx DENIED packet from %.10llx(%s) verb %d size %u%s", + network->id(), + source.toInt(), + (path) ? (path->address().toString(tmp)) : "???", + (int)verb, + packetLength, + credentialsRequested ? " (credentials requested)" : " (credentials not requested)"); - std::pair byn; - { Mutex::Lock l(_byNet_m); _byNet.get(network->id(),byn); } + std::pair byn; + { + Mutex::Lock l(_byNet_m); + _byNet.get(network->id(), byn); + } - if ( ((_globalTarget)&&((int)_globalLevel >= (int)Trace::LEVEL_VERBOSE)) || ((byn.first)&&((int)byn.second >= (int)Trace::LEVEL_VERBOSE)) ) { - Dictionary d; - d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__INCOMING_NETWORK_ACCESS_DENIED_S); - d.add(ZT_REMOTE_TRACE_FIELD__PACKET_ID,packetId); - d.add(ZT_REMOTE_TRACE_FIELD__PACKET_VERB,(uint64_t)verb); - d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_ZTADDR,source); - if (path) { - d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_PHYADDR,path->address().toString(tmp)); - d.add(ZT_REMOTE_TRACE_FIELD__LOCAL_SOCKET,path->localSocket()); - } - d.add(ZT_REMOTE_TRACE_FIELD__NETWORK_ID,network->id()); + if (((_globalTarget) && ((int)_globalLevel >= (int)Trace::LEVEL_VERBOSE)) || ((byn.first) && ((int)byn.second >= (int)Trace::LEVEL_VERBOSE))) { + Dictionary d; + d.add(ZT_REMOTE_TRACE_FIELD__EVENT, ZT_REMOTE_TRACE_EVENT__INCOMING_NETWORK_ACCESS_DENIED_S); + d.add(ZT_REMOTE_TRACE_FIELD__PACKET_ID, packetId); + d.add(ZT_REMOTE_TRACE_FIELD__PACKET_VERB, (uint64_t)verb); + d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_ZTADDR, source); + if (path) { + d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_PHYADDR, path->address().toString(tmp)); + d.add(ZT_REMOTE_TRACE_FIELD__LOCAL_SOCKET, path->localSocket()); + } + d.add(ZT_REMOTE_TRACE_FIELD__NETWORK_ID, network->id()); - if ((_globalTarget)&&((int)_globalLevel >= (int)Trace::LEVEL_VERBOSE)) { - _send(tPtr,d,_globalTarget); - } - if ((byn.first)&&((int)byn.second >= (int)Trace::LEVEL_VERBOSE)) { - _send(tPtr,d,byn.first); - } - } + if ((_globalTarget) && ((int)_globalLevel >= (int)Trace::LEVEL_VERBOSE)) { + _send(tPtr, d, _globalTarget); + } + if ((byn.first) && ((int)byn.second >= (int)Trace::LEVEL_VERBOSE)) { + _send(tPtr, d, byn.first); + } + } } -void Trace::incomingNetworkFrameDropped(void *const tPtr,const SharedPtr &network,const SharedPtr &path,const uint64_t packetId,const unsigned int packetLength,const Address &source,const Packet::Verb verb,const MAC &sourceMac,const MAC &destMac,const char *reason) +void Trace::incomingNetworkFrameDropped( + void* const tPtr, + const SharedPtr& network, + const SharedPtr& path, + const uint64_t packetId, + const unsigned int packetLength, + const Address& source, + const Packet::Verb verb, + const MAC& sourceMac, + const MAC& destMac, + const char* reason) { - char tmp[128]; - if (!network) { - return; // sanity check - } + char tmp[128]; + if (! network) { + return; // sanity check + } - ZT_LOCAL_TRACE(tPtr,RR,"%.16llx DROPPED frame from %.10llx(%s) verb %d size %u",network->id(),source.toInt(),(path) ? (path->address().toString(tmp)) : "???",(int)verb,packetLength); + ZT_LOCAL_TRACE(tPtr, RR, "%.16llx DROPPED frame from %.10llx(%s) verb %d size %u", network->id(), source.toInt(), (path) ? (path->address().toString(tmp)) : "???", (int)verb, packetLength); - std::pair byn; - { Mutex::Lock l(_byNet_m); _byNet.get(network->id(),byn); } + std::pair byn; + { + Mutex::Lock l(_byNet_m); + _byNet.get(network->id(), byn); + } - if ( ((_globalTarget)&&((int)_globalLevel >= (int)Trace::LEVEL_VERBOSE)) || ((byn.first)&&((int)byn.second >= (int)Trace::LEVEL_VERBOSE)) ) { - Dictionary d; - d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__INCOMING_NETWORK_FRAME_DROPPED_S); - d.add(ZT_REMOTE_TRACE_FIELD__PACKET_ID,packetId); - d.add(ZT_REMOTE_TRACE_FIELD__PACKET_VERB,(uint64_t)verb); - d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_ZTADDR,source); - if (path) { - d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_PHYADDR,path->address().toString(tmp)); - d.add(ZT_REMOTE_TRACE_FIELD__LOCAL_SOCKET,path->localSocket()); - } - d.add(ZT_REMOTE_TRACE_FIELD__NETWORK_ID,network->id()); - d.add(ZT_REMOTE_TRACE_FIELD__SOURCE_MAC,sourceMac.toInt()); - d.add(ZT_REMOTE_TRACE_FIELD__DEST_MAC,destMac.toInt()); - if (reason) { - d.add(ZT_REMOTE_TRACE_FIELD__REASON,reason); - } + if (((_globalTarget) && ((int)_globalLevel >= (int)Trace::LEVEL_VERBOSE)) || ((byn.first) && ((int)byn.second >= (int)Trace::LEVEL_VERBOSE))) { + Dictionary d; + d.add(ZT_REMOTE_TRACE_FIELD__EVENT, ZT_REMOTE_TRACE_EVENT__INCOMING_NETWORK_FRAME_DROPPED_S); + d.add(ZT_REMOTE_TRACE_FIELD__PACKET_ID, packetId); + d.add(ZT_REMOTE_TRACE_FIELD__PACKET_VERB, (uint64_t)verb); + d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_ZTADDR, source); + if (path) { + d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_PHYADDR, path->address().toString(tmp)); + d.add(ZT_REMOTE_TRACE_FIELD__LOCAL_SOCKET, path->localSocket()); + } + d.add(ZT_REMOTE_TRACE_FIELD__NETWORK_ID, network->id()); + d.add(ZT_REMOTE_TRACE_FIELD__SOURCE_MAC, sourceMac.toInt()); + d.add(ZT_REMOTE_TRACE_FIELD__DEST_MAC, destMac.toInt()); + if (reason) { + d.add(ZT_REMOTE_TRACE_FIELD__REASON, reason); + } - if ((_globalTarget)&&((int)_globalLevel >= (int)Trace::LEVEL_VERBOSE)) { - _send(tPtr,d,_globalTarget); - } - if ((byn.first)&&((int)byn.second >= (int)Trace::LEVEL_VERBOSE)) { - _send(tPtr,d,byn.first); - } - } + if ((_globalTarget) && ((int)_globalLevel >= (int)Trace::LEVEL_VERBOSE)) { + _send(tPtr, d, _globalTarget); + } + if ((byn.first) && ((int)byn.second >= (int)Trace::LEVEL_VERBOSE)) { + _send(tPtr, d, byn.first); + } + } } -void Trace::incomingPacketMessageAuthenticationFailure(void *const tPtr,const SharedPtr &path,const uint64_t packetId,const Address &source,const unsigned int hops,const char *reason) +void Trace::incomingPacketMessageAuthenticationFailure(void* const tPtr, const SharedPtr& path, const uint64_t packetId, const Address& source, const unsigned int hops, const char* reason) { - char tmp[128]; + char tmp[128]; - ZT_LOCAL_TRACE(tPtr,RR,"MAC failed for packet %.16llx from %.10llx(%s)",packetId,source.toInt(),(path) ? path->address().toString(tmp) : "???"); + ZT_LOCAL_TRACE(tPtr, RR, "MAC failed for packet %.16llx from %.10llx(%s)", packetId, source.toInt(), (path) ? path->address().toString(tmp) : "???"); - if ((_globalTarget)&&((int)_globalLevel >= Trace::LEVEL_DEBUG)) { - Dictionary d; - d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__PACKET_MAC_FAILURE_S); - d.add(ZT_REMOTE_TRACE_FIELD__PACKET_ID,packetId); - d.add(ZT_REMOTE_TRACE_FIELD__PACKET_HOPS,(uint64_t)hops); - d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_ZTADDR,source); - if (path) { - d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_PHYADDR,path->address().toString(tmp)); - d.add(ZT_REMOTE_TRACE_FIELD__LOCAL_SOCKET,path->localSocket()); - } - if (reason) { - d.add(ZT_REMOTE_TRACE_FIELD__REASON,reason); - } + if ((_globalTarget) && ((int)_globalLevel >= Trace::LEVEL_DEBUG)) { + Dictionary d; + d.add(ZT_REMOTE_TRACE_FIELD__EVENT, ZT_REMOTE_TRACE_EVENT__PACKET_MAC_FAILURE_S); + d.add(ZT_REMOTE_TRACE_FIELD__PACKET_ID, packetId); + d.add(ZT_REMOTE_TRACE_FIELD__PACKET_HOPS, (uint64_t)hops); + d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_ZTADDR, source); + if (path) { + d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_PHYADDR, path->address().toString(tmp)); + d.add(ZT_REMOTE_TRACE_FIELD__LOCAL_SOCKET, path->localSocket()); + } + if (reason) { + d.add(ZT_REMOTE_TRACE_FIELD__REASON, reason); + } - _send(tPtr,d,_globalTarget); - } + _send(tPtr, d, _globalTarget); + } } -void Trace::incomingPacketInvalid(void *const tPtr,const SharedPtr &path,const uint64_t packetId,const Address &source,const unsigned int hops,const Packet::Verb verb,const char *reason) +void Trace::incomingPacketInvalid(void* const tPtr, const SharedPtr& path, const uint64_t packetId, const Address& source, const unsigned int hops, const Packet::Verb verb, const char* reason) { - char tmp[128]; + char tmp[128]; - ZT_LOCAL_TRACE(tPtr,RR,"INVALID packet %.16llx from %.10llx(%s) (%s)",packetId,source.toInt(),(path) ? path->address().toString(tmp) : "???",(reason) ? reason : "unknown reason"); + ZT_LOCAL_TRACE(tPtr, RR, "INVALID packet %.16llx from %.10llx(%s) (%s)", packetId, source.toInt(), (path) ? path->address().toString(tmp) : "???", (reason) ? reason : "unknown reason"); - if ((_globalTarget)&&((int)_globalLevel >= Trace::LEVEL_DEBUG)) { - Dictionary d; - d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__PACKET_INVALID_S); - d.add(ZT_REMOTE_TRACE_FIELD__PACKET_ID,packetId); - d.add(ZT_REMOTE_TRACE_FIELD__PACKET_VERB,(uint64_t)verb); - d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_ZTADDR,source); - if (path) { - d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_PHYADDR,path->address().toString(tmp)); - d.add(ZT_REMOTE_TRACE_FIELD__LOCAL_SOCKET,path->localSocket()); - } - d.add(ZT_REMOTE_TRACE_FIELD__PACKET_HOPS,(uint64_t)hops); - if (reason) { - d.add(ZT_REMOTE_TRACE_FIELD__REASON,reason); - } + if ((_globalTarget) && ((int)_globalLevel >= Trace::LEVEL_DEBUG)) { + Dictionary d; + d.add(ZT_REMOTE_TRACE_FIELD__EVENT, ZT_REMOTE_TRACE_EVENT__PACKET_INVALID_S); + d.add(ZT_REMOTE_TRACE_FIELD__PACKET_ID, packetId); + d.add(ZT_REMOTE_TRACE_FIELD__PACKET_VERB, (uint64_t)verb); + d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_ZTADDR, source); + if (path) { + d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_PHYADDR, path->address().toString(tmp)); + d.add(ZT_REMOTE_TRACE_FIELD__LOCAL_SOCKET, path->localSocket()); + } + d.add(ZT_REMOTE_TRACE_FIELD__PACKET_HOPS, (uint64_t)hops); + if (reason) { + d.add(ZT_REMOTE_TRACE_FIELD__REASON, reason); + } - _send(tPtr,d,_globalTarget); - } + _send(tPtr, d, _globalTarget); + } } -void Trace::incomingPacketDroppedHELLO(void *const tPtr,const SharedPtr &path,const uint64_t packetId,const Address &source,const char *reason) +void Trace::incomingPacketDroppedHELLO(void* const tPtr, const SharedPtr& path, const uint64_t packetId, const Address& source, const char* reason) { - char tmp[128]; + char tmp[128]; - ZT_LOCAL_TRACE(tPtr,RR,"DROPPED HELLO from %.10llx(%s) (%s)",source.toInt(),(path) ? path->address().toString(tmp) : "???",(reason) ? reason : "???"); + ZT_LOCAL_TRACE(tPtr, RR, "DROPPED HELLO from %.10llx(%s) (%s)", source.toInt(), (path) ? path->address().toString(tmp) : "???", (reason) ? reason : "???"); - if ((_globalTarget)&&((int)_globalLevel >= Trace::LEVEL_DEBUG)) { - Dictionary d; - d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__PACKET_INVALID_S); - d.add(ZT_REMOTE_TRACE_FIELD__PACKET_ID,packetId); - d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_ZTADDR,source); - if (path) { - d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_PHYADDR,path->address().toString(tmp)); - d.add(ZT_REMOTE_TRACE_FIELD__LOCAL_SOCKET,path->localSocket()); - } - if (reason) { - d.add(ZT_REMOTE_TRACE_FIELD__REASON,reason); - } + if ((_globalTarget) && ((int)_globalLevel >= Trace::LEVEL_DEBUG)) { + Dictionary d; + d.add(ZT_REMOTE_TRACE_FIELD__EVENT, ZT_REMOTE_TRACE_EVENT__PACKET_INVALID_S); + d.add(ZT_REMOTE_TRACE_FIELD__PACKET_ID, packetId); + d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_ZTADDR, source); + if (path) { + d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_PHYADDR, path->address().toString(tmp)); + d.add(ZT_REMOTE_TRACE_FIELD__LOCAL_SOCKET, path->localSocket()); + } + if (reason) { + d.add(ZT_REMOTE_TRACE_FIELD__REASON, reason); + } - _send(tPtr,d,_globalTarget); - } + _send(tPtr, d, _globalTarget); + } } -void Trace::networkConfigRequestSent(void *const tPtr,const Network &network,const Address &controller) +void Trace::networkConfigRequestSent(void* const tPtr, const Network& network, const Address& controller) { - ZT_LOCAL_TRACE(tPtr,RR,"requesting configuration for network %.16llx",network.id()); - if ((_globalTarget)&&((int)_globalLevel >= Trace::LEVEL_DEBUG)) { - Dictionary d; - d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__NETWORK_CONFIG_REQUEST_SENT_S); - d.add(ZT_REMOTE_TRACE_FIELD__NETWORK_ID,network.id()); - d.add(ZT_REMOTE_TRACE_FIELD__NETWORK_CONTROLLER_ID,controller); - _send(tPtr,d,_globalTarget); - } + ZT_LOCAL_TRACE(tPtr, RR, "requesting configuration for network %.16llx", network.id()); + if ((_globalTarget) && ((int)_globalLevel >= Trace::LEVEL_DEBUG)) { + Dictionary d; + d.add(ZT_REMOTE_TRACE_FIELD__EVENT, ZT_REMOTE_TRACE_EVENT__NETWORK_CONFIG_REQUEST_SENT_S); + d.add(ZT_REMOTE_TRACE_FIELD__NETWORK_ID, network.id()); + d.add(ZT_REMOTE_TRACE_FIELD__NETWORK_CONTROLLER_ID, controller); + _send(tPtr, d, _globalTarget); + } } void Trace::networkFilter( - void *const tPtr, - const Network &network, - const RuleResultLog &primaryRuleSetLog, - const RuleResultLog *const matchingCapabilityRuleSetLog, - const Capability *const matchingCapability, - const Address &ztSource, - const Address &ztDest, - const MAC &macSource, - const MAC &macDest, - const uint8_t *const frameData, - const unsigned int frameLen, - const unsigned int etherType, - const unsigned int vlanId, - const bool noTee, - const bool inbound, - const int accept) + void* const tPtr, + const Network& network, + const RuleResultLog& primaryRuleSetLog, + const RuleResultLog* const matchingCapabilityRuleSetLog, + const Capability* const matchingCapability, + const Address& ztSource, + const Address& ztDest, + const MAC& macSource, + const MAC& macDest, + const uint8_t* const frameData, + const unsigned int frameLen, + const unsigned int etherType, + const unsigned int vlanId, + const bool noTee, + const bool inbound, + const int accept) { - std::pair byn; - { Mutex::Lock l(_byNet_m); _byNet.get(network.id(),byn); } + std::pair byn; + { + Mutex::Lock l(_byNet_m); + _byNet.get(network.id(), byn); + } - if ( ((_globalTarget)&&((int)_globalLevel >= (int)Trace::LEVEL_RULES)) || ((byn.first)&&((int)byn.second >= (int)Trace::LEVEL_RULES)) ) { - Dictionary d; - d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__NETWORK_FILTER_TRACE_S); - d.add(ZT_REMOTE_TRACE_FIELD__NETWORK_ID,network.id()); - d.add(ZT_REMOTE_TRACE_FIELD__SOURCE_ZTADDR,ztSource); - d.add(ZT_REMOTE_TRACE_FIELD__DEST_ZTADDR,ztDest); - d.add(ZT_REMOTE_TRACE_FIELD__SOURCE_MAC,macSource.toInt()); - d.add(ZT_REMOTE_TRACE_FIELD__DEST_MAC,macDest.toInt()); - d.add(ZT_REMOTE_TRACE_FIELD__ETHERTYPE,(uint64_t)etherType); - d.add(ZT_REMOTE_TRACE_FIELD__VLAN_ID,(uint64_t)vlanId); - d.add(ZT_REMOTE_TRACE_FIELD__FILTER_FLAG_NOTEE,noTee ? "1" : "0"); - d.add(ZT_REMOTE_TRACE_FIELD__FILTER_FLAG_INBOUND,inbound ? "1" : "0"); - d.add(ZT_REMOTE_TRACE_FIELD__FILTER_RESULT,(int64_t)accept); - d.add(ZT_REMOTE_TRACE_FIELD__FILTER_BASE_RULE_LOG,(const char *)primaryRuleSetLog.data(),(int)primaryRuleSetLog.sizeBytes()); - if (matchingCapabilityRuleSetLog) { - d.add(ZT_REMOTE_TRACE_FIELD__FILTER_CAP_RULE_LOG,(const char *)matchingCapabilityRuleSetLog->data(),(int)matchingCapabilityRuleSetLog->sizeBytes()); - } - if (matchingCapability) { - d.add(ZT_REMOTE_TRACE_FIELD__FILTER_CAP_ID,(uint64_t)matchingCapability->id()); - } - d.add(ZT_REMOTE_TRACE_FIELD__FRAME_LENGTH,(uint64_t)frameLen); - if (frameLen > 0) { - d.add(ZT_REMOTE_TRACE_FIELD__FRAME_DATA,(const char *)frameData,(frameLen > 256) ? (int)256 : (int)frameLen); - } + if (((_globalTarget) && ((int)_globalLevel >= (int)Trace::LEVEL_RULES)) || ((byn.first) && ((int)byn.second >= (int)Trace::LEVEL_RULES))) { + Dictionary d; + d.add(ZT_REMOTE_TRACE_FIELD__EVENT, ZT_REMOTE_TRACE_EVENT__NETWORK_FILTER_TRACE_S); + d.add(ZT_REMOTE_TRACE_FIELD__NETWORK_ID, network.id()); + d.add(ZT_REMOTE_TRACE_FIELD__SOURCE_ZTADDR, ztSource); + d.add(ZT_REMOTE_TRACE_FIELD__DEST_ZTADDR, ztDest); + d.add(ZT_REMOTE_TRACE_FIELD__SOURCE_MAC, macSource.toInt()); + d.add(ZT_REMOTE_TRACE_FIELD__DEST_MAC, macDest.toInt()); + d.add(ZT_REMOTE_TRACE_FIELD__ETHERTYPE, (uint64_t)etherType); + d.add(ZT_REMOTE_TRACE_FIELD__VLAN_ID, (uint64_t)vlanId); + d.add(ZT_REMOTE_TRACE_FIELD__FILTER_FLAG_NOTEE, noTee ? "1" : "0"); + d.add(ZT_REMOTE_TRACE_FIELD__FILTER_FLAG_INBOUND, inbound ? "1" : "0"); + d.add(ZT_REMOTE_TRACE_FIELD__FILTER_RESULT, (int64_t)accept); + d.add(ZT_REMOTE_TRACE_FIELD__FILTER_BASE_RULE_LOG, (const char*)primaryRuleSetLog.data(), (int)primaryRuleSetLog.sizeBytes()); + if (matchingCapabilityRuleSetLog) { + d.add(ZT_REMOTE_TRACE_FIELD__FILTER_CAP_RULE_LOG, (const char*)matchingCapabilityRuleSetLog->data(), (int)matchingCapabilityRuleSetLog->sizeBytes()); + } + if (matchingCapability) { + d.add(ZT_REMOTE_TRACE_FIELD__FILTER_CAP_ID, (uint64_t)matchingCapability->id()); + } + d.add(ZT_REMOTE_TRACE_FIELD__FRAME_LENGTH, (uint64_t)frameLen); + if (frameLen > 0) { + d.add(ZT_REMOTE_TRACE_FIELD__FRAME_DATA, (const char*)frameData, (frameLen > 256) ? (int)256 : (int)frameLen); + } - if ((_globalTarget)&&((int)_globalLevel >= (int)Trace::LEVEL_RULES)) { - _send(tPtr,d,_globalTarget); - } - if ((byn.first)&&((int)byn.second >= (int)Trace::LEVEL_RULES)) { - _send(tPtr,d,byn.first); - } - } + if ((_globalTarget) && ((int)_globalLevel >= (int)Trace::LEVEL_RULES)) { + _send(tPtr, d, _globalTarget); + } + if ((byn.first) && ((int)byn.second >= (int)Trace::LEVEL_RULES)) { + _send(tPtr, d, byn.first); + } + } } -void Trace::credentialRejected(void *const tPtr,const CertificateOfMembership &c,const char *reason) +void Trace::credentialRejected(void* const tPtr, const CertificateOfMembership& c, const char* reason) { - std::pair byn; - if (c.networkId()) { - Mutex::Lock l(_byNet_m); - _byNet.get(c.networkId(),byn); - } + std::pair byn; + if (c.networkId()) { + Mutex::Lock l(_byNet_m); + _byNet.get(c.networkId(), byn); + } - if ((_globalTarget)||(byn.first)) { - Dictionary d; - d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__CREDENTIAL_REJECTED_S); - d.add(ZT_REMOTE_TRACE_FIELD__NETWORK_ID,c.networkId()); - d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TYPE,(uint64_t)c.credentialType()); - d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ID,(uint64_t)c.id()); - d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TIMESTAMP,c.timestamp()); - d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ISSUED_TO,c.issuedTo()); - if (reason) { - d.add(ZT_REMOTE_TRACE_FIELD__REASON,reason); - } + if ((_globalTarget) || (byn.first)) { + Dictionary d; + d.add(ZT_REMOTE_TRACE_FIELD__EVENT, ZT_REMOTE_TRACE_EVENT__CREDENTIAL_REJECTED_S); + d.add(ZT_REMOTE_TRACE_FIELD__NETWORK_ID, c.networkId()); + d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TYPE, (uint64_t)c.credentialType()); + d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ID, (uint64_t)c.id()); + d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TIMESTAMP, c.timestamp()); + d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ISSUED_TO, c.issuedTo()); + if (reason) { + d.add(ZT_REMOTE_TRACE_FIELD__REASON, reason); + } - if (_globalTarget) { - _send(tPtr,d,_globalTarget); - } - if (byn.first) { - _send(tPtr,d,byn.first); - } - } + if (_globalTarget) { + _send(tPtr, d, _globalTarget); + } + if (byn.first) { + _send(tPtr, d, byn.first); + } + } } -void Trace::credentialRejected(void *const tPtr,const CertificateOfOwnership &c,const char *reason) +void Trace::credentialRejected(void* const tPtr, const CertificateOfOwnership& c, const char* reason) { - std::pair byn; - if (c.networkId()) { - Mutex::Lock l(_byNet_m); - _byNet.get(c.networkId(),byn); - } + std::pair byn; + if (c.networkId()) { + Mutex::Lock l(_byNet_m); + _byNet.get(c.networkId(), byn); + } - if ((_globalTarget)||(byn.first)) { - Dictionary d; - d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__CREDENTIAL_REJECTED_S); - d.add(ZT_REMOTE_TRACE_FIELD__NETWORK_ID,c.networkId()); - d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TYPE,(uint64_t)c.credentialType()); - d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ID,(uint64_t)c.id()); - d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TIMESTAMP,c.timestamp()); - d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ISSUED_TO,c.issuedTo()); - if (reason) { - d.add(ZT_REMOTE_TRACE_FIELD__REASON,reason); - } + if ((_globalTarget) || (byn.first)) { + Dictionary d; + d.add(ZT_REMOTE_TRACE_FIELD__EVENT, ZT_REMOTE_TRACE_EVENT__CREDENTIAL_REJECTED_S); + d.add(ZT_REMOTE_TRACE_FIELD__NETWORK_ID, c.networkId()); + d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TYPE, (uint64_t)c.credentialType()); + d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ID, (uint64_t)c.id()); + d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TIMESTAMP, c.timestamp()); + d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ISSUED_TO, c.issuedTo()); + if (reason) { + d.add(ZT_REMOTE_TRACE_FIELD__REASON, reason); + } - if (_globalTarget) { - _send(tPtr,d,_globalTarget); - } - if (byn.first) { - _send(tPtr,d,byn.first); - } - } + if (_globalTarget) { + _send(tPtr, d, _globalTarget); + } + if (byn.first) { + _send(tPtr, d, byn.first); + } + } } -void Trace::credentialRejected(void *const tPtr,const Capability &c,const char *reason) +void Trace::credentialRejected(void* const tPtr, const Capability& c, const char* reason) { - std::pair byn; - if (c.networkId()) { - Mutex::Lock l(_byNet_m); - _byNet.get(c.networkId(),byn); - } + std::pair byn; + if (c.networkId()) { + Mutex::Lock l(_byNet_m); + _byNet.get(c.networkId(), byn); + } - if ((_globalTarget)||(byn.first)) { - Dictionary d; - d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__CREDENTIAL_REJECTED_S); - d.add(ZT_REMOTE_TRACE_FIELD__NETWORK_ID,c.networkId()); - d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TYPE,(uint64_t)c.credentialType()); - d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ID,(uint64_t)c.id()); - d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TIMESTAMP,c.timestamp()); - d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ISSUED_TO,c.issuedTo()); - if (reason) { - d.add(ZT_REMOTE_TRACE_FIELD__REASON,reason); - } + if ((_globalTarget) || (byn.first)) { + Dictionary d; + d.add(ZT_REMOTE_TRACE_FIELD__EVENT, ZT_REMOTE_TRACE_EVENT__CREDENTIAL_REJECTED_S); + d.add(ZT_REMOTE_TRACE_FIELD__NETWORK_ID, c.networkId()); + d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TYPE, (uint64_t)c.credentialType()); + d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ID, (uint64_t)c.id()); + d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TIMESTAMP, c.timestamp()); + d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ISSUED_TO, c.issuedTo()); + if (reason) { + d.add(ZT_REMOTE_TRACE_FIELD__REASON, reason); + } - if (_globalTarget) { - _send(tPtr,d,_globalTarget); - } - if (byn.first) { - _send(tPtr,d,byn.first); - } - } + if (_globalTarget) { + _send(tPtr, d, _globalTarget); + } + if (byn.first) { + _send(tPtr, d, byn.first); + } + } } -void Trace::credentialRejected(void *const tPtr,const Tag &c,const char *reason) +void Trace::credentialRejected(void* const tPtr, const Tag& c, const char* reason) { - std::pair byn; - if (c.networkId()) { - Mutex::Lock l(_byNet_m); - _byNet.get(c.networkId(),byn); - } + std::pair byn; + if (c.networkId()) { + Mutex::Lock l(_byNet_m); + _byNet.get(c.networkId(), byn); + } - if ((_globalTarget)||(byn.first)) { - Dictionary d; - d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__CREDENTIAL_REJECTED_S); - d.add(ZT_REMOTE_TRACE_FIELD__NETWORK_ID,c.networkId()); - d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TYPE,(uint64_t)c.credentialType()); - d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ID,(uint64_t)c.id()); - d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TIMESTAMP,c.timestamp()); - d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ISSUED_TO,c.issuedTo()); - d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_INFO,(uint64_t)c.value()); - if (reason) { - d.add(ZT_REMOTE_TRACE_FIELD__REASON,reason); - } + if ((_globalTarget) || (byn.first)) { + Dictionary d; + d.add(ZT_REMOTE_TRACE_FIELD__EVENT, ZT_REMOTE_TRACE_EVENT__CREDENTIAL_REJECTED_S); + d.add(ZT_REMOTE_TRACE_FIELD__NETWORK_ID, c.networkId()); + d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TYPE, (uint64_t)c.credentialType()); + d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ID, (uint64_t)c.id()); + d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TIMESTAMP, c.timestamp()); + d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ISSUED_TO, c.issuedTo()); + d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_INFO, (uint64_t)c.value()); + if (reason) { + d.add(ZT_REMOTE_TRACE_FIELD__REASON, reason); + } - if (_globalTarget) { - _send(tPtr,d,_globalTarget); - } - if (byn.first) { - _send(tPtr,d,byn.first); - } - } + if (_globalTarget) { + _send(tPtr, d, _globalTarget); + } + if (byn.first) { + _send(tPtr, d, byn.first); + } + } } -void Trace::credentialRejected(void *const tPtr,const Revocation &c,const char *reason) +void Trace::credentialRejected(void* const tPtr, const Revocation& c, const char* reason) { - std::pair byn; - if (c.networkId()) { - Mutex::Lock l(_byNet_m); - _byNet.get(c.networkId(),byn); - } + std::pair byn; + if (c.networkId()) { + Mutex::Lock l(_byNet_m); + _byNet.get(c.networkId(), byn); + } - if ((_globalTarget)||(byn.first)) { - Dictionary d; - d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__CREDENTIAL_REJECTED_S); - d.add(ZT_REMOTE_TRACE_FIELD__NETWORK_ID,c.networkId()); - d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TYPE,(uint64_t)c.credentialType()); - d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ID,(uint64_t)c.id()); - d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_REVOCATION_TARGET,c.target()); - if (reason) { - d.add(ZT_REMOTE_TRACE_FIELD__REASON, reason); - } + if ((_globalTarget) || (byn.first)) { + Dictionary d; + d.add(ZT_REMOTE_TRACE_FIELD__EVENT, ZT_REMOTE_TRACE_EVENT__CREDENTIAL_REJECTED_S); + d.add(ZT_REMOTE_TRACE_FIELD__NETWORK_ID, c.networkId()); + d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TYPE, (uint64_t)c.credentialType()); + d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ID, (uint64_t)c.id()); + d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_REVOCATION_TARGET, c.target()); + if (reason) { + d.add(ZT_REMOTE_TRACE_FIELD__REASON, reason); + } - if (_globalTarget) { - _send(tPtr,d,_globalTarget); - } - if (byn.first) { - _send(tPtr,d,byn.first); - } - } + if (_globalTarget) { + _send(tPtr, d, _globalTarget); + } + if (byn.first) { + _send(tPtr, d, byn.first); + } + } } void Trace::updateMemoizedSettings() { - _globalTarget = RR->node->remoteTraceTarget(); - _globalLevel = RR->node->remoteTraceLevel(); - const std::vector< SharedPtr > nws(RR->node->allNetworks()); - { - Mutex::Lock l(_byNet_m); - _byNet.clear(); - for(std::vector< SharedPtr >::const_iterator n(nws.begin());n!=nws.end();++n) { - const Address dest((*n)->config().remoteTraceTarget); - if (dest) { - std::pair &m = _byNet[(*n)->id()]; - m.first = dest; - m.second = (*n)->config().remoteTraceLevel; - } - } - } + _globalTarget = RR->node->remoteTraceTarget(); + _globalLevel = RR->node->remoteTraceLevel(); + const std::vector > nws(RR->node->allNetworks()); + { + Mutex::Lock l(_byNet_m); + _byNet.clear(); + for (std::vector >::const_iterator n(nws.begin()); n != nws.end(); ++n) { + const Address dest((*n)->config().remoteTraceTarget); + if (dest) { + std::pair& m = _byNet[(*n)->id()]; + m.first = dest; + m.second = (*n)->config().remoteTraceLevel; + } + } + } } -void Trace::_send(void *const tPtr,const Dictionary &d,const Address &dest) +void Trace::_send(void* const tPtr, const Dictionary& d, const Address& dest) { - Packet outp(dest,RR->identity.address(),Packet::VERB_REMOTE_TRACE); - outp.appendCString(d.data()); - outp.compress(); - RR->sw->send(tPtr,outp,true); + Packet outp(dest, RR->identity.address(), Packet::VERB_REMOTE_TRACE); + outp.appendCString(d.data()); + outp.compress(); + RR->sw->send(tPtr, outp, true); } -void Trace::_spamToAllNetworks(void *const tPtr,const Dictionary &d,const Level level) +void Trace::_spamToAllNetworks(void* const tPtr, const Dictionary& d, const Level level) { - Mutex::Lock l(_byNet_m); - Hashtable< uint64_t,std::pair< Address,Trace::Level > >::Iterator i(_byNet); - uint64_t *k = (uint64_t *)0; - std::pair *v = (std::pair *)0; - while (i.next(k,v)) { - if ((v)&&(v->first)&&((int)v->second >= (int)level)) { - _send(tPtr,d,v->first); - } - } + Mutex::Lock l(_byNet_m); + Hashtable >::Iterator i(_byNet); + uint64_t* k = (uint64_t*)0; + std::pair* v = (std::pair*)0; + while (i.next(k, v)) { + if ((v) && (v->first) && ((int)v->second >= (int)level)) { + _send(tPtr, d, v->first); + } + } } -} // namespace ZeroTier +} // namespace ZeroTier diff --git a/node/Trace.hpp b/node/Trace.hpp index 963941d7..826383b1 100644 --- a/node/Trace.hpp +++ b/node/Trace.hpp @@ -14,21 +14,20 @@ #ifndef ZT_TRACE_HPP #define ZT_TRACE_HPP -#include -#include -#include -#include - #include "../include/ZeroTierOne.h" - #include "Constants.hpp" -#include "SharedPtr.hpp" -#include "Packet.hpp" #include "Credential.hpp" -#include "InetAddress.hpp" #include "Dictionary.hpp" -#include "Mutex.hpp" #include "Hashtable.hpp" +#include "InetAddress.hpp" +#include "Mutex.hpp" +#include "Packet.hpp" +#include "SharedPtr.hpp" + +#include +#include +#include +#include namespace ZeroTier { @@ -49,118 +48,133 @@ class Capability; /** * Remote tracing and trace logging handler */ -class Trace -{ -public: - /** - * Trace verbosity level - */ - enum Level - { - LEVEL_NORMAL = 0, - LEVEL_VERBOSE = 10, - LEVEL_RULES = 15, - LEVEL_DEBUG = 20, - LEVEL_INSANE = 30 - }; +class Trace { + public: + /** + * Trace verbosity level + */ + enum Level { LEVEL_NORMAL = 0, LEVEL_VERBOSE = 10, LEVEL_RULES = 15, LEVEL_DEBUG = 20, LEVEL_INSANE = 30 }; - /** - * Filter rule evaluation result log - * - * Each rule in a rule set gets a four-bit log entry. A log entry - * of zero means not evaluated. Otherwise each four-bit log entry - * contains two two-bit values of 01 for 'false' and 10 for 'true'. - * As with four-bit rules an 00 value here means this was not - * evaluated or was not relevant. - */ - class RuleResultLog - { - public: - RuleResultLog() {} + /** + * Filter rule evaluation result log + * + * Each rule in a rule set gets a four-bit log entry. A log entry + * of zero means not evaluated. Otherwise each four-bit log entry + * contains two two-bit values of 01 for 'false' and 10 for 'true'. + * As with four-bit rules an 00 value here means this was not + * evaluated or was not relevant. + */ + class RuleResultLog { + public: + RuleResultLog() + { + } - inline void log(const unsigned int rn,const uint8_t thisRuleMatches,const uint8_t thisSetMatches) - { - _l[rn >> 1] |= ( ((thisRuleMatches + 1) << 2) | (thisSetMatches + 1) ) << ((rn & 1) << 2); - } - inline void logSkipped(const unsigned int rn,const uint8_t thisSetMatches) - { - _l[rn >> 1] |= (thisSetMatches + 1) << ((rn & 1) << 2); - } + inline void log(const unsigned int rn, const uint8_t thisRuleMatches, const uint8_t thisSetMatches) + { + _l[rn >> 1] |= (((thisRuleMatches + 1) << 2) | (thisSetMatches + 1)) << ((rn & 1) << 2); + } + inline void logSkipped(const unsigned int rn, const uint8_t thisSetMatches) + { + _l[rn >> 1] |= (thisSetMatches + 1) << ((rn & 1) << 2); + } - inline void clear() - { - memset(_l,0,sizeof(_l)); - } + inline void clear() + { + memset(_l, 0, sizeof(_l)); + } - inline const uint8_t *data() const { return _l; } - inline unsigned int sizeBytes() const { return (ZT_MAX_NETWORK_RULES / 2); } + inline const uint8_t* data() const + { + return _l; + } + inline unsigned int sizeBytes() const + { + return (ZT_MAX_NETWORK_RULES / 2); + } - private: - uint8_t _l[ZT_MAX_NETWORK_RULES / 2]; - }; + private: + uint8_t _l[ZT_MAX_NETWORK_RULES / 2]; + }; - Trace(const RuntimeEnvironment *renv) : - RR(renv), - _byNet(8) - { - } + Trace(const RuntimeEnvironment* renv) : RR(renv), _byNet(8) + { + } - void resettingPathsInScope(void *const tPtr,const Address &reporter,const InetAddress &reporterPhysicalAddress,const InetAddress &myPhysicalAddress,const InetAddress::IpScope scope); + void resettingPathsInScope(void* const tPtr, const Address& reporter, const InetAddress& reporterPhysicalAddress, const InetAddress& myPhysicalAddress, const InetAddress::IpScope scope); - void peerConfirmingUnknownPath(void *const tPtr,const uint64_t networkId,Peer &peer,const SharedPtr &path,const uint64_t packetId,const Packet::Verb verb); + void peerConfirmingUnknownPath(void* const tPtr, const uint64_t networkId, Peer& peer, const SharedPtr& path, const uint64_t packetId, const Packet::Verb verb); - void bondStateMessage(void *const tPtr,char *msg); + void bondStateMessage(void* const tPtr, char* msg); - void peerLearnedNewPath(void *const tPtr,const uint64_t networkId,Peer &peer,const SharedPtr &newPath,const uint64_t packetId); - void peerRedirected(void *const tPtr,const uint64_t networkId,Peer &peer,const SharedPtr &newPath); + void peerLearnedNewPath(void* const tPtr, const uint64_t networkId, Peer& peer, const SharedPtr& newPath, const uint64_t packetId); + void peerRedirected(void* const tPtr, const uint64_t networkId, Peer& peer, const SharedPtr& newPath); - void incomingPacketMessageAuthenticationFailure(void *const tPtr,const SharedPtr &path,const uint64_t packetId,const Address &source,const unsigned int hops,const char *reason); - void incomingPacketInvalid(void *const tPtr,const SharedPtr &path,const uint64_t packetId,const Address &source,const unsigned int hops,const Packet::Verb verb,const char *reason); - void incomingPacketDroppedHELLO(void *const tPtr,const SharedPtr &path,const uint64_t packetId,const Address &source,const char *reason); + void incomingPacketMessageAuthenticationFailure(void* const tPtr, const SharedPtr& path, const uint64_t packetId, const Address& source, const unsigned int hops, const char* reason); + void incomingPacketInvalid(void* const tPtr, const SharedPtr& path, const uint64_t packetId, const Address& source, const unsigned int hops, const Packet::Verb verb, const char* reason); + void incomingPacketDroppedHELLO(void* const tPtr, const SharedPtr& path, const uint64_t packetId, const Address& source, const char* reason); - void outgoingNetworkFrameDropped(void *const tPtr,const SharedPtr &network,const MAC &sourceMac,const MAC &destMac,const unsigned int etherType,const unsigned int vlanId,const unsigned int frameLen,const char *reason); - void incomingNetworkAccessDenied(void *const tPtr,const SharedPtr &network,const SharedPtr &path,const uint64_t packetId,const unsigned int packetLength,const Address &source,const Packet::Verb verb,bool credentialsRequested); - void incomingNetworkFrameDropped(void *const tPtr,const SharedPtr &network,const SharedPtr &path,const uint64_t packetId,const unsigned int packetLength,const Address &source,const Packet::Verb verb,const MAC &sourceMac,const MAC &destMac,const char *reason); + void outgoingNetworkFrameDropped(void* const tPtr, const SharedPtr& network, const MAC& sourceMac, const MAC& destMac, const unsigned int etherType, const unsigned int vlanId, const unsigned int frameLen, const char* reason); + void incomingNetworkAccessDenied( + void* const tPtr, + const SharedPtr& network, + const SharedPtr& path, + const uint64_t packetId, + const unsigned int packetLength, + const Address& source, + const Packet::Verb verb, + bool credentialsRequested); + void incomingNetworkFrameDropped( + void* const tPtr, + const SharedPtr& network, + const SharedPtr& path, + const uint64_t packetId, + const unsigned int packetLength, + const Address& source, + const Packet::Verb verb, + const MAC& sourceMac, + const MAC& destMac, + const char* reason); - void networkConfigRequestSent(void *const tPtr,const Network &network,const Address &controller); - void networkFilter( - void *const tPtr, - const Network &network, - const RuleResultLog &primaryRuleSetLog, - const RuleResultLog *const matchingCapabilityRuleSetLog, - const Capability *const matchingCapability, - const Address &ztSource, - const Address &ztDest, - const MAC &macSource, - const MAC &macDest, - const uint8_t *const frameData, - const unsigned int frameLen, - const unsigned int etherType, - const unsigned int vlanId, - const bool noTee, - const bool inbound, - const int accept); + void networkConfigRequestSent(void* const tPtr, const Network& network, const Address& controller); + void networkFilter( + void* const tPtr, + const Network& network, + const RuleResultLog& primaryRuleSetLog, + const RuleResultLog* const matchingCapabilityRuleSetLog, + const Capability* const matchingCapability, + const Address& ztSource, + const Address& ztDest, + const MAC& macSource, + const MAC& macDest, + const uint8_t* const frameData, + const unsigned int frameLen, + const unsigned int etherType, + const unsigned int vlanId, + const bool noTee, + const bool inbound, + const int accept); - void credentialRejected(void *const tPtr,const CertificateOfMembership &c,const char *reason); - void credentialRejected(void *const tPtr,const CertificateOfOwnership &c,const char *reason); - void credentialRejected(void *const tPtr,const Capability &c,const char *reason); - void credentialRejected(void *const tPtr,const Tag &c,const char *reason); - void credentialRejected(void *const tPtr,const Revocation &c,const char *reason); + void credentialRejected(void* const tPtr, const CertificateOfMembership& c, const char* reason); + void credentialRejected(void* const tPtr, const CertificateOfOwnership& c, const char* reason); + void credentialRejected(void* const tPtr, const Capability& c, const char* reason); + void credentialRejected(void* const tPtr, const Tag& c, const char* reason); + void credentialRejected(void* const tPtr, const Revocation& c, const char* reason); - void updateMemoizedSettings(); + void updateMemoizedSettings(); -private: - const RuntimeEnvironment *const RR; + private: + const RuntimeEnvironment* const RR; - void _send(void *const tPtr,const Dictionary &d,const Address &dest); - void _spamToAllNetworks(void *const tPtr,const Dictionary &d,const Level level); + void _send(void* const tPtr, const Dictionary& d, const Address& dest); + void _spamToAllNetworks(void* const tPtr, const Dictionary& d, const Level level); - Address _globalTarget; - Trace::Level _globalLevel; - Hashtable< uint64_t,std::pair< Address,Trace::Level > > _byNet; - Mutex _byNet_m; + Address _globalTarget; + Trace::Level _globalLevel; + Hashtable > _byNet; + Mutex _byNet_m; }; -} // namespace ZeroTier +} // namespace ZeroTier #endif diff --git a/node/Utils.cpp b/node/Utils.cpp index 4e53cb59..c8149b60 100644 --- a/node/Utils.cpp +++ b/node/Utils.cpp @@ -11,23 +11,23 @@ */ /****/ -#include -#include -#include -#include -#include -#include - #include "Constants.hpp" +#include +#include +#include +#include +#include +#include + #ifdef __UNIX_LIKE__ -#include +#include #include #include -#include #include +#include #include -#include +#include #ifdef ZT_ARCH_ARM_HAS_NEON #ifdef __LINUX__ #include @@ -36,13 +36,13 @@ #endif #ifdef __WINDOWS__ -#include #include +#include #endif -#include "Utils.hpp" #include "Mutex.hpp" #include "Salsa20.hpp" +#include "Utils.hpp" #ifdef __APPLE__ #include @@ -55,8 +55,8 @@ #ifdef ZT_ARCH_ARM_HAS_NEON #ifdef __LINUX__ -#include #include +#include #endif #if defined(__FreeBSD__) @@ -64,9 +64,9 @@ #include static inline long getauxval(int caps) { - long hwcaps = 0; - elf_aux_info(caps, &hwcaps, sizeof(hwcaps)); - return hwcaps; + long hwcaps = 0; + elf_aux_info(caps, &hwcaps, sizeof(hwcaps)); + return hwcaps; } #endif @@ -87,13 +87,13 @@ static inline long getauxval(int caps) #define HWCAP_SHA2 0 #endif -#endif // ZT_ARCH_ARM_HAS_NEON +#endif // ZT_ARCH_ARM_HAS_NEON namespace ZeroTier { -const uint64_t Utils::ZERO256[4] = {0ULL,0ULL,0ULL,0ULL}; +const uint64_t Utils::ZERO256[4] = { 0ULL, 0ULL, 0ULL, 0ULL }; -const char Utils::HEXCHARS[16] = { '0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f' }; +const char Utils::HEXCHARS[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; #ifdef ZT_ARCH_ARM_HAS_NEON Utils::ARMCapabilities::ARMCapabilities() noexcept @@ -109,26 +109,27 @@ Utils::ARMCapabilities::ARMCapabilities() noexcept #else #ifdef HWCAP2_AES - if (sizeof(void *) == 4) { - const long hwcaps2 = getauxval(AT_HWCAP2); - this->aes = (hwcaps2 & HWCAP2_AES) != 0; - this->crc32 = (hwcaps2 & HWCAP2_CRC32) != 0; - this->pmull = (hwcaps2 & HWCAP2_PMULL) != 0; - this->sha1 = (hwcaps2 & HWCAP2_SHA1) != 0; - this->sha2 = (hwcaps2 & HWCAP2_SHA2) != 0; - } else { + if (sizeof(void*) == 4) { + const long hwcaps2 = getauxval(AT_HWCAP2); + this->aes = (hwcaps2 & HWCAP2_AES) != 0; + this->crc32 = (hwcaps2 & HWCAP2_CRC32) != 0; + this->pmull = (hwcaps2 & HWCAP2_PMULL) != 0; + this->sha1 = (hwcaps2 & HWCAP2_SHA1) != 0; + this->sha2 = (hwcaps2 & HWCAP2_SHA2) != 0; + } + else { #endif - const long hwcaps = getauxval(AT_HWCAP); - this->aes = (hwcaps & HWCAP_AES) != 0; - this->crc32 = (hwcaps & HWCAP_CRC32) != 0; - this->pmull = (hwcaps & HWCAP_PMULL) != 0; - this->sha1 = (hwcaps & HWCAP_SHA1) != 0; - this->sha2 = (hwcaps & HWCAP_SHA2) != 0; + const long hwcaps = getauxval(AT_HWCAP); + this->aes = (hwcaps & HWCAP_AES) != 0; + this->crc32 = (hwcaps & HWCAP_CRC32) != 0; + this->pmull = (hwcaps & HWCAP_PMULL) != 0; + this->sha1 = (hwcaps & HWCAP_SHA1) != 0; + this->sha2 = (hwcaps & HWCAP_SHA2) != 0; #ifdef HWCAP2_AES - } + } #endif -#endif // __APPLE__ +#endif // __APPLE__ } const Utils::ARMCapabilities Utils::ARMCAP; @@ -138,172 +139,168 @@ const Utils::ARMCapabilities Utils::ARMCAP; Utils::CPUIDRegisters::CPUIDRegisters() noexcept { - uint32_t eax, ebx, ecx, edx; + uint32_t eax, ebx, ecx, edx; #ifdef __WINDOWS__ - int regs[4]; - __cpuid(regs,1); - eax = (uint32_t)regs[0]; - ebx = (uint32_t)regs[1]; - ecx = (uint32_t)regs[2]; - edx = (uint32_t)regs[3]; + int regs[4]; + __cpuid(regs, 1); + eax = (uint32_t)regs[0]; + ebx = (uint32_t)regs[1]; + ecx = (uint32_t)regs[2]; + edx = (uint32_t)regs[3]; #else - __asm__ __volatile__ ( - "cpuid" - : "=a"(eax), "=b"(ebx), "=c"(ecx), "=d"(edx) - : "a"(1), "c"(0) - ); + __asm__ __volatile__("cpuid" : "=a"(eax), "=b"(ebx), "=c"(ecx), "=d"(edx) : "a"(1), "c"(0)); #endif - rdrand = ((ecx & (1U << 30U)) != 0); - aes = (((ecx & (1U << 25U)) != 0) && ((ecx & (1U << 19U)) != 0) && ((ecx & (1U << 1U)) != 0)); - avx = ((ecx & (1U << 25U)) != 0); + rdrand = ((ecx & (1U << 30U)) != 0); + aes = (((ecx & (1U << 25U)) != 0) && ((ecx & (1U << 19U)) != 0) && ((ecx & (1U << 1U)) != 0)); + avx = ((ecx & (1U << 25U)) != 0); #ifdef __WINDOWS__ - __cpuid(regs,7); - eax = (uint32_t)regs[0]; - ebx = (uint32_t)regs[1]; - ecx = (uint32_t)regs[2]; - edx = (uint32_t)regs[3]; + __cpuid(regs, 7); + eax = (uint32_t)regs[0]; + ebx = (uint32_t)regs[1]; + ecx = (uint32_t)regs[2]; + edx = (uint32_t)regs[3]; #else - __asm__ __volatile__ ( - "cpuid" - : "=a"(eax), "=b"(ebx), "=c"(ecx), "=d"(edx) - : "a"(7), "c"(0) - ); + __asm__ __volatile__("cpuid" : "=a"(eax), "=b"(ebx), "=c"(ecx), "=d"(edx) : "a"(7), "c"(0)); #endif - vaes = aes && avx && ((ecx & (1U << 9U)) != 0); - vpclmulqdq = aes && avx && ((ecx & (1U << 10U)) != 0); - avx2 = avx && ((ebx & (1U << 5U)) != 0); - avx512f = avx && ((ebx & (1U << 16U)) != 0); - sha = ((ebx & (1U << 29U)) != 0); - fsrm = ((edx & (1U << 4U)) != 0); + vaes = aes && avx && ((ecx & (1U << 9U)) != 0); + vpclmulqdq = aes && avx && ((ecx & (1U << 10U)) != 0); + avx2 = avx && ((ebx & (1U << 5U)) != 0); + avx512f = avx && ((ebx & (1U << 16U)) != 0); + sha = ((ebx & (1U << 29U)) != 0); + fsrm = ((edx & (1U << 4U)) != 0); } const Utils::CPUIDRegisters Utils::CPUID; #endif // Crazy hack to force memory to be securely zeroed in spite of the best efforts of optimizing compilers. -static void _Utils_doBurn(volatile uint8_t *ptr,unsigned int len) +static void _Utils_doBurn(volatile uint8_t* ptr, unsigned int len) { - volatile uint8_t *const end = ptr + len; - while (ptr != end) { - *(ptr++) = (uint8_t)0; - } + volatile uint8_t* const end = ptr + len; + while (ptr != end) { + *(ptr++) = (uint8_t)0; + } } -static void (*volatile _Utils_doBurn_ptr)(volatile uint8_t *,unsigned int) = _Utils_doBurn; -void Utils::burn(void *ptr,unsigned int len) { (_Utils_doBurn_ptr)((volatile uint8_t *)ptr,len); } - -static unsigned long _Utils_itoa(unsigned long n,char *s) +static void (*volatile _Utils_doBurn_ptr)(volatile uint8_t*, unsigned int) = _Utils_doBurn; +void Utils::burn(void* ptr, unsigned int len) { - if (n == 0) { - return 0; - } - unsigned long pos = _Utils_itoa(n / 10,s); - if (pos >= 22) { // sanity check, should be impossible - pos = 22; - } - s[pos] = '0' + (char)(n % 10); - return pos + 1; -} -char *Utils::decimal(unsigned long n,char s[24]) -{ - if (n == 0) { - s[0] = '0'; - s[1] = (char)0; - return s; - } - s[_Utils_itoa(n,s)] = (char)0; - return s; + (_Utils_doBurn_ptr)((volatile uint8_t*)ptr, len); } -void Utils::getSecureRandom(void *buf,unsigned int bytes) +static unsigned long _Utils_itoa(unsigned long n, char* s) { - static Mutex globalLock; - static Salsa20 s20; - static bool s20Initialized = false; - static uint8_t randomBuf[65536]; - static unsigned int randomPtr = sizeof(randomBuf); + if (n == 0) { + return 0; + } + unsigned long pos = _Utils_itoa(n / 10, s); + if (pos >= 22) { // sanity check, should be impossible + pos = 22; + } + s[pos] = '0' + (char)(n % 10); + return pos + 1; +} +char* Utils::decimal(unsigned long n, char s[24]) +{ + if (n == 0) { + s[0] = '0'; + s[1] = (char)0; + return s; + } + s[_Utils_itoa(n, s)] = (char)0; + return s; +} - Mutex::Lock _l(globalLock); +void Utils::getSecureRandom(void* buf, unsigned int bytes) +{ + static Mutex globalLock; + static Salsa20 s20; + static bool s20Initialized = false; + static uint8_t randomBuf[65536]; + static unsigned int randomPtr = sizeof(randomBuf); - /* Just for posterity we Salsa20 encrypt the result of whatever system - * CSPRNG we use. There have been several bugs at the OS or OS distribution - * level in the past that resulted in systematically weak or predictable - * keys due to random seeding problems. This mitigates that by grabbing - * a bit of extra entropy and further randomizing the result, and comes - * at almost no cost and with no real downside if the random source is - * good. */ - if (!s20Initialized) { - s20Initialized = true; - uint64_t s20Key[4]; - s20Key[0] = (uint64_t)time(0); // system clock - s20Key[1] = (uint64_t)buf; // address of buf - s20Key[2] = (uint64_t)s20Key; // address of s20Key[] - s20Key[3] = (uint64_t)&s20; // address of s20 - s20.init(s20Key,s20Key); - } + Mutex::Lock _l(globalLock); + + /* Just for posterity we Salsa20 encrypt the result of whatever system + * CSPRNG we use. There have been several bugs at the OS or OS distribution + * level in the past that resulted in systematically weak or predictable + * keys due to random seeding problems. This mitigates that by grabbing + * a bit of extra entropy and further randomizing the result, and comes + * at almost no cost and with no real downside if the random source is + * good. */ + if (! s20Initialized) { + s20Initialized = true; + uint64_t s20Key[4]; + s20Key[0] = (uint64_t)time(0); // system clock + s20Key[1] = (uint64_t)buf; // address of buf + s20Key[2] = (uint64_t)s20Key; // address of s20Key[] + s20Key[3] = (uint64_t)&s20; // address of s20 + s20.init(s20Key, s20Key); + } #ifdef __WINDOWS__ - static HCRYPTPROV cryptProvider = NULL; + static HCRYPTPROV cryptProvider = NULL; - for(unsigned int i=0;i= sizeof(randomBuf)) { - if (cryptProvider == NULL) { - if (!CryptAcquireContextA(&cryptProvider,NULL,NULL,PROV_RSA_FULL,CRYPT_VERIFYCONTEXT|CRYPT_SILENT)) { - fprintf(stderr,"FATAL ERROR: Utils::getSecureRandom() unable to obtain WinCrypt context!\r\n"); - exit(1); - } - } - if (!CryptGenRandom(cryptProvider,(DWORD)sizeof(randomBuf),(BYTE *)randomBuf)) { - fprintf(stderr,"FATAL ERROR: Utils::getSecureRandom() CryptGenRandom failed!\r\n"); - exit(1); - } - randomPtr = 0; - s20.crypt12(randomBuf,randomBuf,sizeof(randomBuf)); - s20.init(randomBuf,randomBuf); - } - ((uint8_t *)buf)[i] = randomBuf[randomPtr++]; - } + for (unsigned int i = 0; i < bytes; ++i) { + if (randomPtr >= sizeof(randomBuf)) { + if (cryptProvider == NULL) { + if (! CryptAcquireContextA(&cryptProvider, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) { + fprintf(stderr, "FATAL ERROR: Utils::getSecureRandom() unable to obtain WinCrypt context!\r\n"); + exit(1); + } + } + if (! CryptGenRandom(cryptProvider, (DWORD)sizeof(randomBuf), (BYTE*)randomBuf)) { + fprintf(stderr, "FATAL ERROR: Utils::getSecureRandom() CryptGenRandom failed!\r\n"); + exit(1); + } + randomPtr = 0; + s20.crypt12(randomBuf, randomBuf, sizeof(randomBuf)); + s20.init(randomBuf, randomBuf); + } + ((uint8_t*)buf)[i] = randomBuf[randomPtr++]; + } -#else // not __WINDOWS__ +#else // not __WINDOWS__ - static int devURandomFd = -1; + static int devURandomFd = -1; - if (devURandomFd < 0) { - devURandomFd = ::open("/dev/urandom",O_RDONLY); - if (devURandomFd < 0) { - fprintf(stderr,"FATAL ERROR: Utils::getSecureRandom() unable to open /dev/urandom\n"); - exit(1); - return; - } - } + if (devURandomFd < 0) { + devURandomFd = ::open("/dev/urandom", O_RDONLY); + if (devURandomFd < 0) { + fprintf(stderr, "FATAL ERROR: Utils::getSecureRandom() unable to open /dev/urandom\n"); + exit(1); + return; + } + } - for(unsigned int i=0;i= sizeof(randomBuf)) { - for(;;) { - if ((int)::read(devURandomFd,randomBuf,sizeof(randomBuf)) != (int)sizeof(randomBuf)) { - ::close(devURandomFd); - devURandomFd = ::open("/dev/urandom",O_RDONLY); - if (devURandomFd < 0) { - fprintf(stderr,"FATAL ERROR: Utils::getSecureRandom() unable to open /dev/urandom\n"); - exit(1); - return; - } - } else { - break; - } - } - randomPtr = 0; - s20.crypt12(randomBuf,randomBuf,sizeof(randomBuf)); - s20.init(randomBuf,randomBuf); - } - ((uint8_t *)buf)[i] = randomBuf[randomPtr++]; - } + for (unsigned int i = 0; i < bytes; ++i) { + if (randomPtr >= sizeof(randomBuf)) { + for (;;) { + if ((int)::read(devURandomFd, randomBuf, sizeof(randomBuf)) != (int)sizeof(randomBuf)) { + ::close(devURandomFd); + devURandomFd = ::open("/dev/urandom", O_RDONLY); + if (devURandomFd < 0) { + fprintf(stderr, "FATAL ERROR: Utils::getSecureRandom() unable to open /dev/urandom\n"); + exit(1); + return; + } + } + else { + break; + } + } + randomPtr = 0; + s20.crypt12(randomBuf, randomBuf, sizeof(randomBuf)); + s20.init(randomBuf, randomBuf); + } + ((uint8_t*)buf)[i] = randomBuf[randomPtr++]; + } -#endif // __WINDOWS__ or not +#endif // __WINDOWS__ or not } -} // namespace ZeroTier +} // namespace ZeroTier diff --git a/node/Utils.hpp b/node/Utils.hpp index 41809cba..e1b2d19d 100644 --- a/node/Utils.hpp +++ b/node/Utils.hpp @@ -14,17 +14,16 @@ #ifndef ZT_UTILS_HPP #define ZT_UTILS_HPP +#include +#include +#include +#include #include #include -#include #include -#include - #include -#include +#include #include -#include -#include #if defined(__FreeBSD__) #include @@ -34,15 +33,9 @@ #if __BYTE_ORDER == __LITTLE_ENDIAN #define ZT_CONST_TO_BE_UINT16(x) ((uint16_t)((uint16_t)((uint16_t)(x) << 8U) | (uint16_t)((uint16_t)(x) >> 8U))) -#define ZT_CONST_TO_BE_UINT64(x) ( \ - (((uint64_t)(x) & 0x00000000000000ffULL) << 56U) | \ - (((uint64_t)(x) & 0x000000000000ff00ULL) << 40U) | \ - (((uint64_t)(x) & 0x0000000000ff0000ULL) << 24U) | \ - (((uint64_t)(x) & 0x00000000ff000000ULL) << 8U) | \ - (((uint64_t)(x) & 0x000000ff00000000ULL) >> 8U) | \ - (((uint64_t)(x) & 0x0000ff0000000000ULL) >> 24U) | \ - (((uint64_t)(x) & 0x00ff000000000000ULL) >> 40U) | \ - (((uint64_t)(x) & 0xff00000000000000ULL) >> 56U)) +#define ZT_CONST_TO_BE_UINT64(x) \ + ((((uint64_t)(x) & 0x00000000000000ffULL) << 56U) | (((uint64_t)(x) & 0x000000000000ff00ULL) << 40U) | (((uint64_t)(x) & 0x0000000000ff0000ULL) << 24U) | (((uint64_t)(x) & 0x00000000ff000000ULL) << 8U) \ + | (((uint64_t)(x) & 0x000000ff00000000ULL) >> 8U) | (((uint64_t)(x) & 0x0000ff0000000000ULL) >> 24U) | (((uint64_t)(x) & 0x00ff000000000000ULL) >> 40U) | (((uint64_t)(x) & 0xff00000000000000ULL) >> 56U)) #else #define ZT_CONST_TO_BE_UINT16(x) ((uint16_t)(x)) #define ZT_CONST_TO_BE_UINT64(x) ((uint64_t)(x)) @@ -58,813 +51,825 @@ namespace ZeroTier { /** * Miscellaneous utility functions and global constants */ -class Utils -{ -public: - static const uint64_t ZERO256[4]; +class Utils { + public: + static const uint64_t ZERO256[4]; #ifdef ZT_ARCH_ARM_HAS_NEON - struct ARMCapabilities - { - ARMCapabilities() noexcept; + struct ARMCapabilities { + ARMCapabilities() noexcept; - bool aes; - bool crc32; - bool pmull; - bool sha1; - bool sha2; - }; - static const ARMCapabilities ARMCAP; + bool aes; + bool crc32; + bool pmull; + bool sha1; + bool sha2; + }; + static const ARMCapabilities ARMCAP; #endif #ifdef ZT_ARCH_X64 - struct CPUIDRegisters - { - CPUIDRegisters() noexcept; + struct CPUIDRegisters { + CPUIDRegisters() noexcept; - bool rdrand; - bool aes; - bool avx; - bool vaes; // implies AVX - bool vpclmulqdq; // implies AVX - bool avx2; - bool avx512f; - bool sha; - bool fsrm; - }; - static const CPUIDRegisters CPUID; + bool rdrand; + bool aes; + bool avx; + bool vaes; // implies AVX + bool vpclmulqdq; // implies AVX + bool avx2; + bool avx512f; + bool sha; + bool fsrm; + }; + static const CPUIDRegisters CPUID; #endif - /** - * Compute the log2 (most significant bit set) of a 32-bit integer - * - * @param v Integer to compute - * @return log2 or 0 if v is 0 - */ - static inline unsigned int log2(uint32_t v) - { - uint32_t r = (v > 0xffff) << 4; - v >>= r; - uint32_t shift = (v > 0xff) << 3; - v >>= shift; - r |= shift; - shift = (v > 0xf) << 2; - v >>= shift; - r |= shift; - shift = (v > 0x3) << 1; - v >>= shift; - r |= shift; - r |= (v >> 1); - return (unsigned int)r; - } + /** + * Compute the log2 (most significant bit set) of a 32-bit integer + * + * @param v Integer to compute + * @return log2 or 0 if v is 0 + */ + static inline unsigned int log2(uint32_t v) + { + uint32_t r = (v > 0xffff) << 4; + v >>= r; + uint32_t shift = (v > 0xff) << 3; + v >>= shift; + r |= shift; + shift = (v > 0xf) << 2; + v >>= shift; + r |= shift; + shift = (v > 0x3) << 1; + v >>= shift; + r |= shift; + r |= (v >> 1); + return (unsigned int)r; + } - /** - * Perform a time-invariant binary comparison - * - * @param a First binary string - * @param b Second binary string - * @param len Length of strings - * @return True if strings are equal - */ - static inline bool secureEq(const void *a,const void *b,unsigned int len) - { - uint8_t diff = 0; - for(unsigned int i=0;i(a))[i] ^ (reinterpret_cast(b))[i] ); - } - return (diff == 0); - } + /** + * Perform a time-invariant binary comparison + * + * @param a First binary string + * @param b Second binary string + * @param len Length of strings + * @return True if strings are equal + */ + static inline bool secureEq(const void* a, const void* b, unsigned int len) + { + uint8_t diff = 0; + for (unsigned int i = 0; i < len; ++i) { + diff |= ((reinterpret_cast(a))[i] ^ (reinterpret_cast(b))[i]); + } + return (diff == 0); + } - /** - * Securely zero memory, avoiding compiler optimizations and such - */ - static void burn(void *ptr,unsigned int len); + /** + * Securely zero memory, avoiding compiler optimizations and such + */ + static void burn(void* ptr, unsigned int len); - /** - * @param n Number to convert - * @param s Buffer, at least 24 bytes in size - * @return String containing 'n' in base 10 form - */ - static char *decimal(unsigned long n,char s[24]); + /** + * @param n Number to convert + * @param s Buffer, at least 24 bytes in size + * @return String containing 'n' in base 10 form + */ + static char* decimal(unsigned long n, char s[24]); - static inline char *hex(uint64_t i,char s[17]) - { - s[0] = HEXCHARS[(i >> 60) & 0xf]; - s[1] = HEXCHARS[(i >> 56) & 0xf]; - s[2] = HEXCHARS[(i >> 52) & 0xf]; - s[3] = HEXCHARS[(i >> 48) & 0xf]; - s[4] = HEXCHARS[(i >> 44) & 0xf]; - s[5] = HEXCHARS[(i >> 40) & 0xf]; - s[6] = HEXCHARS[(i >> 36) & 0xf]; - s[7] = HEXCHARS[(i >> 32) & 0xf]; - s[8] = HEXCHARS[(i >> 28) & 0xf]; - s[9] = HEXCHARS[(i >> 24) & 0xf]; - s[10] = HEXCHARS[(i >> 20) & 0xf]; - s[11] = HEXCHARS[(i >> 16) & 0xf]; - s[12] = HEXCHARS[(i >> 12) & 0xf]; - s[13] = HEXCHARS[(i >> 8) & 0xf]; - s[14] = HEXCHARS[(i >> 4) & 0xf]; - s[15] = HEXCHARS[i & 0xf]; - s[16] = (char)0; - return s; - } + static inline char* hex(uint64_t i, char s[17]) + { + s[0] = HEXCHARS[(i >> 60) & 0xf]; + s[1] = HEXCHARS[(i >> 56) & 0xf]; + s[2] = HEXCHARS[(i >> 52) & 0xf]; + s[3] = HEXCHARS[(i >> 48) & 0xf]; + s[4] = HEXCHARS[(i >> 44) & 0xf]; + s[5] = HEXCHARS[(i >> 40) & 0xf]; + s[6] = HEXCHARS[(i >> 36) & 0xf]; + s[7] = HEXCHARS[(i >> 32) & 0xf]; + s[8] = HEXCHARS[(i >> 28) & 0xf]; + s[9] = HEXCHARS[(i >> 24) & 0xf]; + s[10] = HEXCHARS[(i >> 20) & 0xf]; + s[11] = HEXCHARS[(i >> 16) & 0xf]; + s[12] = HEXCHARS[(i >> 12) & 0xf]; + s[13] = HEXCHARS[(i >> 8) & 0xf]; + s[14] = HEXCHARS[(i >> 4) & 0xf]; + s[15] = HEXCHARS[i & 0xf]; + s[16] = (char)0; + return s; + } - static inline char *hex10(uint64_t i,char s[11]) - { - s[0] = HEXCHARS[(i >> 36) & 0xf]; - s[1] = HEXCHARS[(i >> 32) & 0xf]; - s[2] = HEXCHARS[(i >> 28) & 0xf]; - s[3] = HEXCHARS[(i >> 24) & 0xf]; - s[4] = HEXCHARS[(i >> 20) & 0xf]; - s[5] = HEXCHARS[(i >> 16) & 0xf]; - s[6] = HEXCHARS[(i >> 12) & 0xf]; - s[7] = HEXCHARS[(i >> 8) & 0xf]; - s[8] = HEXCHARS[(i >> 4) & 0xf]; - s[9] = HEXCHARS[i & 0xf]; - s[10] = (char)0; - return s; - } + static inline char* hex10(uint64_t i, char s[11]) + { + s[0] = HEXCHARS[(i >> 36) & 0xf]; + s[1] = HEXCHARS[(i >> 32) & 0xf]; + s[2] = HEXCHARS[(i >> 28) & 0xf]; + s[3] = HEXCHARS[(i >> 24) & 0xf]; + s[4] = HEXCHARS[(i >> 20) & 0xf]; + s[5] = HEXCHARS[(i >> 16) & 0xf]; + s[6] = HEXCHARS[(i >> 12) & 0xf]; + s[7] = HEXCHARS[(i >> 8) & 0xf]; + s[8] = HEXCHARS[(i >> 4) & 0xf]; + s[9] = HEXCHARS[i & 0xf]; + s[10] = (char)0; + return s; + } - static inline char *hex(uint32_t i,char s[9]) - { - s[0] = HEXCHARS[(i >> 28) & 0xf]; - s[1] = HEXCHARS[(i >> 24) & 0xf]; - s[2] = HEXCHARS[(i >> 20) & 0xf]; - s[3] = HEXCHARS[(i >> 16) & 0xf]; - s[4] = HEXCHARS[(i >> 12) & 0xf]; - s[5] = HEXCHARS[(i >> 8) & 0xf]; - s[6] = HEXCHARS[(i >> 4) & 0xf]; - s[7] = HEXCHARS[i & 0xf]; - s[8] = (char)0; - return s; - } + static inline char* hex(uint32_t i, char s[9]) + { + s[0] = HEXCHARS[(i >> 28) & 0xf]; + s[1] = HEXCHARS[(i >> 24) & 0xf]; + s[2] = HEXCHARS[(i >> 20) & 0xf]; + s[3] = HEXCHARS[(i >> 16) & 0xf]; + s[4] = HEXCHARS[(i >> 12) & 0xf]; + s[5] = HEXCHARS[(i >> 8) & 0xf]; + s[6] = HEXCHARS[(i >> 4) & 0xf]; + s[7] = HEXCHARS[i & 0xf]; + s[8] = (char)0; + return s; + } - static inline char *hex(uint16_t i,char s[5]) - { - s[0] = HEXCHARS[(i >> 12) & 0xf]; - s[1] = HEXCHARS[(i >> 8) & 0xf]; - s[2] = HEXCHARS[(i >> 4) & 0xf]; - s[3] = HEXCHARS[i & 0xf]; - s[4] = (char)0; - return s; - } + static inline char* hex(uint16_t i, char s[5]) + { + s[0] = HEXCHARS[(i >> 12) & 0xf]; + s[1] = HEXCHARS[(i >> 8) & 0xf]; + s[2] = HEXCHARS[(i >> 4) & 0xf]; + s[3] = HEXCHARS[i & 0xf]; + s[4] = (char)0; + return s; + } - static inline char *hex(uint8_t i,char s[3]) - { - s[0] = HEXCHARS[(i >> 4) & 0xf]; - s[1] = HEXCHARS[i & 0xf]; - s[2] = (char)0; - return s; - } + static inline char* hex(uint8_t i, char s[3]) + { + s[0] = HEXCHARS[(i >> 4) & 0xf]; + s[1] = HEXCHARS[i & 0xf]; + s[2] = (char)0; + return s; + } - static inline char *hex(const void *d,unsigned int l,char *s) - { - char *const save = s; - for(unsigned int i=0;i(d)[i]; - *(s++) = HEXCHARS[b >> 4]; - *(s++) = HEXCHARS[b & 0xf]; - } - *s = (char)0; - return save; - } + static inline char* hex(const void* d, unsigned int l, char* s) + { + char* const save = s; + for (unsigned int i = 0; i < l; ++i) { + const unsigned int b = reinterpret_cast(d)[i]; + *(s++) = HEXCHARS[b >> 4]; + *(s++) = HEXCHARS[b & 0xf]; + } + *s = (char)0; + return save; + } - static inline unsigned int unhex(const char *h,void *buf,unsigned int buflen) - { - unsigned int l = 0; - while (l < buflen) { - uint8_t hc = *(reinterpret_cast(h++)); - if (!hc) { - break; - } + static inline unsigned int unhex(const char* h, void* buf, unsigned int buflen) + { + unsigned int l = 0; + while (l < buflen) { + uint8_t hc = *(reinterpret_cast(h++)); + if (! hc) { + break; + } - uint8_t c = 0; - if ((hc >= 48)&&(hc <= 57)) { // 0..9 - c = hc - 48; - } else if ((hc >= 97)&&(hc <= 102)) { // a..f - c = hc - 87; - } else if ((hc >= 65)&&(hc <= 70)) { // A..F - c = hc - 55; - } + uint8_t c = 0; + if ((hc >= 48) && (hc <= 57)) { // 0..9 + c = hc - 48; + } + else if ((hc >= 97) && (hc <= 102)) { // a..f + c = hc - 87; + } + else if ((hc >= 65) && (hc <= 70)) { // A..F + c = hc - 55; + } - hc = *(reinterpret_cast(h++)); - if (!hc) { - break; - } + hc = *(reinterpret_cast(h++)); + if (! hc) { + break; + } - c <<= 4; - if ((hc >= 48)&&(hc <= 57)) { - c |= hc - 48; - } else if ((hc >= 97)&&(hc <= 102)) { - c |= hc - 87; - } else if ((hc >= 65)&&(hc <= 70)) { - c |= hc - 55; - } + c <<= 4; + if ((hc >= 48) && (hc <= 57)) { + c |= hc - 48; + } + else if ((hc >= 97) && (hc <= 102)) { + c |= hc - 87; + } + else if ((hc >= 65) && (hc <= 70)) { + c |= hc - 55; + } - reinterpret_cast(buf)[l++] = c; - } - return l; - } + reinterpret_cast(buf)[l++] = c; + } + return l; + } - static inline unsigned int unhex(const char *h,unsigned int hlen,void *buf,unsigned int buflen) - { - unsigned int l = 0; - const char *hend = h + hlen; - while (l < buflen) { - if (h == hend) { - break; - } - uint8_t hc = *(reinterpret_cast(h++)); - if (!hc) { - break; - } + static inline unsigned int unhex(const char* h, unsigned int hlen, void* buf, unsigned int buflen) + { + unsigned int l = 0; + const char* hend = h + hlen; + while (l < buflen) { + if (h == hend) { + break; + } + uint8_t hc = *(reinterpret_cast(h++)); + if (! hc) { + break; + } - uint8_t c = 0; - if ((hc >= 48)&&(hc <= 57)) { - c = hc - 48; - } else if ((hc >= 97)&&(hc <= 102)) { - c = hc - 87; - } else if ((hc >= 65)&&(hc <= 70)) { - c = hc - 55; - } + uint8_t c = 0; + if ((hc >= 48) && (hc <= 57)) { + c = hc - 48; + } + else if ((hc >= 97) && (hc <= 102)) { + c = hc - 87; + } + else if ((hc >= 65) && (hc <= 70)) { + c = hc - 55; + } - if (h == hend) { - break; - } - hc = *(reinterpret_cast(h++)); - if (!hc) { - break; - } + if (h == hend) { + break; + } + hc = *(reinterpret_cast(h++)); + if (! hc) { + break; + } - c <<= 4; - if ((hc >= 48)&&(hc <= 57)) { - c |= hc - 48; - } else if ((hc >= 97)&&(hc <= 102)) { - c |= hc - 87; - } else if ((hc >= 65)&&(hc <= 70)) { - c |= hc - 55; - } + c <<= 4; + if ((hc >= 48) && (hc <= 57)) { + c |= hc - 48; + } + else if ((hc >= 97) && (hc <= 102)) { + c |= hc - 87; + } + else if ((hc >= 65) && (hc <= 70)) { + c |= hc - 55; + } - reinterpret_cast(buf)[l++] = c; - } - return l; - } + reinterpret_cast(buf)[l++] = c; + } + return l; + } - static inline float normalize(float value, float bigMin, float bigMax, float targetMin, float targetMax) - { - float bigSpan = bigMax - bigMin; - float smallSpan = targetMax - targetMin; - float valueScaled = (value - bigMin) / bigSpan; - return targetMin + valueScaled * smallSpan; - } + static inline float normalize(float value, float bigMin, float bigMax, float targetMin, float targetMax) + { + float bigSpan = bigMax - bigMin; + float smallSpan = targetMax - targetMin; + float valueScaled = (value - bigMin) / bigSpan; + return targetMin + valueScaled * smallSpan; + } - /** - * Generate secure random bytes - * - * This will try to use whatever OS sources of entropy are available. It's - * guarded by an internal mutex so it's thread-safe. - * - * @param buf Buffer to fill - * @param bytes Number of random bytes to generate - */ - static void getSecureRandom(void *buf,unsigned int bytes); + /** + * Generate secure random bytes + * + * This will try to use whatever OS sources of entropy are available. It's + * guarded by an internal mutex so it's thread-safe. + * + * @param buf Buffer to fill + * @param bytes Number of random bytes to generate + */ + static void getSecureRandom(void* buf, unsigned int bytes); - /** - * Tokenize a string (alias for strtok_r or strtok_s depending on platform) - * - * @param str String to split - * @param delim Delimiters - * @param saveptr Pointer to a char * for temporary reentrant storage - */ - static inline char *stok(char *str,const char *delim,char **saveptr) - { + /** + * Tokenize a string (alias for strtok_r or strtok_s depending on platform) + * + * @param str String to split + * @param delim Delimiters + * @param saveptr Pointer to a char * for temporary reentrant storage + */ + static inline char* stok(char* str, const char* delim, char** saveptr) + { #ifdef __WINDOWS__ - return strtok_s(str,delim,saveptr); + return strtok_s(str, delim, saveptr); #else - return strtok_r(str,delim,saveptr); + return strtok_r(str, delim, saveptr); #endif - } + } - static inline unsigned int strToUInt(const char *s) { return (unsigned int)strtoul(s,(char **)0,10); } - static inline int strToInt(const char *s) { return (int)strtol(s,(char **)0,10); } - static inline unsigned long strToULong(const char *s) { return strtoul(s,(char **)0,10); } - static inline long strToLong(const char *s) { return strtol(s,(char **)0,10); } - static inline double strToDouble(const char *s) { return strtod(s,NULL); } - static inline unsigned long long strToU64(const char *s) - { + static inline unsigned int strToUInt(const char* s) + { + return (unsigned int)strtoul(s, (char**)0, 10); + } + static inline int strToInt(const char* s) + { + return (int)strtol(s, (char**)0, 10); + } + static inline unsigned long strToULong(const char* s) + { + return strtoul(s, (char**)0, 10); + } + static inline long strToLong(const char* s) + { + return strtol(s, (char**)0, 10); + } + static inline double strToDouble(const char* s) + { + return strtod(s, NULL); + } + static inline unsigned long long strToU64(const char* s) + { #ifdef __WINDOWS__ - return (unsigned long long)_strtoui64(s,(char **)0,10); + return (unsigned long long)_strtoui64(s, (char**)0, 10); #else - return strtoull(s,(char **)0,10); + return strtoull(s, (char**)0, 10); #endif - } - static inline long long strTo64(const char *s) - { + } + static inline long long strTo64(const char* s) + { #ifdef __WINDOWS__ - return (long long)_strtoi64(s,(char **)0,10); + return (long long)_strtoi64(s, (char**)0, 10); #else - return strtoll(s,(char **)0,10); + return strtoll(s, (char**)0, 10); #endif - } - static inline unsigned int hexStrToUInt(const char *s) { return (unsigned int)strtoul(s,(char **)0,16); } - static inline int hexStrToInt(const char *s) { return (int)strtol(s,(char **)0,16); } - static inline unsigned long hexStrToULong(const char *s) { return strtoul(s,(char **)0,16); } - static inline long hexStrToLong(const char *s) { return strtol(s,(char **)0,16); } - static inline unsigned long long hexStrToU64(const char *s) - { + } + static inline unsigned int hexStrToUInt(const char* s) + { + return (unsigned int)strtoul(s, (char**)0, 16); + } + static inline int hexStrToInt(const char* s) + { + return (int)strtol(s, (char**)0, 16); + } + static inline unsigned long hexStrToULong(const char* s) + { + return strtoul(s, (char**)0, 16); + } + static inline long hexStrToLong(const char* s) + { + return strtol(s, (char**)0, 16); + } + static inline unsigned long long hexStrToU64(const char* s) + { #ifdef __WINDOWS__ - return (unsigned long long)_strtoui64(s,(char **)0,16); + return (unsigned long long)_strtoui64(s, (char**)0, 16); #else - return strtoull(s,(char **)0,16); + return strtoull(s, (char**)0, 16); #endif - } - static inline long long hexStrTo64(const char *s) - { + } + static inline long long hexStrTo64(const char* s) + { #ifdef __WINDOWS__ - return (long long)_strtoi64(s,(char **)0,16); + return (long long)_strtoi64(s, (char**)0, 16); #else - return strtoll(s,(char **)0,16); + return strtoll(s, (char**)0, 16); #endif - } + } - /** - * Perform a safe C string copy, ALWAYS null-terminating the result - * - * This will never ever EVER result in dest[] not being null-terminated - * regardless of any input parameter (other than len==0 which is invalid). - * - * @param dest Destination buffer (must not be NULL) - * @param len Length of dest[] (if zero, false is returned and nothing happens) - * @param src Source string (if NULL, dest will receive a zero-length string and true is returned) - * @return True on success, false on overflow (buffer will still be 0-terminated) - */ - static inline bool scopy(char *dest,unsigned int len,const char *src) - { - if (!len) { - return false; // sanity check - } - if (!src) { - *dest = (char)0; - return true; - } - char *end = dest + len; - while ((*dest++ = *src++)) { - if (dest == end) { - *(--dest) = (char)0; - return false; - } - } - return true; - } + /** + * Perform a safe C string copy, ALWAYS null-terminating the result + * + * This will never ever EVER result in dest[] not being null-terminated + * regardless of any input parameter (other than len==0 which is invalid). + * + * @param dest Destination buffer (must not be NULL) + * @param len Length of dest[] (if zero, false is returned and nothing happens) + * @param src Source string (if NULL, dest will receive a zero-length string and true is returned) + * @return True on success, false on overflow (buffer will still be 0-terminated) + */ + static inline bool scopy(char* dest, unsigned int len, const char* src) + { + if (! len) { + return false; // sanity check + } + if (! src) { + *dest = (char)0; + return true; + } + char* end = dest + len; + while ((*dest++ = *src++)) { + if (dest == end) { + *(--dest) = (char)0; + return false; + } + } + return true; + } - /** - * Count the number of bits set in an integer - * - * @param v 32-bit integer - * @return Number of bits set in this integer (0-32) - */ - static inline uint32_t countBits(uint32_t v) - { - v = v - ((v >> 1) & (uint32_t)0x55555555); - v = (v & (uint32_t)0x33333333) + ((v >> 2) & (uint32_t)0x33333333); - return ((((v + (v >> 4)) & (uint32_t)0xF0F0F0F) * (uint32_t)0x1010101) >> 24); - } + /** + * Count the number of bits set in an integer + * + * @param v 32-bit integer + * @return Number of bits set in this integer (0-32) + */ + static inline uint32_t countBits(uint32_t v) + { + v = v - ((v >> 1) & (uint32_t)0x55555555); + v = (v & (uint32_t)0x33333333) + ((v >> 2) & (uint32_t)0x33333333); + return ((((v + (v >> 4)) & (uint32_t)0xF0F0F0F) * (uint32_t)0x1010101) >> 24); + } - /** - * Count the number of bits set in an integer - * - * @param v 64-bit integer - * @return Number of bits set in this integer (0-64) - */ - static inline uint64_t countBits(uint64_t v) - { - v = v - ((v >> 1) & (uint64_t)~(uint64_t)0/3); - v = (v & (uint64_t)~(uint64_t)0/15*3) + ((v >> 2) & (uint64_t)~(uint64_t)0/15*3); - v = (v + (v >> 4)) & (uint64_t)~(uint64_t)0/255*15; - return (uint64_t)(v * ((uint64_t)~(uint64_t)0/255)) >> 56; - } + /** + * Count the number of bits set in an integer + * + * @param v 64-bit integer + * @return Number of bits set in this integer (0-64) + */ + static inline uint64_t countBits(uint64_t v) + { + v = v - ((v >> 1) & (uint64_t)~(uint64_t)0 / 3); + v = (v & (uint64_t)~(uint64_t)0 / 15 * 3) + ((v >> 2) & (uint64_t)~(uint64_t)0 / 15 * 3); + v = (v + (v >> 4)) & (uint64_t)~(uint64_t)0 / 255 * 15; + return (uint64_t)(v * ((uint64_t)~(uint64_t)0 / 255)) >> 56; + } - /** - * Check if a memory buffer is all-zero - * - * @param p Memory to scan - * @param len Length of memory - * @return True if memory is all zero - */ - static inline bool isZero(const void *p,unsigned int len) - { - for(unsigned int i=0;i> 8) | - ((n & 0x0000ff0000000000ULL) >> 24) | - ((n & 0x00ff000000000000ULL) >> 40) | - ((n & 0xff00000000000000ULL) >> 56) - ); - #endif - #endif - } + /** + * Unconditionally swap bytes regardless of host byte order + * + * @param n Integer to swap + * @return Integer with bytes reversed + */ + static ZT_INLINE uint64_t swapBytes(const uint64_t n) noexcept + { +#ifdef __GNUC__ + return __builtin_bswap64(n); +#else +#ifdef _MSC_VER + return (uint64_t)_byteswap_uint64((unsigned __int64)n); +#else + return ( + ((n & 0x00000000000000ffULL) << 56) | ((n & 0x000000000000ff00ULL) << 40) | ((n & 0x0000000000ff0000ULL) << 24) | ((n & 0x00000000ff000000ULL) << 8) | ((n & 0x000000ff00000000ULL) >> 8) | ((n & 0x0000ff0000000000ULL) >> 24) + | ((n & 0x00ff000000000000ULL) >> 40) | ((n & 0xff00000000000000ULL) >> 56)); +#endif +#endif + } - /** - * Unconditionally swap bytes regardless of host byte order - * - * @param n Integer to swap - * @return Integer with bytes reversed - */ - static ZT_INLINE uint32_t swapBytes(const uint32_t n) noexcept - { - #if defined(__GNUC__) - return __builtin_bswap32(n); - #else - #ifdef _MSC_VER - return (uint32_t)_byteswap_ulong((unsigned long)n); - #else - return htonl(n); - #endif - #endif - } + /** + * Unconditionally swap bytes regardless of host byte order + * + * @param n Integer to swap + * @return Integer with bytes reversed + */ + static ZT_INLINE uint32_t swapBytes(const uint32_t n) noexcept + { +#if defined(__GNUC__) + return __builtin_bswap32(n); +#else +#ifdef _MSC_VER + return (uint32_t)_byteswap_ulong((unsigned long)n); +#else + return htonl(n); +#endif +#endif + } - /** - * Unconditionally swap bytes regardless of host byte order - * - * @param n Integer to swap - * @return Integer with bytes reversed - */ - static ZT_INLINE uint16_t swapBytes(const uint16_t n) noexcept - { - #if defined(__GNUC__) - return __builtin_bswap16(n); - #else - #ifdef _MSC_VER - return (uint16_t)_byteswap_ushort((unsigned short)n); - #else - return htons(n); - #endif - #endif - } + /** + * Unconditionally swap bytes regardless of host byte order + * + * @param n Integer to swap + * @return Integer with bytes reversed + */ + static ZT_INLINE uint16_t swapBytes(const uint16_t n) noexcept + { +#if defined(__GNUC__) + return __builtin_bswap16(n); +#else +#ifdef _MSC_VER + return (uint16_t)_byteswap_ushort((unsigned short)n); +#else + return htons(n); +#endif +#endif + } - // These are helper adapters to load and swap integer types special cased by size - // to work with all typedef'd variants, signed/unsigned, etc. - template< typename I, unsigned int S > - class _swap_bytes_bysize; + // These are helper adapters to load and swap integer types special cased by size + // to work with all typedef'd variants, signed/unsigned, etc. + template class _swap_bytes_bysize; - template< typename I > - class _swap_bytes_bysize< I, 1 > - { - public: - static ZT_INLINE I s(const I n) noexcept - { return n; } - }; + template class _swap_bytes_bysize { + public: + static ZT_INLINE I s(const I n) noexcept + { + return n; + } + }; - template< typename I > - class _swap_bytes_bysize< I, 2 > - { - public: - static ZT_INLINE I s(const I n) noexcept - { return (I)swapBytes((uint16_t)n); } - }; + template class _swap_bytes_bysize { + public: + static ZT_INLINE I s(const I n) noexcept + { + return (I)swapBytes((uint16_t)n); + } + }; - template< typename I > - class _swap_bytes_bysize< I, 4 > - { - public: - static ZT_INLINE I s(const I n) noexcept - { return (I)swapBytes((uint32_t)n); } - }; + template class _swap_bytes_bysize { + public: + static ZT_INLINE I s(const I n) noexcept + { + return (I)swapBytes((uint32_t)n); + } + }; - template< typename I > - class _swap_bytes_bysize< I, 8 > - { - public: - static ZT_INLINE I s(const I n) noexcept - { return (I)swapBytes((uint64_t)n); } - }; + template class _swap_bytes_bysize { + public: + static ZT_INLINE I s(const I n) noexcept + { + return (I)swapBytes((uint64_t)n); + } + }; - template< typename I, unsigned int S > - class _load_be_bysize; + template class _load_be_bysize; - template< typename I > - class _load_be_bysize< I, 1 > - { - public: - static ZT_INLINE I l(const uint8_t *const p) noexcept - { return p[0]; } - }; + template class _load_be_bysize { + public: + static ZT_INLINE I l(const uint8_t* const p) noexcept + { + return p[0]; + } + }; - template< typename I > - class _load_be_bysize< I, 2 > - { - public: - static ZT_INLINE I l(const uint8_t *const p) noexcept - { return (I)(((unsigned int)p[0] << 8U) | (unsigned int)p[1]); } - }; + template class _load_be_bysize { + public: + static ZT_INLINE I l(const uint8_t* const p) noexcept + { + return (I)(((unsigned int)p[0] << 8U) | (unsigned int)p[1]); + } + }; - template< typename I > - class _load_be_bysize< I, 4 > - { - public: - static ZT_INLINE I l(const uint8_t *const p) noexcept - { return (I)(((uint32_t)p[0] << 24U) | ((uint32_t)p[1] << 16U) | ((uint32_t)p[2] << 8U) | (uint32_t)p[3]); } - }; + template class _load_be_bysize { + public: + static ZT_INLINE I l(const uint8_t* const p) noexcept + { + return (I)(((uint32_t)p[0] << 24U) | ((uint32_t)p[1] << 16U) | ((uint32_t)p[2] << 8U) | (uint32_t)p[3]); + } + }; - template< typename I > - class _load_be_bysize< I, 8 > - { - public: - static ZT_INLINE I l(const uint8_t *const p) noexcept - { return (I)(((uint64_t)p[0] << 56U) | ((uint64_t)p[1] << 48U) | ((uint64_t)p[2] << 40U) | ((uint64_t)p[3] << 32U) | ((uint64_t)p[4] << 24U) | ((uint64_t)p[5] << 16U) | ((uint64_t)p[6] << 8U) | (uint64_t)p[7]); } - }; + template class _load_be_bysize { + public: + static ZT_INLINE I l(const uint8_t* const p) noexcept + { + return (I)(((uint64_t)p[0] << 56U) | ((uint64_t)p[1] << 48U) | ((uint64_t)p[2] << 40U) | ((uint64_t)p[3] << 32U) | ((uint64_t)p[4] << 24U) | ((uint64_t)p[5] << 16U) | ((uint64_t)p[6] << 8U) | (uint64_t)p[7]); + } + }; - template< typename I, unsigned int S > - class _load_le_bysize; + template class _load_le_bysize; - template< typename I > - class _load_le_bysize< I, 1 > - { - public: - static ZT_INLINE I l(const uint8_t *const p) noexcept - { return p[0]; } - }; + template class _load_le_bysize { + public: + static ZT_INLINE I l(const uint8_t* const p) noexcept + { + return p[0]; + } + }; - template< typename I > - class _load_le_bysize< I, 2 > - { - public: - static ZT_INLINE I l(const uint8_t *const p) noexcept - { return (I)((unsigned int)p[0] | ((unsigned int)p[1] << 8U)); } - }; + template class _load_le_bysize { + public: + static ZT_INLINE I l(const uint8_t* const p) noexcept + { + return (I)((unsigned int)p[0] | ((unsigned int)p[1] << 8U)); + } + }; - template< typename I > - class _load_le_bysize< I, 4 > - { - public: - static ZT_INLINE I l(const uint8_t *const p) noexcept - { return (I)((uint32_t)p[0] | ((uint32_t)p[1] << 8U) | ((uint32_t)p[2] << 16U) | ((uint32_t)p[3] << 24U)); } - }; + template class _load_le_bysize { + public: + static ZT_INLINE I l(const uint8_t* const p) noexcept + { + return (I)((uint32_t)p[0] | ((uint32_t)p[1] << 8U) | ((uint32_t)p[2] << 16U) | ((uint32_t)p[3] << 24U)); + } + }; - template< typename I > - class _load_le_bysize< I, 8 > - { - public: - static ZT_INLINE I l(const uint8_t *const p) noexcept - { return (I)((uint64_t)p[0] | ((uint64_t)p[1] << 8U) | ((uint64_t)p[2] << 16U) | ((uint64_t)p[3] << 24U) | ((uint64_t)p[4] << 32U) | ((uint64_t)p[5] << 40U) | ((uint64_t)p[6] << 48U) | ((uint64_t)p[7]) << 56U); } - }; + template class _load_le_bysize { + public: + static ZT_INLINE I l(const uint8_t* const p) noexcept + { + return (I)((uint64_t)p[0] | ((uint64_t)p[1] << 8U) | ((uint64_t)p[2] << 16U) | ((uint64_t)p[3] << 24U) | ((uint64_t)p[4] << 32U) | ((uint64_t)p[5] << 40U) | ((uint64_t)p[6] << 48U) | ((uint64_t)p[7]) << 56U); + } + }; - /** - * Convert any signed or unsigned integer type to big-endian ("network") byte order - * - * @tparam I Integer type (usually inferred) - * @param n Value to convert - * @return Value in big-endian order - */ - template< typename I > - static ZT_INLINE I hton(const I n) noexcept - { - #if __BYTE_ORDER == __LITTLE_ENDIAN - return _swap_bytes_bysize< I, sizeof(I) >::s(n); - #else - return n; - #endif - } + /** + * Convert any signed or unsigned integer type to big-endian ("network") byte order + * + * @tparam I Integer type (usually inferred) + * @param n Value to convert + * @return Value in big-endian order + */ + template static ZT_INLINE I hton(const I n) noexcept + { +#if __BYTE_ORDER == __LITTLE_ENDIAN + return _swap_bytes_bysize::s(n); +#else + return n; +#endif + } - /** - * Convert any signed or unsigned integer type to host byte order from big-endian ("network") byte order - * - * @tparam I Integer type (usually inferred) - * @param n Value to convert - * @return Value in host byte order - */ - template< typename I > - static ZT_INLINE I ntoh(const I n) noexcept - { - #if __BYTE_ORDER == __LITTLE_ENDIAN - return _swap_bytes_bysize< I, sizeof(I) >::s(n); - #else - return n; - #endif - } + /** + * Convert any signed or unsigned integer type to host byte order from big-endian ("network") byte order + * + * @tparam I Integer type (usually inferred) + * @param n Value to convert + * @return Value in host byte order + */ + template static ZT_INLINE I ntoh(const I n) noexcept + { +#if __BYTE_ORDER == __LITTLE_ENDIAN + return _swap_bytes_bysize::s(n); +#else + return n; +#endif + } - /** - * Copy bits from memory into an integer type without modifying their order - * - * @tparam I Type to load - * @param p Byte stream, must be at least sizeof(I) in size - * @return Loaded raw integer - */ - template< typename I > - static ZT_INLINE I loadMachineEndian(const void *const p) noexcept - { - #ifdef ZT_NO_UNALIGNED_ACCESS - I tmp; - for(int i=0;i<(int)sizeof(I);++i) { - reinterpret_cast(&tmp)[i] = reinterpret_cast(p)[i]; - } - return tmp; - #else - return *reinterpret_cast(p); - #endif - } + /** + * Copy bits from memory into an integer type without modifying their order + * + * @tparam I Type to load + * @param p Byte stream, must be at least sizeof(I) in size + * @return Loaded raw integer + */ + template static ZT_INLINE I loadMachineEndian(const void* const p) noexcept + { +#ifdef ZT_NO_UNALIGNED_ACCESS + I tmp; + for (int i = 0; i < (int)sizeof(I); ++i) { + reinterpret_cast(&tmp)[i] = reinterpret_cast(p)[i]; + } + return tmp; +#else + return *reinterpret_cast(p); +#endif + } - /** - * Copy bits from memory into an integer type without modifying their order - * - * @tparam I Type to store - * @param p Byte array (must be at least sizeof(I)) - * @param i Integer to store - */ - template< typename I > - static ZT_INLINE void storeMachineEndian(void *const p, const I i) noexcept - { - #ifdef ZT_NO_UNALIGNED_ACCESS - for(unsigned int k=0;k(p)[k] = reinterpret_cast(&i)[k]; - } - #else - *reinterpret_cast(p) = i; - #endif - } + /** + * Copy bits from memory into an integer type without modifying their order + * + * @tparam I Type to store + * @param p Byte array (must be at least sizeof(I)) + * @param i Integer to store + */ + template static ZT_INLINE void storeMachineEndian(void* const p, const I i) noexcept + { +#ifdef ZT_NO_UNALIGNED_ACCESS + for (unsigned int k = 0; k < sizeof(I); ++k) { + reinterpret_cast(p)[k] = reinterpret_cast(&i)[k]; + } +#else + *reinterpret_cast(p) = i; +#endif + } - /** - * Decode a big-endian value from a byte stream - * - * @tparam I Type to decode (should be unsigned e.g. uint32_t or uint64_t) - * @param p Byte stream, must be at least sizeof(I) in size - * @return Decoded integer - */ - template< typename I > - static ZT_INLINE I loadBigEndian(const void *const p) noexcept - { - #ifdef ZT_NO_UNALIGNED_ACCESS - return _load_be_bysize::l(reinterpret_cast(p)); - #else - return ntoh(*reinterpret_cast(p)); - #endif - } + /** + * Decode a big-endian value from a byte stream + * + * @tparam I Type to decode (should be unsigned e.g. uint32_t or uint64_t) + * @param p Byte stream, must be at least sizeof(I) in size + * @return Decoded integer + */ + template static ZT_INLINE I loadBigEndian(const void* const p) noexcept + { +#ifdef ZT_NO_UNALIGNED_ACCESS + return _load_be_bysize::l(reinterpret_cast(p)); +#else + return ntoh(*reinterpret_cast(p)); +#endif + } - /** - * Save an integer in big-endian format - * - * @tparam I Integer type to store (usually inferred) - * @param p Byte stream to write (must be at least sizeof(I)) - * #param i Integer to write - */ - template< typename I > - static ZT_INLINE void storeBigEndian(void *const p, I i) noexcept - { - #ifdef ZT_NO_UNALIGNED_ACCESS - storeMachineEndian(p,hton(i)); - #else - *reinterpret_cast(p) = hton(i); - #endif - } + /** + * Save an integer in big-endian format + * + * @tparam I Integer type to store (usually inferred) + * @param p Byte stream to write (must be at least sizeof(I)) + * #param i Integer to write + */ + template static ZT_INLINE void storeBigEndian(void* const p, I i) noexcept + { +#ifdef ZT_NO_UNALIGNED_ACCESS + storeMachineEndian(p, hton(i)); +#else + *reinterpret_cast(p) = hton(i); +#endif + } - /** - * Decode a little-endian value from a byte stream - * - * @tparam I Type to decode - * @param p Byte stream, must be at least sizeof(I) in size - * @return Decoded integer - */ - template< typename I > - static ZT_INLINE I loadLittleEndian(const void *const p) noexcept - { - #if __BYTE_ORDER == __BIG_ENDIAN || defined(ZT_NO_UNALIGNED_ACCESS) - return _load_le_bysize::l(reinterpret_cast(p)); - #else - return *reinterpret_cast(p); - #endif - } + /** + * Decode a little-endian value from a byte stream + * + * @tparam I Type to decode + * @param p Byte stream, must be at least sizeof(I) in size + * @return Decoded integer + */ + template static ZT_INLINE I loadLittleEndian(const void* const p) noexcept + { +#if __BYTE_ORDER == __BIG_ENDIAN || defined(ZT_NO_UNALIGNED_ACCESS) + return _load_le_bysize::l(reinterpret_cast(p)); +#else + return *reinterpret_cast(p); +#endif + } - /** - * Save an integer in little-endian format - * - * @tparam I Integer type to store (usually inferred) - * @param p Byte stream to write (must be at least sizeof(I)) - * #param i Integer to write - */ - template< typename I > - static ZT_INLINE void storeLittleEndian(void *const p, const I i) noexcept - { - #if __BYTE_ORDER == __BIG_ENDIAN - storeMachineEndian(p,_swap_bytes_bysize::s(i)); - #else - #ifdef ZT_NO_UNALIGNED_ACCESS - storeMachineEndian(p,i); - #else - *reinterpret_cast(p) = i; - #endif - #endif - } + /** + * Save an integer in little-endian format + * + * @tparam I Integer type to store (usually inferred) + * @param p Byte stream to write (must be at least sizeof(I)) + * #param i Integer to write + */ + template static ZT_INLINE void storeLittleEndian(void* const p, const I i) noexcept + { +#if __BYTE_ORDER == __BIG_ENDIAN + storeMachineEndian(p, _swap_bytes_bysize::s(i)); +#else +#ifdef ZT_NO_UNALIGNED_ACCESS + storeMachineEndian(p, i); +#else + *reinterpret_cast(p) = i; +#endif +#endif + } - /** - * Copy memory block whose size is known at compile time. - * - * @tparam L Size of memory - * @param dest Destination memory - * @param src Source memory - */ - template< unsigned long L > - static ZT_INLINE void copy(void *dest, const void *src) noexcept - { - #if defined(ZT_ARCH_X64) && defined(__GNUC__) - uintptr_t l = L; - __asm__ __volatile__ ("cld ; rep movsb" : "+c"(l), "+S"(src), "+D"(dest) :: "memory"); - #else - memcpy(dest, src, L); - #endif - } + /** + * Copy memory block whose size is known at compile time. + * + * @tparam L Size of memory + * @param dest Destination memory + * @param src Source memory + */ + template static ZT_INLINE void copy(void* dest, const void* src) noexcept + { +#if defined(ZT_ARCH_X64) && defined(__GNUC__) + uintptr_t l = L; + __asm__ __volatile__("cld ; rep movsb" : "+c"(l), "+S"(src), "+D"(dest)::"memory"); +#else + memcpy(dest, src, L); +#endif + } - /** - * Copy memory block whose size is known at run time - * - * @param dest Destination memory - * @param src Source memory - * @param len Bytes to copy - */ - static ZT_INLINE void copy(void *dest, const void *src, unsigned long len) noexcept - { - #if defined(ZT_ARCH_X64) && defined(__GNUC__) - __asm__ __volatile__ ("cld ; rep movsb" : "+c"(len), "+S"(src), "+D"(dest) :: "memory"); - #else - memcpy(dest, src, len); - #endif - } + /** + * Copy memory block whose size is known at run time + * + * @param dest Destination memory + * @param src Source memory + * @param len Bytes to copy + */ + static ZT_INLINE void copy(void* dest, const void* src, unsigned long len) noexcept + { +#if defined(ZT_ARCH_X64) && defined(__GNUC__) + __asm__ __volatile__("cld ; rep movsb" : "+c"(len), "+S"(src), "+D"(dest)::"memory"); +#else + memcpy(dest, src, len); +#endif + } - /** - * Zero memory block whose size is known at compile time - * - * @tparam L Size in bytes - * @param dest Memory to zero - */ - template< unsigned long L > - static ZT_INLINE void zero(void *dest) noexcept - { - #if defined(ZT_ARCH_X64) && defined(__GNUC__) - uintptr_t l = L; - __asm__ __volatile__ ("cld ; rep stosb" :"+c" (l), "+D" (dest) : "a" (0) : "memory"); - #else - memset(dest, 0, L); - #endif - } + /** + * Zero memory block whose size is known at compile time + * + * @tparam L Size in bytes + * @param dest Memory to zero + */ + template static ZT_INLINE void zero(void* dest) noexcept + { +#if defined(ZT_ARCH_X64) && defined(__GNUC__) + uintptr_t l = L; + __asm__ __volatile__("cld ; rep stosb" : "+c"(l), "+D"(dest) : "a"(0) : "memory"); +#else + memset(dest, 0, L); +#endif + } - /** - * Zero memory block whose size is known at run time - * - * @param dest Memory to zero - * @param len Size in bytes - */ - static ZT_INLINE void zero(void *dest, unsigned long len) noexcept - { - #if defined(ZT_ARCH_X64) && defined(__GNUC__) - __asm__ __volatile__ ("cld ; rep stosb" :"+c" (len), "+D" (dest) : "a" (0) : "memory"); - #else - memset(dest, 0, len); - #endif - } + /** + * Zero memory block whose size is known at run time + * + * @param dest Memory to zero + * @param len Size in bytes + */ + static ZT_INLINE void zero(void* dest, unsigned long len) noexcept + { +#if defined(ZT_ARCH_X64) && defined(__GNUC__) + __asm__ __volatile__("cld ; rep stosb" : "+c"(len), "+D"(dest) : "a"(0) : "memory"); +#else + memset(dest, 0, len); +#endif + } - /** - * Hexadecimal characters 0-f - */ - static const char HEXCHARS[16]; + /** + * Hexadecimal characters 0-f + */ + static const char HEXCHARS[16]; - /* - * Remove `-` and `:` from a MAC address (in-place). - * - * @param mac The MAC address - */ - static inline void cleanMac(std::string& mac) - { - auto start = mac.begin(); - auto end = mac.end(); - auto new_end = std::remove_if(start, end, [](char c) { return c == 45 || c == 58; }); - mac.erase(new_end, end); - } + /* + * Remove `-` and `:` from a MAC address (in-place). + * + * @param mac The MAC address + */ + static inline void cleanMac(std::string& mac) + { + auto start = mac.begin(); + auto end = mac.end(); + auto new_end = std::remove_if(start, end, [](char c) { return c == 45 || c == 58; }); + mac.erase(new_end, end); + } }; -} // namespace ZeroTier +} // namespace ZeroTier #endif diff --git a/node/World.hpp b/node/World.hpp index 1c27b85e..c3b5d3d4 100644 --- a/node/World.hpp +++ b/node/World.hpp @@ -14,14 +14,14 @@ #ifndef ZT_WORLD_HPP #define ZT_WORLD_HPP -#include -#include - -#include "Constants.hpp" -#include "InetAddress.hpp" -#include "Identity.hpp" #include "Buffer.hpp" -#include "C25519.hpp" +#include "Constants.hpp" +#include "ECC.hpp" +#include "Identity.hpp" +#include "InetAddress.hpp" + +#include +#include /** * Maximum number of roots (sanity limit, okay to increase) @@ -41,7 +41,7 @@ /** * The (more than) maximum length of a serialized World */ -#define ZT_WORLD_MAX_SERIALIZED_LENGTH (((1024 + (32 * ZT_WORLD_MAX_STABLE_ENDPOINTS_PER_ROOT)) * ZT_WORLD_MAX_ROOTS) + ZT_C25519_PUBLIC_KEY_LEN + ZT_C25519_SIGNATURE_LEN + 128) +#define ZT_WORLD_MAX_SERIALIZED_LENGTH (((1024 + (32 * ZT_WORLD_MAX_STABLE_ENDPOINTS_PER_ROOT)) * ZT_WORLD_MAX_ROOTS) + ZT_ECC_PUBLIC_KEY_SET_LEN + ZT_ECC_SIGNATURE_LEN + 128) /** * World ID for Earth @@ -76,217 +76,249 @@ namespace ZeroTier { * world ID for Mars and nearby space is defined but not yet used, and a test * world ID is provided for testing purposes. */ -class World -{ -public: - /** - * World type -- do not change IDs - */ - enum Type - { - TYPE_NULL = 0, - TYPE_PLANET = 1, // Planets, of which there is currently one (Earth) - TYPE_MOON = 127 // Moons, which are user-created and many - }; +class World { + public: + /** + * World type -- do not change IDs + */ + enum Type { + TYPE_NULL = 0, + TYPE_PLANET = 1, // Planets, of which there is currently one (Earth) + TYPE_MOON = 127 // Moons, which are user-created and many + }; - /** - * Upstream server definition in world/moon - */ - struct Root - { - Identity identity; - std::vector stableEndpoints; + /** + * Upstream server definition in world/moon + */ + struct Root { + Identity identity; + std::vector stableEndpoints; - inline bool operator==(const Root &r) const { return ((identity == r.identity)&&(stableEndpoints == r.stableEndpoints)); } - inline bool operator!=(const Root &r) const { return (!(*this == r)); } - inline bool operator<(const Root &r) const { return (identity < r.identity); } // for sorting - }; + inline bool operator==(const Root& r) const + { + return ((identity == r.identity) && (stableEndpoints == r.stableEndpoints)); + } + inline bool operator!=(const Root& r) const + { + return (! (*this == r)); + } + inline bool operator<(const Root& r) const + { + return (identity < r.identity); + } // for sorting + }; - /** - * Construct an empty / null World - */ - World() : - _id(0), - _ts(0), - _type(TYPE_NULL) {} + /** + * Construct an empty / null World + */ + World() : _id(0), _ts(0), _type(TYPE_NULL) + { + } - /** - * @return Root servers for this world and their stable endpoints - */ - inline const std::vector &roots() const { return _roots; } + /** + * @return Root servers for this world and their stable endpoints + */ + inline const std::vector& roots() const + { + return _roots; + } - /** - * @return World type: planet or moon - */ - inline Type type() const { return _type; } + /** + * @return World type: planet or moon + */ + inline Type type() const + { + return _type; + } - /** - * @return World unique identifier - */ - inline uint64_t id() const { return _id; } + /** + * @return World unique identifier + */ + inline uint64_t id() const + { + return _id; + } - /** - * @return World definition timestamp - */ - inline uint64_t timestamp() const { return _ts; } + /** + * @return World definition timestamp + */ + inline uint64_t timestamp() const + { + return _ts; + } - /** - * @return C25519 signature - */ - inline const C25519::Signature &signature() const { return _signature; } + /** + * @return C25519 signature + */ + inline const ECC::Signature& signature() const + { + return _signature; + } - /** - * @return Public key that must sign next update - */ - inline const C25519::Public &updatesMustBeSignedBy() const { return _updatesMustBeSignedBy; } + /** + * @return Public key that must sign next update + */ + inline const ECC::Public& updatesMustBeSignedBy() const + { + return _updatesMustBeSignedBy; + } - /** - * Check whether a world update should replace this one - * - * @param update Candidate update - * @return True if update is newer than current, matches its ID and type, and is properly signed (or if current is NULL) - */ - inline bool shouldBeReplacedBy(const World &update) - { - if ((_id == 0)||(_type == TYPE_NULL)) { - return true; - } - if ((_id == update._id)&&(_ts < update._ts)&&(_type == update._type)) { - Buffer tmp; - update.serialize(tmp,true); - return C25519::verify(_updatesMustBeSignedBy,tmp.data(),tmp.size(),update._signature); - } - return false; - } + /** + * Check whether a world update should replace this one + * + * @param update Candidate update + * @return True if update is newer than current, matches its ID and type, and is properly signed (or if current is NULL) + */ + inline bool shouldBeReplacedBy(const World& update) + { + if ((_id == 0) || (_type == TYPE_NULL)) { + return true; + } + if ((_id == update._id) && (_ts < update._ts) && (_type == update._type)) { + Buffer tmp; + update.serialize(tmp, true); + return ECC::verify(_updatesMustBeSignedBy, tmp.data(), tmp.size(), update._signature); + } + return false; + } - /** - * @return True if this World is non-empty - */ - inline operator bool() const { return (_type != TYPE_NULL); } + /** + * @return True if this World is non-empty + */ + inline operator bool() const + { + return (_type != TYPE_NULL); + } - template - inline void serialize(Buffer &b,bool forSign = false) const - { - if (forSign) { - b.append((uint64_t)0x7f7f7f7f7f7f7f7fULL); - } + template inline void serialize(Buffer& b, bool forSign = false) const + { + if (forSign) { + b.append((uint64_t)0x7f7f7f7f7f7f7f7fULL); + } - b.append((uint8_t)_type); - b.append((uint64_t)_id); - b.append((uint64_t)_ts); - b.append(_updatesMustBeSignedBy.data,ZT_C25519_PUBLIC_KEY_LEN); - if (!forSign) { - b.append(_signature.data,ZT_C25519_SIGNATURE_LEN); - } - b.append((uint8_t)_roots.size()); - for(std::vector::const_iterator r(_roots.begin());r!=_roots.end();++r) { - r->identity.serialize(b); - b.append((uint8_t)r->stableEndpoints.size()); - for(std::vector::const_iterator ep(r->stableEndpoints.begin());ep!=r->stableEndpoints.end();++ep) { - ep->serialize(b); - } - } - if (_type == TYPE_MOON) { - b.append((uint16_t)0); // no attached dictionary (for future use) - } + b.append((uint8_t)_type); + b.append((uint64_t)_id); + b.append((uint64_t)_ts); + b.append(_updatesMustBeSignedBy.data, ZT_ECC_PUBLIC_KEY_SET_LEN); + if (! forSign) { + b.append(_signature.data, ZT_ECC_SIGNATURE_LEN); + } + b.append((uint8_t)_roots.size()); + for (std::vector::const_iterator r(_roots.begin()); r != _roots.end(); ++r) { + r->identity.serialize(b); + b.append((uint8_t)r->stableEndpoints.size()); + for (std::vector::const_iterator ep(r->stableEndpoints.begin()); ep != r->stableEndpoints.end(); ++ep) { + ep->serialize(b); + } + } + if (_type == TYPE_MOON) { + b.append((uint16_t)0); // no attached dictionary (for future use) + } - if (forSign) { - b.append((uint64_t)0xf7f7f7f7f7f7f7f7ULL); - } - } + if (forSign) { + b.append((uint64_t)0xf7f7f7f7f7f7f7f7ULL); + } + } - template - inline unsigned int deserialize(const Buffer &b,unsigned int startAt = 0) - { - unsigned int p = startAt; + template inline unsigned int deserialize(const Buffer& b, unsigned int startAt = 0) + { + unsigned int p = startAt; - _roots.clear(); + _roots.clear(); - switch((Type)b[p++]) { - case TYPE_NULL: // shouldn't ever really happen in serialized data but it's not invalid - _type = TYPE_NULL; - break; - case TYPE_PLANET: - _type = TYPE_PLANET; - break; - case TYPE_MOON: - _type = TYPE_MOON; - break; - default: - throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_INVALID_TYPE; - } + switch ((Type)b[p++]) { + case TYPE_NULL: // shouldn't ever really happen in serialized data but it's not invalid + _type = TYPE_NULL; + break; + case TYPE_PLANET: + _type = TYPE_PLANET; + break; + case TYPE_MOON: + _type = TYPE_MOON; + break; + default: + throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_INVALID_TYPE; + } - _id = b.template at(p); - p += 8; - _ts = b.template at(p); - p += 8; - memcpy(_updatesMustBeSignedBy.data,b.field(p,ZT_C25519_PUBLIC_KEY_LEN),ZT_C25519_PUBLIC_KEY_LEN); - p += ZT_C25519_PUBLIC_KEY_LEN; - memcpy(_signature.data,b.field(p,ZT_C25519_SIGNATURE_LEN),ZT_C25519_SIGNATURE_LEN); - p += ZT_C25519_SIGNATURE_LEN; - const unsigned int numRoots = (unsigned int)b[p++]; - if (numRoots > ZT_WORLD_MAX_ROOTS) { - throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_OVERFLOW; - } - for(unsigned int k=0;k ZT_WORLD_MAX_STABLE_ENDPOINTS_PER_ROOT) { - throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_OVERFLOW; - } - for(unsigned int kk=0;kk(p) + 2; - } + _id = b.template at(p); + p += 8; + _ts = b.template at(p); + p += 8; + memcpy(_updatesMustBeSignedBy.data, b.field(p, ZT_ECC_PUBLIC_KEY_SET_LEN), ZT_ECC_PUBLIC_KEY_SET_LEN); + p += ZT_ECC_PUBLIC_KEY_SET_LEN; + memcpy(_signature.data, b.field(p, ZT_ECC_SIGNATURE_LEN), ZT_ECC_SIGNATURE_LEN); + p += ZT_ECC_SIGNATURE_LEN; + const unsigned int numRoots = (unsigned int)b[p++]; + if (numRoots > ZT_WORLD_MAX_ROOTS) { + throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_OVERFLOW; + } + for (unsigned int k = 0; k < numRoots; ++k) { + _roots.push_back(Root()); + Root& r = _roots.back(); + p += r.identity.deserialize(b, p); + unsigned int numStableEndpoints = b[p++]; + if (numStableEndpoints > ZT_WORLD_MAX_STABLE_ENDPOINTS_PER_ROOT) { + throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_OVERFLOW; + } + for (unsigned int kk = 0; kk < numStableEndpoints; ++kk) { + r.stableEndpoints.push_back(InetAddress()); + p += r.stableEndpoints.back().deserialize(b, p); + } + } + if (_type == TYPE_MOON) { + p += b.template at(p) + 2; + } - return (p - startAt); - } + return (p - startAt); + } - inline bool operator==(const World &w) const { return ((_id == w._id)&&(_ts == w._ts)&&(memcmp(_updatesMustBeSignedBy.data,w._updatesMustBeSignedBy.data,ZT_C25519_PUBLIC_KEY_LEN) == 0)&&(memcmp(_signature.data,w._signature.data,ZT_C25519_SIGNATURE_LEN) == 0)&&(_roots == w._roots)&&(_type == w._type)); } - inline bool operator!=(const World &w) const { return (!(*this == w)); } + inline bool operator==(const World& w) const + { + return ( + (_id == w._id) && (_ts == w._ts) && (memcmp(_updatesMustBeSignedBy.data, w._updatesMustBeSignedBy.data, ZT_ECC_PUBLIC_KEY_SET_LEN) == 0) && (memcmp(_signature.data, w._signature.data, ZT_ECC_SIGNATURE_LEN) == 0) + && (_roots == w._roots) && (_type == w._type)); + } + inline bool operator!=(const World& w) const + { + return (! (*this == w)); + } - /** - * Create a World object signed with a key pair - * - * @param t World type - * @param id World ID - * @param ts World timestamp / revision - * @param sk Key that must be used to sign the next future update to this world - * @param roots Roots and their stable endpoints - * @param signWith Key to sign this World with (can have the same public as the next-update signing key, but doesn't have to) - * @return Signed World object - */ - static inline World make(World::Type t,uint64_t id,uint64_t ts,const C25519::Public &sk,const std::vector &roots,const C25519::Pair &signWith) - { - World w; - w._id = id; - w._ts = ts; - w._type = t; - w._updatesMustBeSignedBy = sk; - w._roots = roots; + /** + * Create a World object signed with a key pair + * + * @param t World type + * @param id World ID + * @param ts World timestamp / revision + * @param sk Key that must be used to sign the next future update to this world + * @param roots Roots and their stable endpoints + * @param signWith Key to sign this World with (can have the same public as the next-update signing key, but doesn't have to) + * @return Signed World object + */ + static inline World make(World::Type t, uint64_t id, uint64_t ts, const ECC::Public& sk, const std::vector& roots, const ECC::Pair& signWith) + { + World w; + w._id = id; + w._ts = ts; + w._type = t; + w._updatesMustBeSignedBy = sk; + w._roots = roots; - Buffer tmp; - w.serialize(tmp,true); - w._signature = C25519::sign(signWith,tmp.data(),tmp.size()); + Buffer tmp; + w.serialize(tmp, true); + w._signature = ECC::sign(signWith, tmp.data(), tmp.size()); - return w; - } + return w; + } -protected: - uint64_t _id; - uint64_t _ts; - Type _type; - C25519::Public _updatesMustBeSignedBy; - C25519::Signature _signature; - std::vector _roots; + protected: + uint64_t _id; + uint64_t _ts; + Type _type; + ECC::Public _updatesMustBeSignedBy; + ECC::Signature _signature; + std::vector _roots; }; -} // namespace ZeroTier +} // namespace ZeroTier #endif diff --git a/objects.mk b/objects.mk index 1d8a6c0a..3d1cd927 100644 --- a/objects.mk +++ b/objects.mk @@ -2,7 +2,7 @@ CORE_OBJS=\ node/AES.o \ node/AES_aesni.o \ node/AES_armcrypto.o \ - node/C25519.o \ + node/ECC.o \ node/Capability.o \ node/CertificateOfMembership.o \ node/CertificateOfOwnership.o \ diff --git a/one.cpp b/one.cpp index 2e4e6384..a99bf499 100644 --- a/one.cpp +++ b/one.cpp @@ -13,6 +13,7 @@ #ifndef _GNU_SOURCE #define _GNU_SOURCE +#include "node/ECC.hpp" #endif #include @@ -1552,9 +1553,9 @@ static int idtool(int argc,char **argv) fprintf(stderr,"%s is not readable" ZT_EOL_S,argv[3]); return 1; } - C25519::Signature signature = id.sign(inf.data(),(unsigned int)inf.length()); + ECC::Signature signature = id.sign(inf.data(),(unsigned int)inf.length()); char hexbuf[1024]; - printf("%s",Utils::hex(signature.data,ZT_C25519_SIGNATURE_LEN,hexbuf)); + printf("%s",Utils::hex(signature.data,ZT_ECC_SIGNATURE_LEN,hexbuf)); } else if (!strcmp(argv[1],"verify")) { if (argc < 5) { idtoolPrintHelp(stdout,argv[0]); @@ -1602,14 +1603,14 @@ static int idtool(int argc,char **argv) return 1; } - C25519::Pair kp(C25519::generate()); + ECC::Pair kp(ECC::generate()); char idtmp[4096]; nlohmann::json mj; mj["objtype"] = "world"; mj["worldType"] = "moon"; - mj["updatesMustBeSignedBy"] = mj["signingKey"] = Utils::hex(kp.pub.data,ZT_C25519_PUBLIC_KEY_LEN,idtmp); - mj["signingKey_SECRET"] = Utils::hex(kp.priv.data,ZT_C25519_PRIVATE_KEY_LEN,idtmp); + mj["updatesMustBeSignedBy"] = mj["signingKey"] = Utils::hex(kp.pub.data,ZT_ECC_PUBLIC_KEY_SET_LEN,idtmp); + mj["signingKey_SECRET"] = Utils::hex(kp.priv.data,ZT_ECC_PRIVATE_KEY_SET_LEN,idtmp); mj["id"] = id.address().toString(idtmp); nlohmann::json seedj; seedj["identity"] = id.toString(false,idtmp); @@ -1646,11 +1647,11 @@ static int idtool(int argc,char **argv) return 1; } - C25519::Pair signingKey; - C25519::Public updatesMustBeSignedBy; - Utils::unhex(OSUtils::jsonString(mj["signingKey"],"").c_str(),signingKey.pub.data,ZT_C25519_PUBLIC_KEY_LEN); - Utils::unhex(OSUtils::jsonString(mj["signingKey_SECRET"],"").c_str(),signingKey.priv.data,ZT_C25519_PRIVATE_KEY_LEN); - Utils::unhex(OSUtils::jsonString(mj["updatesMustBeSignedBy"],"").c_str(),updatesMustBeSignedBy.data,ZT_C25519_PUBLIC_KEY_LEN); + ECC::Pair signingKey; + ECC::Public updatesMustBeSignedBy; + Utils::unhex(OSUtils::jsonString(mj["signingKey"],"").c_str(),signingKey.pub.data,ZT_ECC_PUBLIC_KEY_SET_LEN); + Utils::unhex(OSUtils::jsonString(mj["signingKey_SECRET"],"").c_str(),signingKey.priv.data,ZT_ECC_PRIVATE_KEY_SET_LEN); + Utils::unhex(OSUtils::jsonString(mj["updatesMustBeSignedBy"],"").c_str(),updatesMustBeSignedBy.data,ZT_ECC_PUBLIC_KEY_SET_LEN); std::vector roots; nlohmann::json &rootsj = mj["roots"]; diff --git a/osdep/Arp.cpp b/osdep/Arp.cpp index 036d7df6..16192bf7 100644 --- a/osdep/Arp.cpp +++ b/osdep/Arp.cpp @@ -11,111 +11,116 @@ */ /****/ -#include -#include -#include - #include "Arp.hpp" + #include "OSUtils.hpp" +#include +#include +#include + namespace ZeroTier { -static const uint8_t ARP_REQUEST_HEADER[8] = { 0x00,0x01,0x08,0x00,0x06,0x04,0x00,0x01 }; -static const uint8_t ARP_RESPONSE_HEADER[8] = { 0x00,0x01,0x08,0x00,0x06,0x04,0x00,0x02 }; +static const uint8_t ARP_REQUEST_HEADER[8] = { 0x00, 0x01, 0x08, 0x00, 0x06, 0x04, 0x00, 0x01 }; +static const uint8_t ARP_RESPONSE_HEADER[8] = { 0x00, 0x01, 0x08, 0x00, 0x06, 0x04, 0x00, 0x02 }; -Arp::Arp() : - _cache(256), - _lastCleaned(OSUtils::now()) +Arp::Arp() : _cache(256), _lastCleaned(OSUtils::now()) { } -void Arp::addLocal(uint32_t ip,const MAC &mac) +void Arp::addLocal(uint32_t ip, const MAC& mac) { - _ArpEntry &e = _cache[ip]; - e.lastQuerySent = 0; // local IP - e.lastResponseReceived = 0; // local IP - e.mac = mac; - e.local = true; + _ArpEntry& e = _cache[ip]; + e.lastQuerySent = 0; // local IP + e.lastResponseReceived = 0; // local IP + e.mac = mac; + e.local = true; } void Arp::remove(uint32_t ip) { - _cache.erase(ip); + _cache.erase(ip); } -uint32_t Arp::processIncomingArp(const void *arp,unsigned int len,void *response,unsigned int &responseLen,MAC &responseDest) +uint32_t Arp::processIncomingArp(const void* arp, unsigned int len, void* response, unsigned int& responseLen, MAC& responseDest) { - const uint64_t now = OSUtils::now(); - uint32_t ip = 0; + const uint64_t now = OSUtils::now(); + uint32_t ip = 0; - responseLen = 0; - responseDest.zero(); + responseLen = 0; + responseDest.zero(); - if (len >= 28) { - if (!memcmp(arp,ARP_REQUEST_HEADER,8)) { - // Respond to ARP requests for locally-known IPs - _ArpEntry *targetEntry = _cache.get(reinterpret_cast(arp)[6]); - if ((targetEntry)&&(targetEntry->local)) { - memcpy(response,ARP_RESPONSE_HEADER,8); - targetEntry->mac.copyTo(reinterpret_cast(response) + 8,6); - memcpy(reinterpret_cast(response) + 14,reinterpret_cast(arp) + 24,4); - memcpy(reinterpret_cast(response) + 18,reinterpret_cast(arp) + 8,10); - responseLen = 28; - responseDest.setTo(reinterpret_cast(arp) + 8,6); - } - } else if (!memcmp(arp,ARP_RESPONSE_HEADER,8)) { - // Learn cache entries for remote IPs from relevant ARP replies - uint32_t responseIp = 0; - memcpy(&responseIp,reinterpret_cast(arp) + 14,4); - _ArpEntry *queryEntry = _cache.get(responseIp); - if ((queryEntry)&&(!queryEntry->local)&&((now - queryEntry->lastQuerySent) <= ZT_ARP_QUERY_MAX_TTL)) { - queryEntry->lastResponseReceived = now; - queryEntry->mac.setTo(reinterpret_cast(arp) + 8,6); - ip = responseIp; - } - } - } + if (len >= 28) { + if (! memcmp(arp, ARP_REQUEST_HEADER, 8)) { + // Respond to ARP requests for locally-known IPs + _ArpEntry* targetEntry = _cache.get(reinterpret_cast(arp)[6]); + if ((targetEntry) && (targetEntry->local)) { + memcpy(response, ARP_RESPONSE_HEADER, 8); + targetEntry->mac.copyTo(reinterpret_cast(response) + 8, 6); + memcpy(reinterpret_cast(response) + 14, reinterpret_cast(arp) + 24, 4); + memcpy(reinterpret_cast(response) + 18, reinterpret_cast(arp) + 8, 10); + responseLen = 28; + responseDest.setTo(reinterpret_cast(arp) + 8, 6); + } + } + else if (! memcmp(arp, ARP_RESPONSE_HEADER, 8)) { + // Learn cache entries for remote IPs from relevant ARP replies + uint32_t responseIp = 0; + memcpy(&responseIp, reinterpret_cast(arp) + 14, 4); + _ArpEntry* queryEntry = _cache.get(responseIp); + if ((queryEntry) && (! queryEntry->local) && ((now - queryEntry->lastQuerySent) <= ZT_ARP_QUERY_MAX_TTL)) { + queryEntry->lastResponseReceived = now; + queryEntry->mac.setTo(reinterpret_cast(arp) + 8, 6); + ip = responseIp; + } + } + } - if ((now - _lastCleaned) >= ZT_ARP_EXPIRE) { - _lastCleaned = now; - Hashtable< uint32_t,_ArpEntry >::Iterator i(_cache); - uint32_t *k = (uint32_t *)0; - _ArpEntry *v = (_ArpEntry *)0; - while (i.next(k,v)) { - if ((!v->local)&&((now - v->lastResponseReceived) >= ZT_ARP_EXPIRE)) - _cache.erase(*k); - } - } + if ((now - _lastCleaned) >= ZT_ARP_EXPIRE) { + _lastCleaned = now; + Hashtable::Iterator i(_cache); + uint32_t* k = (uint32_t*)0; + _ArpEntry* v = (_ArpEntry*)0; + while (i.next(k, v)) { + if ((! v->local) && ((now - v->lastResponseReceived) >= ZT_ARP_EXPIRE)) + _cache.erase(*k); + } + } - return ip; + return ip; } -MAC Arp::query(const MAC &localMac,uint32_t localIp,uint32_t targetIp,void *query,unsigned int &queryLen,MAC &queryDest) +MAC Arp::query(const MAC& localMac, uint32_t localIp, uint32_t targetIp, void* query, unsigned int& queryLen, MAC& queryDest) { - const uint64_t now = OSUtils::now(); + const uint64_t now = OSUtils::now(); - _ArpEntry &e = _cache[targetIp]; + _ArpEntry& e = _cache[targetIp]; - if ( ((e.mac)&&((now - e.lastResponseReceived) >= (ZT_ARP_EXPIRE / 3))) || - ((!e.mac)&&((now - e.lastQuerySent) >= ZT_ARP_QUERY_INTERVAL)) ) { - e.lastQuerySent = now; + if (((e.mac) && ((now - e.lastResponseReceived) >= (ZT_ARP_EXPIRE / 3))) || ((! e.mac) && ((now - e.lastQuerySent) >= ZT_ARP_QUERY_INTERVAL))) { + e.lastQuerySent = now; - uint8_t *q = reinterpret_cast(query); - memcpy(q,ARP_REQUEST_HEADER,8); q += 8; // ARP request header information, always the same - localMac.copyTo(q,6); q += 6; // sending host MAC address - memcpy(q,&localIp,4); q += 4; // sending host IP (IP already in big-endian byte order) - memset(q,0,6); q += 6; // sending zeros for target MAC address as thats what we want to find - memcpy(q,&targetIp,4); // target IP address for resolution (IP already in big-endian byte order) - queryLen = 28; - if (e.mac) - queryDest = e.mac; // confirmation query, send directly to address holder - else queryDest = (uint64_t)0xffffffffffffULL; // broadcast query - } else { - queryLen = 0; - queryDest.zero(); - } + uint8_t* q = reinterpret_cast(query); + memcpy(q, ARP_REQUEST_HEADER, 8); + q += 8; // ARP request header information, always the same + localMac.copyTo(q, 6); + q += 6; // sending host MAC address + memcpy(q, &localIp, 4); + q += 4; // sending host IP (IP already in big-endian byte order) + memset(q, 0, 6); + q += 6; // sending zeros for target MAC address as thats what we want to find + memcpy(q, &targetIp, 4); // target IP address for resolution (IP already in big-endian byte order) + queryLen = 28; + if (e.mac) + queryDest = e.mac; // confirmation query, send directly to address holder + else + queryDest = (uint64_t)0xffffffffffffULL; // broadcast query + } + else { + queryLen = 0; + queryDest.zero(); + } - return e.mac; + return e.mac; } -} // namespace ZeroTier +} // namespace ZeroTier diff --git a/osdep/Arp.hpp b/osdep/Arp.hpp index 9453997f..3785479e 100644 --- a/osdep/Arp.hpp +++ b/osdep/Arp.hpp @@ -14,14 +14,13 @@ #ifndef ZT_ARP_HPP #define ZT_ARP_HPP -#include - -#include - #include "../node/Constants.hpp" #include "../node/Hashtable.hpp" #include "../node/MAC.hpp" +#include +#include + /** * Maximum possible ARP length * @@ -67,77 +66,77 @@ namespace ZeroTier { * This class is not thread-safe and must be guarded if used in multi-threaded * code. */ -class Arp -{ -public: - Arp(); +class Arp { + public: + Arp(); - /** - * Set a local IP entry that we should respond to ARPs for - * - * @param mac Our local MAC address - * @param ip IP in big-endian byte order (sin_addr.s_addr) - */ - void addLocal(uint32_t ip,const MAC &mac); + /** + * Set a local IP entry that we should respond to ARPs for + * + * @param mac Our local MAC address + * @param ip IP in big-endian byte order (sin_addr.s_addr) + */ + void addLocal(uint32_t ip, const MAC& mac); - /** - * Delete a local IP entry or a cached ARP entry - * - * @param ip IP in big-endian byte order (sin_addr.s_addr) - */ - void remove(uint32_t ip); + /** + * Delete a local IP entry or a cached ARP entry + * + * @param ip IP in big-endian byte order (sin_addr.s_addr) + */ + void remove(uint32_t ip); - /** - * Process ARP packets - * - * For ARP queries, a response is generated and responseLen is set to its - * frame payload length in bytes. - * - * For ARP responses, the cache is populated and the IP address entry that - * was learned is returned. - * - * @param arp ARP frame data - * @param len Length of ARP frame (usually 28) - * @param response Response buffer -- MUST be a minimum of ZT_ARP_BUF_LENGTH in size - * @param responseLen Response length, or set to 0 if no response - * @param responseDest Destination of response, or set to null if no response - * @return IP address learned or 0 if no new IPs in cache - */ - uint32_t processIncomingArp(const void *arp,unsigned int len,void *response,unsigned int &responseLen,MAC &responseDest); + /** + * Process ARP packets + * + * For ARP queries, a response is generated and responseLen is set to its + * frame payload length in bytes. + * + * For ARP responses, the cache is populated and the IP address entry that + * was learned is returned. + * + * @param arp ARP frame data + * @param len Length of ARP frame (usually 28) + * @param response Response buffer -- MUST be a minimum of ZT_ARP_BUF_LENGTH in size + * @param responseLen Response length, or set to 0 if no response + * @param responseDest Destination of response, or set to null if no response + * @return IP address learned or 0 if no new IPs in cache + */ + uint32_t processIncomingArp(const void* arp, unsigned int len, void* response, unsigned int& responseLen, MAC& responseDest); - /** - * Get the MAC corresponding to an IP, generating a query if needed - * - * This returns a MAC for a remote IP. The local MAC is returned for local - * IPs as well. It may also generate a query if the IP is not known or the - * entry needs to be refreshed. In this case queryLen will be set to a - * non-zero value, so this should always be checked on return even if the - * MAC returned is non-null. - * - * @param localMac Local MAC address of host interface + /** + * Get the MAC corresponding to an IP, generating a query if needed + * + * This returns a MAC for a remote IP. The local MAC is returned for local + * IPs as well. It may also generate a query if the IP is not known or the + * entry needs to be refreshed. In this case queryLen will be set to a + * non-zero value, so this should always be checked on return even if the + * MAC returned is non-null. + * + * @param localMac Local MAC address of host interface * @param localIp Local IP address of host interface - * @param targetIp IP to look up - * @param query Buffer for generated query -- MUST be a minimum of ZT_ARP_BUF_LENGTH in size - * @param queryLen Length of generated query, or set to 0 if no query generated - * @param queryDest Destination of query, or set to null if no query generated - * @return MAC or 0 if no cached entry for this IP - */ - MAC query(const MAC &localMac,uint32_t localIp,uint32_t targetIp,void *query,unsigned int &queryLen,MAC &queryDest); + * @param targetIp IP to look up + * @param query Buffer for generated query -- MUST be a minimum of ZT_ARP_BUF_LENGTH in size + * @param queryLen Length of generated query, or set to 0 if no query generated + * @param queryDest Destination of query, or set to null if no query generated + * @return MAC or 0 if no cached entry for this IP + */ + MAC query(const MAC& localMac, uint32_t localIp, uint32_t targetIp, void* query, unsigned int& queryLen, MAC& queryDest); -private: - struct _ArpEntry - { - _ArpEntry() : lastQuerySent(0),lastResponseReceived(0),mac(),local(false) {} - uint64_t lastQuerySent; // Time last query was sent or 0 for local IP - uint64_t lastResponseReceived; // Time of last ARP response or 0 for local IP - MAC mac; // MAC address of device responsible for IP or null if not known yet - bool local; // True if this is a local ARP entry - }; + private: + struct _ArpEntry { + _ArpEntry() : lastQuerySent(0), lastResponseReceived(0), mac(), local(false) + { + } + uint64_t lastQuerySent; // Time last query was sent or 0 for local IP + uint64_t lastResponseReceived; // Time of last ARP response or 0 for local IP + MAC mac; // MAC address of device responsible for IP or null if not known yet + bool local; // True if this is a local ARP entry + }; - Hashtable< uint32_t,_ArpEntry > _cache; - uint64_t _lastCleaned; + Hashtable _cache; + uint64_t _lastCleaned; }; -} // namespace ZeroTier +} // namespace ZeroTier #endif diff --git a/osdep/BSDEthernetTap.cpp b/osdep/BSDEthernetTap.cpp index 1a240c1a..a5bc9794 100644 --- a/osdep/BSDEthernetTap.cpp +++ b/osdep/BSDEthernetTap.cpp @@ -11,492 +11,500 @@ */ /****/ -#include -#include -#include -#include -#include +#include "BSDEthernetTap.hpp" -#include -#include +#include "../node/Constants.hpp" +#include "../node/Mutex.hpp" +#include "../node/Utils.hpp" +#include "OSUtils.hpp" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include #include -#include +#include +#include #include +#include +#include #include #include #include #include +#include #include - #include -#include -#include #include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include -#include "../node/Constants.hpp" -#include "../node/Utils.hpp" -#include "../node/Mutex.hpp" -#include "OSUtils.hpp" -#include "BSDEthernetTap.hpp" - #define ZT_BASE32_CHARS "0123456789abcdefghijklmnopqrstuv" #define ZT_TAP_BUF_SIZE (1024 * 16) // ff:ff:ff:ff:ff:ff with no ADI -static const ZeroTier::MulticastGroup _blindWildcardMulticastGroup(ZeroTier::MAC(0xff),0); +static const ZeroTier::MulticastGroup _blindWildcardMulticastGroup(ZeroTier::MAC(0xff), 0); namespace ZeroTier { BSDEthernetTap::BSDEthernetTap( - const char *homePath, - unsigned int concurrency, - bool pinning, - const MAC &mac, - unsigned int mtu, - unsigned int metric, - uint64_t nwid, - const char *friendlyName, - void (*handler)(void *,void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int), - void *arg) : - _handler(handler), - _concurrency(concurrency), - _pinning(pinning), - _arg(arg), - _nwid(nwid), - _mtu(mtu), - _metric(metric), - _fd(0), - _enabled(true), - _lastIfAddrsUpdate(0) + const char* homePath, + unsigned int concurrency, + bool pinning, + const MAC& mac, + unsigned int mtu, + unsigned int metric, + uint64_t nwid, + const char* friendlyName, + void (*handler)(void*, void*, uint64_t, const MAC&, const MAC&, unsigned int, unsigned int, const void*, unsigned int), + void* arg) + : _handler(handler) + , _concurrency(concurrency) + , _pinning(pinning) + , _arg(arg) + , _nwid(nwid) + , _mtu(mtu) + , _metric(metric) + , _fd(0) + , _enabled(true) + , _lastIfAddrsUpdate(0) { - static Mutex globalTapCreateLock; - char devpath[64],ethaddr[64],mtustr[32],metstr[32],tmpdevname[32]; + static Mutex globalTapCreateLock; + char devpath[64], ethaddr[64], mtustr[32], metstr[32], tmpdevname[32]; - Mutex::Lock _gl(globalTapCreateLock); + Mutex::Lock _gl(globalTapCreateLock); #ifdef __FreeBSD__ - /* FreeBSD allows long interface names and interface renaming */ + /* FreeBSD allows long interface names and interface renaming */ - _dev = "zt"; - _dev.push_back(ZT_BASE32_CHARS[(unsigned long)((nwid >> 60) & 0x1f)]); - _dev.push_back(ZT_BASE32_CHARS[(unsigned long)((nwid >> 55) & 0x1f)]); - _dev.push_back(ZT_BASE32_CHARS[(unsigned long)((nwid >> 50) & 0x1f)]); - _dev.push_back(ZT_BASE32_CHARS[(unsigned long)((nwid >> 45) & 0x1f)]); - _dev.push_back(ZT_BASE32_CHARS[(unsigned long)((nwid >> 40) & 0x1f)]); - _dev.push_back(ZT_BASE32_CHARS[(unsigned long)((nwid >> 35) & 0x1f)]); - _dev.push_back(ZT_BASE32_CHARS[(unsigned long)((nwid >> 30) & 0x1f)]); - _dev.push_back(ZT_BASE32_CHARS[(unsigned long)((nwid >> 25) & 0x1f)]); - _dev.push_back(ZT_BASE32_CHARS[(unsigned long)((nwid >> 20) & 0x1f)]); - _dev.push_back(ZT_BASE32_CHARS[(unsigned long)((nwid >> 15) & 0x1f)]); - _dev.push_back(ZT_BASE32_CHARS[(unsigned long)((nwid >> 10) & 0x1f)]); - _dev.push_back(ZT_BASE32_CHARS[(unsigned long)((nwid >> 5) & 0x1f)]); - _dev.push_back(ZT_BASE32_CHARS[(unsigned long)(nwid & 0x1f)]); + _dev = "zt"; + _dev.push_back(ZT_BASE32_CHARS[(unsigned long)((nwid >> 60) & 0x1f)]); + _dev.push_back(ZT_BASE32_CHARS[(unsigned long)((nwid >> 55) & 0x1f)]); + _dev.push_back(ZT_BASE32_CHARS[(unsigned long)((nwid >> 50) & 0x1f)]); + _dev.push_back(ZT_BASE32_CHARS[(unsigned long)((nwid >> 45) & 0x1f)]); + _dev.push_back(ZT_BASE32_CHARS[(unsigned long)((nwid >> 40) & 0x1f)]); + _dev.push_back(ZT_BASE32_CHARS[(unsigned long)((nwid >> 35) & 0x1f)]); + _dev.push_back(ZT_BASE32_CHARS[(unsigned long)((nwid >> 30) & 0x1f)]); + _dev.push_back(ZT_BASE32_CHARS[(unsigned long)((nwid >> 25) & 0x1f)]); + _dev.push_back(ZT_BASE32_CHARS[(unsigned long)((nwid >> 20) & 0x1f)]); + _dev.push_back(ZT_BASE32_CHARS[(unsigned long)((nwid >> 15) & 0x1f)]); + _dev.push_back(ZT_BASE32_CHARS[(unsigned long)((nwid >> 10) & 0x1f)]); + _dev.push_back(ZT_BASE32_CHARS[(unsigned long)((nwid >> 5) & 0x1f)]); + _dev.push_back(ZT_BASE32_CHARS[(unsigned long)(nwid & 0x1f)]); - std::vector devFiles(OSUtils::listDirectory("/dev")); - for(int i=9993;i<(9993+128);++i) { - OSUtils::ztsnprintf(tmpdevname,sizeof(tmpdevname),"tap%d",i); - OSUtils::ztsnprintf(devpath,sizeof(devpath),"/dev/%s",tmpdevname); - if (std::find(devFiles.begin(),devFiles.end(),std::string(tmpdevname)) == devFiles.end()) { - long cpid = (long)vfork(); - if (cpid == 0) { + std::vector devFiles(OSUtils::listDirectory("/dev")); + for (int i = 9993; i < (9993 + 128); ++i) { + OSUtils::ztsnprintf(tmpdevname, sizeof(tmpdevname), "tap%d", i); + OSUtils::ztsnprintf(devpath, sizeof(devpath), "/dev/%s", tmpdevname); + if (std::find(devFiles.begin(), devFiles.end(), std::string(tmpdevname)) == devFiles.end()) { + long cpid = (long)vfork(); + if (cpid == 0) { #ifdef ZT_TRACE - fprintf(stderr, "DEBUG: ifconfig %s create" ZT_EOL_S, tmpdevname); + fprintf(stderr, "DEBUG: ifconfig %s create" ZT_EOL_S, tmpdevname); #endif - ::execl("/sbin/ifconfig","/sbin/ifconfig",tmpdevname,"create",(const char *)0); - ::_exit(-1); - } else if (cpid > 0) { - int exitcode = -1; - ::waitpid(cpid,&exitcode,0); - } else throw std::runtime_error("fork() failed"); + ::execl("/sbin/ifconfig", "/sbin/ifconfig", tmpdevname, "create", (const char*)0); + ::_exit(-1); + } + else if (cpid > 0) { + int exitcode = -1; + ::waitpid(cpid, &exitcode, 0); + } + else + throw std::runtime_error("fork() failed"); - struct stat stattmp; - if (!stat(devpath,&stattmp)) { - cpid = (long)vfork(); - if (cpid == 0) { + struct stat stattmp; + if (! stat(devpath, &stattmp)) { + cpid = (long)vfork(); + if (cpid == 0) { #ifdef ZT_TRACE - fprintf(stderr, "DEBUG: ifconfig %s name %s" ZT_EOL_S, tmpdevname, _dev.c_str()); + fprintf(stderr, "DEBUG: ifconfig %s name %s" ZT_EOL_S, tmpdevname, _dev.c_str()); #endif - ::execl("/sbin/ifconfig","/sbin/ifconfig",tmpdevname,"name",_dev.c_str(),(const char *)0); - ::_exit(-1); - } else if (cpid > 0) { - int exitcode = -1; - ::waitpid(cpid,&exitcode,0); - if (exitcode) - throw std::runtime_error("ifconfig rename operation failed"); - } else throw std::runtime_error("fork() failed"); + ::execl("/sbin/ifconfig", "/sbin/ifconfig", tmpdevname, "name", _dev.c_str(), (const char*)0); + ::_exit(-1); + } + else if (cpid > 0) { + int exitcode = -1; + ::waitpid(cpid, &exitcode, 0); + if (exitcode) + throw std::runtime_error("ifconfig rename operation failed"); + } + else + throw std::runtime_error("fork() failed"); - _fd = ::open(devpath,O_RDWR); - if (_fd > 0) - break; - else throw std::runtime_error("unable to open created tap device"); - } else { - throw std::runtime_error("cannot find /dev node for newly created tap device"); - } - } - } + _fd = ::open(devpath, O_RDWR); + if (_fd > 0) + break; + else + throw std::runtime_error("unable to open created tap device"); + } + else { + throw std::runtime_error("cannot find /dev node for newly created tap device"); + } + } + } #else - /* Other BSDs like OpenBSD only have a limited number of tap devices that cannot be renamed */ + /* Other BSDs like OpenBSD only have a limited number of tap devices that cannot be renamed */ - for(int i=0;i<64;++i) { - OSUtils::ztsnprintf(tmpdevname,sizeof(tmpdevname),"tap%d",i); - OSUtils::ztsnprintf(devpath,sizeof(devpath),"/dev/%s",tmpdevname); - _fd = ::open(devpath,O_RDWR); - if (_fd > 0) { - _dev = tmpdevname; - break; - } - } + for (int i = 0; i < 64; ++i) { + OSUtils::ztsnprintf(tmpdevname, sizeof(tmpdevname), "tap%d", i); + OSUtils::ztsnprintf(devpath, sizeof(devpath), "/dev/%s", tmpdevname); + _fd = ::open(devpath, O_RDWR); + if (_fd > 0) { + _dev = tmpdevname; + break; + } + } #endif - if (_fd <= 0) - throw std::runtime_error("unable to open TAP device or no more devices available"); + if (_fd <= 0) + throw std::runtime_error("unable to open TAP device or no more devices available"); - if (fcntl(_fd,F_SETFL,fcntl(_fd,F_GETFL) & ~O_NONBLOCK) == -1) { - ::close(_fd); - throw std::runtime_error("unable to set flags on file descriptor for TAP device"); - } + if (fcntl(_fd, F_SETFL, fcntl(_fd, F_GETFL) & ~O_NONBLOCK) == -1) { + ::close(_fd); + throw std::runtime_error("unable to set flags on file descriptor for TAP device"); + } - // Configure MAC address and MTU, bring interface up - OSUtils::ztsnprintf(ethaddr,sizeof(ethaddr),"%.2x:%.2x:%.2x:%.2x:%.2x:%.2x",(int)mac[0],(int)mac[1],(int)mac[2],(int)mac[3],(int)mac[4],(int)mac[5]); - OSUtils::ztsnprintf(mtustr,sizeof(mtustr),"%u",_mtu); - OSUtils::ztsnprintf(metstr,sizeof(metstr),"%u",_metric); - long cpid = (long)vfork(); - if (cpid == 0) { + // Configure MAC address and MTU, bring interface up + OSUtils::ztsnprintf(ethaddr, sizeof(ethaddr), "%.2x:%.2x:%.2x:%.2x:%.2x:%.2x", (int)mac[0], (int)mac[1], (int)mac[2], (int)mac[3], (int)mac[4], (int)mac[5]); + OSUtils::ztsnprintf(mtustr, sizeof(mtustr), "%u", _mtu); + OSUtils::ztsnprintf(metstr, sizeof(metstr), "%u", _metric); + long cpid = (long)vfork(); + if (cpid == 0) { #ifdef ZT_TRACE - fprintf(stderr, "DEBUG: ifconfig %s lladdr %s mtu %s metric %s up" ZT_EOL_S, _dev.c_str(), ethaddr, mtustr, metstr); + fprintf(stderr, "DEBUG: ifconfig %s lladdr %s mtu %s metric %s up" ZT_EOL_S, _dev.c_str(), ethaddr, mtustr, metstr); #endif - ::execl("/sbin/ifconfig","/sbin/ifconfig",_dev.c_str(),"lladdr",ethaddr,"mtu",mtustr,"metric",metstr,"up",(const char *)0); - ::_exit(-1); - } else if (cpid > 0) { - int exitcode = -1; - ::waitpid(cpid,&exitcode,0); - if (exitcode) { - ::close(_fd); - throw std::runtime_error("ifconfig failure setting link-layer address and activating tap interface"); - } - } + ::execl("/sbin/ifconfig", "/sbin/ifconfig", _dev.c_str(), "lladdr", ethaddr, "mtu", mtustr, "metric", metstr, "up", (const char*)0); + ::_exit(-1); + } + else if (cpid > 0) { + int exitcode = -1; + ::waitpid(cpid, &exitcode, 0); + if (exitcode) { + ::close(_fd); + throw std::runtime_error("ifconfig failure setting link-layer address and activating tap interface"); + } + } - // Set close-on-exec so that devices cannot persist if we fork/exec for update - fcntl(_fd,F_SETFD,fcntl(_fd,F_GETFD) | FD_CLOEXEC); + // Set close-on-exec so that devices cannot persist if we fork/exec for update + fcntl(_fd, F_SETFD, fcntl(_fd, F_GETFD) | FD_CLOEXEC); - ::pipe(_shutdownSignalPipe); + ::pipe(_shutdownSignalPipe); - _thread = Thread::start(this); + _thread = Thread::start(this); } BSDEthernetTap::~BSDEthernetTap() { - ::write(_shutdownSignalPipe[1],"\0",1); // causes thread to exit - ::close(_fd); - ::close(_shutdownSignalPipe[0]); - ::close(_shutdownSignalPipe[1]); - long cpid = (long)vfork(); - if (cpid == 0) { + ::write(_shutdownSignalPipe[1], "\0", 1); // causes thread to exit + ::close(_fd); + ::close(_shutdownSignalPipe[0]); + ::close(_shutdownSignalPipe[1]); + long cpid = (long)vfork(); + if (cpid == 0) { #ifdef ZT_TRACE - fprintf(stderr, "DEBUG: ifconfig %s destroy" ZT_EOL_S, _dev.c_str()); + fprintf(stderr, "DEBUG: ifconfig %s destroy" ZT_EOL_S, _dev.c_str()); #endif - ::execl("/sbin/ifconfig","/sbin/ifconfig",_dev.c_str(),"destroy",(const char *)0); - ::_exit(-1); - } else if (cpid > 0) { - int exitcode = -1; - ::waitpid(cpid,&exitcode,0); - } - Thread::join(_thread); - for (std::thread &t : _rxThreads) { - t.join(); - } + ::execl("/sbin/ifconfig", "/sbin/ifconfig", _dev.c_str(), "destroy", (const char*)0); + ::_exit(-1); + } + else if (cpid > 0) { + int exitcode = -1; + ::waitpid(cpid, &exitcode, 0); + } + Thread::join(_thread); + for (std::thread& t : _rxThreads) { + t.join(); + } } void BSDEthernetTap::setEnabled(bool en) { - _enabled = en; + _enabled = en; } bool BSDEthernetTap::enabled() const { - return _enabled; + return _enabled; } -static bool ___removeIp(const std::string &_dev,const InetAddress &ip) +static bool ___removeIp(const std::string& _dev, const InetAddress& ip) { - long cpid = (long)vfork(); - if (cpid == 0) { - char ipbuf[64]; + long cpid = (long)vfork(); + if (cpid == 0) { + char ipbuf[64]; #ifdef ZT_TRACE - fprintf(stderr, "DEBUG: ifconfig %s inet %s -alias" ZT_EOL_S, _dev.c_str(), ip.toIpString(ipbuf)); + fprintf(stderr, "DEBUG: ifconfig %s inet %s -alias" ZT_EOL_S, _dev.c_str(), ip.toIpString(ipbuf)); #endif - execl("/sbin/ifconfig","/sbin/ifconfig",_dev.c_str(),"inet",ip.toIpString(ipbuf),"-alias",(const char *)0); - _exit(-1); - } else if (cpid > 0) { - int exitcode = -1; - waitpid(cpid,&exitcode,0); - return (exitcode == 0); - } - return false; // never reached, make compiler shut up about return value + execl("/sbin/ifconfig", "/sbin/ifconfig", _dev.c_str(), "inet", ip.toIpString(ipbuf), "-alias", (const char*)0); + _exit(-1); + } + else if (cpid > 0) { + int exitcode = -1; + waitpid(cpid, &exitcode, 0); + return (exitcode == 0); + } + return false; // never reached, make compiler shut up about return value } -bool BSDEthernetTap::addIp(const InetAddress &ip) +bool BSDEthernetTap::addIp(const InetAddress& ip) { - if (!ip) - return false; + if (! ip) + return false; - std::vector allIps(ips()); - if (std::find(allIps.begin(),allIps.end(),ip) != allIps.end()) - return true; // IP/netmask already assigned + std::vector allIps(ips()); + if (std::find(allIps.begin(), allIps.end(), ip) != allIps.end()) + return true; // IP/netmask already assigned - // Remove and reconfigure if address is the same but netmask is different - for(std::vector::iterator i(allIps.begin());i!=allIps.end();++i) { - if ((i->ipsEqual(ip))&&(i->netmaskBits() != ip.netmaskBits())) { - if (___removeIp(_dev,*i)) - break; - } - } + // Remove and reconfigure if address is the same but netmask is different + for (std::vector::iterator i(allIps.begin()); i != allIps.end(); ++i) { + if ((i->ipsEqual(ip)) && (i->netmaskBits() != ip.netmaskBits())) { + if (___removeIp(_dev, *i)) + break; + } + } - long cpid = (long)vfork(); - if (cpid == 0) { - char tmp[128]; + long cpid = (long)vfork(); + if (cpid == 0) { + char tmp[128]; #ifdef ZT_TRACE - fprintf(stderr, "DEBUG: ifconfig %s %s %s alias" ZT_EOL_S, _dev.c_str(), ip.isV4() ? "inet" : "inet6", ip.toString(tmp)); + fprintf(stderr, "DEBUG: ifconfig %s %s %s alias" ZT_EOL_S, _dev.c_str(), ip.isV4() ? "inet" : "inet6", ip.toString(tmp)); #endif - ::execl("/sbin/ifconfig","/sbin/ifconfig",_dev.c_str(),ip.isV4() ? "inet" : "inet6",ip.toString(tmp),"alias",(const char *)0); - ::_exit(-1); - } else if (cpid > 0) { - int exitcode = -1; - ::waitpid(cpid,&exitcode,0); - return (exitcode == 0); - } - return false; + ::execl("/sbin/ifconfig", "/sbin/ifconfig", _dev.c_str(), ip.isV4() ? "inet" : "inet6", ip.toString(tmp), "alias", (const char*)0); + ::_exit(-1); + } + else if (cpid > 0) { + int exitcode = -1; + ::waitpid(cpid, &exitcode, 0); + return (exitcode == 0); + } + return false; } -bool BSDEthernetTap::removeIp(const InetAddress &ip) +bool BSDEthernetTap::removeIp(const InetAddress& ip) { - if (!ip) - return false; - std::vector allIps(ips()); - if (std::find(allIps.begin(),allIps.end(),ip) != allIps.end()) { - if (___removeIp(_dev,ip)) - return true; - } - return false; + if (! ip) + return false; + std::vector allIps(ips()); + if (std::find(allIps.begin(), allIps.end(), ip) != allIps.end()) { + if (___removeIp(_dev, ip)) + return true; + } + return false; } std::vector BSDEthernetTap::ips() const { - uint64_t now = OSUtils::now(); + uint64_t now = OSUtils::now(); - if ((now - _lastIfAddrsUpdate) <= GETIFADDRS_CACHE_TIME) { - return _ifaddrs; - } - _lastIfAddrsUpdate = now; + if ((now - _lastIfAddrsUpdate) <= GETIFADDRS_CACHE_TIME) { + return _ifaddrs; + } + _lastIfAddrsUpdate = now; - struct ifaddrs *ifa = (struct ifaddrs *)0; - if (getifaddrs(&ifa)) - return std::vector(); + struct ifaddrs* ifa = (struct ifaddrs*)0; + if (getifaddrs(&ifa)) + return std::vector(); - std::vector r; + std::vector r; - struct ifaddrs *p = ifa; - while (p) { - if ((!strcmp(p->ifa_name,_dev.c_str()))&&(p->ifa_addr)&&(p->ifa_netmask)&&(p->ifa_addr->sa_family == p->ifa_netmask->sa_family)) { - switch(p->ifa_addr->sa_family) { - case AF_INET: { - struct sockaddr_in *sin = (struct sockaddr_in *)p->ifa_addr; - struct sockaddr_in *nm = (struct sockaddr_in *)p->ifa_netmask; - r.push_back(InetAddress(&(sin->sin_addr.s_addr),4,Utils::countBits((uint32_t)nm->sin_addr.s_addr))); - } break; - case AF_INET6: { - struct sockaddr_in6 *sin = (struct sockaddr_in6 *)p->ifa_addr; - struct sockaddr_in6 *nm = (struct sockaddr_in6 *)p->ifa_netmask; - uint32_t b[4]; - memcpy(b,nm->sin6_addr.s6_addr,sizeof(b)); - r.push_back(InetAddress(sin->sin6_addr.s6_addr,16,Utils::countBits(b[0]) + Utils::countBits(b[1]) + Utils::countBits(b[2]) + Utils::countBits(b[3]))); - } break; - } - } - p = p->ifa_next; - } + struct ifaddrs* p = ifa; + while (p) { + if ((! strcmp(p->ifa_name, _dev.c_str())) && (p->ifa_addr) && (p->ifa_netmask) && (p->ifa_addr->sa_family == p->ifa_netmask->sa_family)) { + switch (p->ifa_addr->sa_family) { + case AF_INET: { + struct sockaddr_in* sin = (struct sockaddr_in*)p->ifa_addr; + struct sockaddr_in* nm = (struct sockaddr_in*)p->ifa_netmask; + r.push_back(InetAddress(&(sin->sin_addr.s_addr), 4, Utils::countBits((uint32_t)nm->sin_addr.s_addr))); + } break; + case AF_INET6: { + struct sockaddr_in6* sin = (struct sockaddr_in6*)p->ifa_addr; + struct sockaddr_in6* nm = (struct sockaddr_in6*)p->ifa_netmask; + uint32_t b[4]; + memcpy(b, nm->sin6_addr.s6_addr, sizeof(b)); + r.push_back(InetAddress(sin->sin6_addr.s6_addr, 16, Utils::countBits(b[0]) + Utils::countBits(b[1]) + Utils::countBits(b[2]) + Utils::countBits(b[3]))); + } break; + } + } + p = p->ifa_next; + } - if (ifa) - freeifaddrs(ifa); + if (ifa) + freeifaddrs(ifa); - std::sort(r.begin(),r.end()); - std::unique(r.begin(),r.end()); + std::sort(r.begin(), r.end()); + std::unique(r.begin(), r.end()); - _ifaddrs = r; + _ifaddrs = r; - return r; + return r; } -void BSDEthernetTap::put(const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len) +void BSDEthernetTap::put(const MAC& from, const MAC& to, unsigned int etherType, const void* data, unsigned int len) { - char putBuf[ZT_MAX_MTU + 64]; - if ((_fd > 0)&&(len <= _mtu)&&(_enabled)) { - to.copyTo(putBuf,6); - from.copyTo(putBuf + 6,6); - *((uint16_t *)(putBuf + 12)) = htons((uint16_t)etherType); - memcpy(putBuf + 14,data,len); - len += 14; - ::write(_fd,putBuf,len); - } + char putBuf[ZT_MAX_MTU + 64]; + if ((_fd > 0) && (len <= _mtu) && (_enabled)) { + to.copyTo(putBuf, 6); + from.copyTo(putBuf + 6, 6); + *((uint16_t*)(putBuf + 12)) = htons((uint16_t)etherType); + memcpy(putBuf + 14, data, len); + len += 14; + ::write(_fd, putBuf, len); + } } std::string BSDEthernetTap::deviceName() const { - return _dev; + return _dev; } -void BSDEthernetTap::setFriendlyName(const char *friendlyName) +void BSDEthernetTap::setFriendlyName(const char* friendlyName) { } -void BSDEthernetTap::scanMulticastGroups(std::vector &added,std::vector &removed) +void BSDEthernetTap::scanMulticastGroups(std::vector& added, std::vector& removed) { - std::vector newGroups; + std::vector newGroups; #ifndef __OpenBSD__ - struct ifmaddrs *ifmap = (struct ifmaddrs *)0; - if (!getifmaddrs(&ifmap)) { - struct ifmaddrs *p = ifmap; - while (p) { - if (p->ifma_addr->sa_family == AF_LINK) { - struct sockaddr_dl *in = (struct sockaddr_dl *)p->ifma_name; - struct sockaddr_dl *la = (struct sockaddr_dl *)p->ifma_addr; - if ((la->sdl_alen == 6)&&(in->sdl_nlen <= _dev.length())&&(!memcmp(_dev.data(),in->sdl_data,in->sdl_nlen))) - newGroups.push_back(MulticastGroup(MAC(la->sdl_data + la->sdl_nlen,6),0)); - } - p = p->ifma_next; - } - freeifmaddrs(ifmap); - } -#endif // __OpenBSD__ + struct ifmaddrs* ifmap = (struct ifmaddrs*)0; + if (! getifmaddrs(&ifmap)) { + struct ifmaddrs* p = ifmap; + while (p) { + if (p->ifma_addr->sa_family == AF_LINK) { + struct sockaddr_dl* in = (struct sockaddr_dl*)p->ifma_name; + struct sockaddr_dl* la = (struct sockaddr_dl*)p->ifma_addr; + if ((la->sdl_alen == 6) && (in->sdl_nlen <= _dev.length()) && (! memcmp(_dev.data(), in->sdl_data, in->sdl_nlen))) + newGroups.push_back(MulticastGroup(MAC(la->sdl_data + la->sdl_nlen, 6), 0)); + } + p = p->ifma_next; + } + freeifmaddrs(ifmap); + } +#endif // __OpenBSD__ - std::vector allIps(ips()); - for(std::vector::iterator ip(allIps.begin());ip!=allIps.end();++ip) - newGroups.push_back(MulticastGroup::deriveMulticastGroupForAddressResolution(*ip)); + std::vector allIps(ips()); + for (std::vector::iterator ip(allIps.begin()); ip != allIps.end(); ++ip) + newGroups.push_back(MulticastGroup::deriveMulticastGroupForAddressResolution(*ip)); - std::sort(newGroups.begin(),newGroups.end()); - std::unique(newGroups.begin(),newGroups.end()); + std::sort(newGroups.begin(), newGroups.end()); + std::unique(newGroups.begin(), newGroups.end()); - for(std::vector::iterator m(newGroups.begin());m!=newGroups.end();++m) { - if (!std::binary_search(_multicastGroups.begin(),_multicastGroups.end(),*m)) - added.push_back(*m); - } - for(std::vector::iterator m(_multicastGroups.begin());m!=_multicastGroups.end();++m) { - if (!std::binary_search(newGroups.begin(),newGroups.end(),*m)) - removed.push_back(*m); - } + for (std::vector::iterator m(newGroups.begin()); m != newGroups.end(); ++m) { + if (! std::binary_search(_multicastGroups.begin(), _multicastGroups.end(), *m)) + added.push_back(*m); + } + for (std::vector::iterator m(_multicastGroups.begin()); m != _multicastGroups.end(); ++m) { + if (! std::binary_search(newGroups.begin(), newGroups.end(), *m)) + removed.push_back(*m); + } - _multicastGroups.swap(newGroups); + _multicastGroups.swap(newGroups); } void BSDEthernetTap::setMtu(unsigned int mtu) { - if (mtu != _mtu) { - _mtu = mtu; - long cpid = (long)vfork(); - if (cpid == 0) { - char tmp[64]; - OSUtils::ztsnprintf(tmp,sizeof(tmp),"%u",mtu); + if (mtu != _mtu) { + _mtu = mtu; + long cpid = (long)vfork(); + if (cpid == 0) { + char tmp[64]; + OSUtils::ztsnprintf(tmp, sizeof(tmp), "%u", mtu); #ifdef ZT_TRACE - fprintf(stderr, "DEBUG: ifconfig %s mtu %s" ZT_EOL_S, _dev.c_str(), tmp); + fprintf(stderr, "DEBUG: ifconfig %s mtu %s" ZT_EOL_S, _dev.c_str(), tmp); #endif - execl("/sbin/ifconfig","/sbin/ifconfig",_dev.c_str(),"mtu",tmp,(const char *)0); - _exit(-1); - } else if (cpid > 0) { - int exitcode = -1; - waitpid(cpid,&exitcode,0); - } - } + execl("/sbin/ifconfig", "/sbin/ifconfig", _dev.c_str(), "mtu", tmp, (const char*)0); + _exit(-1); + } + else if (cpid > 0) { + int exitcode = -1; + waitpid(cpid, &exitcode, 0); + } + } } -void BSDEthernetTap::threadMain() - throw() +void BSDEthernetTap::threadMain() throw() { - // Wait for a moment after startup -- wait for Network to finish - // constructing itself. - Thread::sleep(500); + // Wait for a moment after startup -- wait for Network to finish + // constructing itself. + Thread::sleep(500); - for (unsigned int i = 0; i < _concurrency; ++i) { - _rxThreads.push_back(std::thread([this, i, _pinning] { + for (unsigned int i = 0; i < _concurrency; ++i) { + _rxThreads.push_back(std::thread([this, i, _pinning] { + if (_pinning) { + int pinCore = i % _concurrency; + fprintf(stderr, "Pinning thread %d to core %d\n", i, pinCore); + pthread_t self = pthread_self(); + cpu_set_t cpuset; + CPU_ZERO(&cpuset); + CPU_SET(pinCore, &cpuset); + // int rc = sched_setaffinity(self, sizeof(cpu_set_t), &cpuset); + int rc = pthread_setaffinity_np(self, sizeof(cpu_set_t), &cpuset); + if (rc != 0) { + fprintf(stderr, "Failed to pin thread %d to core %d: %s\n", i, pinCore, strerror(errno)); + exit(1); + } + } - if (_pinning) { - int pinCore = i % _concurrency; - fprintf(stderr, "Pinning thread %d to core %d\n", i, pinCore); - pthread_t self = pthread_self(); - cpu_set_t cpuset; - CPU_ZERO(&cpuset); - CPU_SET(pinCore, &cpuset); - //int rc = sched_setaffinity(self, sizeof(cpu_set_t), &cpuset); - int rc = pthread_setaffinity_np(self, sizeof(cpu_set_t), &cpuset); - if (rc != 0) - { - fprintf(stderr, "Failed to pin thread %d to core %d: %s\n", i, pinCore, strerror(errno)); - exit(1); - } - } + uint8_t b[ZT_TAP_BUF_SIZE]; + MAC to, from; + fd_set readfds, nullfds; + int n, nfds, r; - uint8_t b[ZT_TAP_BUF_SIZE]; - MAC to, from; - fd_set readfds, nullfds; - int n, nfds, r; + FD_ZERO(&readfds); + FD_ZERO(&nullfds); + nfds = (int)std::max(_shutdownSignalPipe[0], _fd) + 1; - FD_ZERO(&readfds); - FD_ZERO(&nullfds); - nfds = (int)std::max(_shutdownSignalPipe[0],_fd) + 1; + r = 0; - r = 0; + for (;;) { + FD_SET(_shutdownSignalPipe[0], &readfds); + FD_SET(_fd, &readfds); + select(nfds, &readfds, &nullfds, &nullfds, (struct timeval*)0); - for(;;) { - FD_SET(_shutdownSignalPipe[0],&readfds); - FD_SET(_fd,&readfds); - select(nfds,&readfds,&nullfds,&nullfds,(struct timeval *)0); + if (FD_ISSET(_shutdownSignalPipe[0], &readfds)) // writes to shutdown pipe terminate thread + break; - if (FD_ISSET(_shutdownSignalPipe[0],&readfds)) // writes to shutdown pipe terminate thread - break; + if (FD_ISSET(_fd, &readfds)) { + n = (int)::read(_fd, b + r, sizeof(b) - r); + if (n < 0) { + if ((errno != EINTR) && (errno != ETIMEDOUT)) + break; + } + else { + // Some tap drivers like to send the ethernet frame and the + // payload in two chunks, so handle that by accumulating + // data until we have at least a frame. + r += n; + if (r > 14) { + if (r > ((int)_mtu + 14)) // sanity check for weird TAP behavior on some platforms + r = _mtu + 14; - if (FD_ISSET(_fd,&readfds)) { - n = (int)::read(_fd,b + r,sizeof(b) - r); - if (n < 0) { - if ((errno != EINTR)&&(errno != ETIMEDOUT)) - break; - } else { - // Some tap drivers like to send the ethernet frame and the - // payload in two chunks, so handle that by accumulating - // data until we have at least a frame. - r += n; - if (r > 14) { - if (r > ((int)_mtu + 14)) // sanity check for weird TAP behavior on some platforms - r = _mtu + 14; + if (_enabled) { + to.setTo(b, 6); + from.setTo(b + 6, 6); + unsigned int etherType = ntohs(((const uint16_t*)b)[6]); + _handler(_arg, (void*)0, _nwid, from, to, etherType, 0, (const void*)(b + 14), r - 14); + } - if (_enabled) { - to.setTo(b,6); - from.setTo(b + 6,6); - unsigned int etherType = ntohs(((const uint16_t *)b)[6]); - _handler(_arg,(void *)0,_nwid,from,to,etherType,0,(const void *)(b + 14),r - 14); - } - - r = 0; - } - } - } - } - })); - } + r = 0; + } + } + } + } + })); + } } -} // namespace ZeroTier +} // namespace ZeroTier diff --git a/osdep/BSDEthernetTap.hpp b/osdep/BSDEthernetTap.hpp index 50e2e6e8..9656a6c7 100644 --- a/osdep/BSDEthernetTap.hpp +++ b/osdep/BSDEthernetTap.hpp @@ -14,73 +14,72 @@ #ifndef ZT_BSDETHERNETTAP_HPP #define ZT_BSDETHERNETTAP_HPP +#include "../node/Constants.hpp" +#include "../node/MAC.hpp" +#include "../node/MulticastGroup.hpp" +#include "EthernetTap.hpp" +#include "Thread.hpp" + +#include #include #include - #include -#include -#include #include - -#include "../node/Constants.hpp" -#include "../node/MulticastGroup.hpp" -#include "../node/MAC.hpp" -#include "Thread.hpp" -#include "EthernetTap.hpp" +#include namespace ZeroTier { -class BSDEthernetTap : public EthernetTap -{ -public: - BSDEthernetTap( - const char *homePath, - unsigned int concurrency, - bool pinning, - const MAC &mac, - unsigned int mtu, - unsigned int metric, - uint64_t nwid, - const char *friendlyName, - void (*handler)(void *,void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int), - void *arg); +class BSDEthernetTap : public EthernetTap { + public: + BSDEthernetTap( + const char* homePath, + unsigned int concurrency, + bool pinning, + const MAC& mac, + unsigned int mtu, + unsigned int metric, + uint64_t nwid, + const char* friendlyName, + void (*handler)(void*, void*, uint64_t, const MAC&, const MAC&, unsigned int, unsigned int, const void*, unsigned int), + void* arg); - virtual ~BSDEthernetTap(); + virtual ~BSDEthernetTap(); - virtual void setEnabled(bool en); - virtual bool enabled() const; - virtual bool addIp(const InetAddress &ip); - virtual bool removeIp(const InetAddress &ip); - virtual std::vector ips() const; - virtual void put(const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len); - virtual std::string deviceName() const; - virtual void setFriendlyName(const char *friendlyName); - virtual void scanMulticastGroups(std::vector &added,std::vector &removed); - virtual void setMtu(unsigned int mtu); - virtual void setDns(const char *domain, const std::vector &servers) {} + virtual void setEnabled(bool en); + virtual bool enabled() const; + virtual bool addIp(const InetAddress& ip); + virtual bool removeIp(const InetAddress& ip); + virtual std::vector ips() const; + virtual void put(const MAC& from, const MAC& to, unsigned int etherType, const void* data, unsigned int len); + virtual std::string deviceName() const; + virtual void setFriendlyName(const char* friendlyName); + virtual void scanMulticastGroups(std::vector& added, std::vector& removed); + virtual void setMtu(unsigned int mtu); + virtual void setDns(const char* domain, const std::vector& servers) + { + } - void threadMain() - throw(); + void threadMain() throw(); -private: - void (*_handler)(void *,void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int); - void *_arg; - unsigned int _concurrency; - bool _pinning; - uint64_t _nwid; - Thread _thread; - std::string _dev; - std::vector _multicastGroups; - unsigned int _mtu; - unsigned int _metric; - int _fd; - int _shutdownSignalPipe[2]; - volatile bool _enabled; - mutable std::vector _ifaddrs; - mutable uint64_t _lastIfAddrsUpdate; - std::vector _rxThreads; + private: + void (*_handler)(void*, void*, uint64_t, const MAC&, const MAC&, unsigned int, unsigned int, const void*, unsigned int); + void* _arg; + unsigned int _concurrency; + bool _pinning; + uint64_t _nwid; + Thread _thread; + std::string _dev; + std::vector _multicastGroups; + unsigned int _mtu; + unsigned int _metric; + int _fd; + int _shutdownSignalPipe[2]; + volatile bool _enabled; + mutable std::vector _ifaddrs; + mutable uint64_t _lastIfAddrsUpdate; + std::vector _rxThreads; }; -} // namespace ZeroTier +} // namespace ZeroTier #endif diff --git a/osdep/Binder.hpp b/osdep/Binder.hpp index 23e6393a..a4ed3df8 100644 --- a/osdep/Binder.hpp +++ b/osdep/Binder.hpp @@ -22,11 +22,11 @@ #include #ifdef __WINDOWS__ -#include -#include -#include #include #include +#include +#include +#include #else #include #include @@ -34,13 +34,13 @@ #include #include #ifdef __LINUX__ +#include #include #include -#include #endif #endif -#if (defined(__unix__) || defined(__APPLE__)) && !defined(__LINUX__) && !defined(ZT_SDK) +#if (defined(__unix__) || defined(__APPLE__)) && ! defined(__LINUX__) && ! defined(ZT_SDK) #include #if TARGET_OS_OSX #include @@ -86,459 +86,459 @@ namespace ZeroTier { */ class Binder { private: - struct _Binding { - _Binding() : udpSock((PhySocket*)0) - { - } - PhySocket* udpSock; - InetAddress address; - char ifname[256] = {}; - }; + struct _Binding { + _Binding() : udpSock((PhySocket*)0) + { + } + PhySocket* udpSock; + InetAddress address; + char ifname[256] = {}; + }; public: - Binder() : _bindingCount(0) - { - } + Binder() : _bindingCount(0) + { + } - /** - * Close all bound ports, should be called on shutdown - * - * @param phy Physical interface - */ - template void closeAll(Phy& phy) - { - Mutex::Lock _l(_lock); - for (unsigned int b = 0, c = _bindingCount; b < c; ++b) { - phy.close(_bindings[b].udpSock, false); - } - _bindingCount = 0; - } + /** + * Close all bound ports, should be called on shutdown + * + * @param phy Physical interface + */ + template void closeAll(Phy& phy) + { + Mutex::Lock _l(_lock); + for (unsigned int b = 0, c = _bindingCount; b < c; ++b) { + phy.close(_bindings[b].udpSock, false); + } + _bindingCount = 0; + } - /** - * Scan local devices and addresses and rebind TCP and UDP - * - * This should be called after wake from sleep, on detected network device - * changes, on startup, or periodically (e.g. every 30-60s). - * - * @param phy Physical interface - * @param ports Ports to bind on all interfaces - * @param portCount Number of ports - * @param explicitBind If present, override interface IP detection and bind to these (if possible) - * @param ifChecker Interface checker function to see if an interface should be used - * @tparam PHY_HANDLER_TYPE Type for Phy<> template - * @tparam INTERFACE_CHECKER Type for class containing shouldBindInterface() method - */ - template void refresh(Phy& phy, unsigned int* ports, unsigned int portCount, const std::vector explicitBind, INTERFACE_CHECKER& ifChecker) - { - std::map localIfAddrs; - PhySocket *udps; - Mutex::Lock _l(_lock); - bool interfacesEnumerated = true; + /** + * Scan local devices and addresses and rebind TCP and UDP + * + * This should be called after wake from sleep, on detected network device + * changes, on startup, or periodically (e.g. every 30-60s). + * + * @param phy Physical interface + * @param ports Ports to bind on all interfaces + * @param portCount Number of ports + * @param explicitBind If present, override interface IP detection and bind to these (if possible) + * @param ifChecker Interface checker function to see if an interface should be used + * @tparam PHY_HANDLER_TYPE Type for Phy<> template + * @tparam INTERFACE_CHECKER Type for class containing shouldBindInterface() method + */ + template void refresh(Phy& phy, unsigned int* ports, unsigned int portCount, const std::vector explicitBind, INTERFACE_CHECKER& ifChecker) + { + std::map localIfAddrs; + PhySocket* udps; + Mutex::Lock _l(_lock); + bool interfacesEnumerated = true; - if (explicitBind.empty()) { + if (explicitBind.empty()) { #ifdef __WINDOWS__ - char aabuf[32768]; - ULONG aalen = sizeof(aabuf); - if (GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER, (void*)0, reinterpret_cast(aabuf), &aalen) == NO_ERROR) { - PIP_ADAPTER_ADDRESSES a = reinterpret_cast(aabuf); - while (a) { - PIP_ADAPTER_UNICAST_ADDRESS ua = a->FirstUnicastAddress; - while (ua) { - // Don't bind temporary/random IPv6 addresses - if (ua->SuffixOrigin != IpSuffixOriginRandom) { - InetAddress ip(ua->Address.lpSockaddr); - char strBuf[128] = { 0 }; - wcstombs(strBuf, a->FriendlyName, sizeof(strBuf)); - if (ifChecker.shouldBindInterface(strBuf, ip)) { - switch (ip.ipScope()) { - default: - break; - case InetAddress::IP_SCOPE_PSEUDOPRIVATE: - case InetAddress::IP_SCOPE_GLOBAL: - case InetAddress::IP_SCOPE_SHARED: - case InetAddress::IP_SCOPE_PRIVATE: - for (int x = 0; x < (int)portCount; ++x) { - ip.setPort(ports[x]); - localIfAddrs.insert(std::pair(ip, std::string())); - } - break; - } - } - } - ua = ua->Next; - } - a = a->Next; - } - } - else { - interfacesEnumerated = false; - } + char aabuf[32768]; + ULONG aalen = sizeof(aabuf); + if (GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER, (void*)0, reinterpret_cast(aabuf), &aalen) == NO_ERROR) { + PIP_ADAPTER_ADDRESSES a = reinterpret_cast(aabuf); + while (a) { + PIP_ADAPTER_UNICAST_ADDRESS ua = a->FirstUnicastAddress; + while (ua) { + // Don't bind temporary/random IPv6 addresses + if (ua->SuffixOrigin != IpSuffixOriginRandom) { + InetAddress ip(ua->Address.lpSockaddr); + char strBuf[128] = { 0 }; + wcstombs(strBuf, a->FriendlyName, sizeof(strBuf)); + if (ifChecker.shouldBindInterface(strBuf, ip)) { + switch (ip.ipScope()) { + default: + break; + case InetAddress::IP_SCOPE_PSEUDOPRIVATE: + case InetAddress::IP_SCOPE_GLOBAL: + case InetAddress::IP_SCOPE_SHARED: + case InetAddress::IP_SCOPE_PRIVATE: + for (int x = 0; x < (int)portCount; ++x) { + ip.setPort(ports[x]); + localIfAddrs.insert(std::pair(ip, std::string())); + } + break; + } + } + } + ua = ua->Next; + } + a = a->Next; + } + } + else { + interfacesEnumerated = false; + } -#else // not __WINDOWS__ +#else // not __WINDOWS__ - /* On Linux we use an alternative method if available since getifaddrs() - * gets very slow when there are lots of network namespaces. This won't - * work unless /proc/PID/net/if_inet6 exists and it may not on some - * embedded systems, so revert to getifaddrs() there. */ + /* On Linux we use an alternative method if available since getifaddrs() + * gets very slow when there are lots of network namespaces. This won't + * work unless /proc/PID/net/if_inet6 exists and it may not on some + * embedded systems, so revert to getifaddrs() there. */ #ifdef __LINUX__ - char fn[256], tmp[256]; - std::set ifnames; - const unsigned long pid = (unsigned long)getpid(); + char fn[256], tmp[256]; + std::set ifnames; + const unsigned long pid = (unsigned long)getpid(); - // Get all device names - OSUtils::ztsnprintf(fn, sizeof(fn), "/proc/%lu/net/dev", pid); - FILE* procf = fopen(fn, "r"); - if (procf) { - while (fgets(tmp, sizeof(tmp), procf)) { - tmp[255] = 0; - char* saveptr = (char*)0; - for (char* f = Utils::stok(tmp, " \t\r\n:|", &saveptr); (f); f = Utils::stok((char*)0, " \t\r\n:|", &saveptr)) { - if ((strcmp(f, "Inter-") != 0) && (strcmp(f, "face") != 0) && (f[0] != 0)) - ifnames.insert(f); - break; // we only want the first field - } - } - fclose(procf); - } - else { - interfacesEnumerated = false; - } + // Get all device names + OSUtils::ztsnprintf(fn, sizeof(fn), "/proc/%lu/net/dev", pid); + FILE* procf = fopen(fn, "r"); + if (procf) { + while (fgets(tmp, sizeof(tmp), procf)) { + tmp[255] = 0; + char* saveptr = (char*)0; + for (char* f = Utils::stok(tmp, " \t\r\n:|", &saveptr); (f); f = Utils::stok((char*)0, " \t\r\n:|", &saveptr)) { + if ((strcmp(f, "Inter-") != 0) && (strcmp(f, "face") != 0) && (f[0] != 0)) + ifnames.insert(f); + break; // we only want the first field + } + } + fclose(procf); + } + else { + interfacesEnumerated = false; + } - // Get IPv6 addresses (and any device names we don't already know) - OSUtils::ztsnprintf(fn, sizeof(fn), "/proc/%lu/net/if_inet6", pid); - procf = fopen(fn, "r"); - if (procf) { - while (fgets(tmp, sizeof(tmp), procf)) { - tmp[255] = 0; - char* saveptr = (char*)0; - unsigned char ipbits[16]; - memset(ipbits, 0, sizeof(ipbits)); - char* devname = (char*)0; - int flags = 0; - int n = 0; - for (char* f = Utils::stok(tmp, " \t\r\n", &saveptr); (f); f = Utils::stok((char*)0, " \t\r\n", &saveptr)) { - switch (n++) { - case 0: // IP in hex - Utils::unhex(f, 32, ipbits, 16); - break; - case 4: - flags = atoi(f); - break; - case 5: // device name - devname = f; - break; - } - } + // Get IPv6 addresses (and any device names we don't already know) + OSUtils::ztsnprintf(fn, sizeof(fn), "/proc/%lu/net/if_inet6", pid); + procf = fopen(fn, "r"); + if (procf) { + while (fgets(tmp, sizeof(tmp), procf)) { + tmp[255] = 0; + char* saveptr = (char*)0; + unsigned char ipbits[16]; + memset(ipbits, 0, sizeof(ipbits)); + char* devname = (char*)0; + int flags = 0; + int n = 0; + for (char* f = Utils::stok(tmp, " \t\r\n", &saveptr); (f); f = Utils::stok((char*)0, " \t\r\n", &saveptr)) { + switch (n++) { + case 0: // IP in hex + Utils::unhex(f, 32, ipbits, 16); + break; + case 4: + flags = atoi(f); + break; + case 5: // device name + devname = f; + break; + } + } - if ( (flags & IFA_F_TEMPORARY) != 0) { - continue; - } - if (devname) { - ifnames.insert(devname); - InetAddress ip(ipbits, 16, 0); - if (ifChecker.shouldBindInterface(devname, ip)) { - switch (ip.ipScope()) { - default: - break; - case InetAddress::IP_SCOPE_PSEUDOPRIVATE: - case InetAddress::IP_SCOPE_GLOBAL: - case InetAddress::IP_SCOPE_SHARED: - case InetAddress::IP_SCOPE_PRIVATE: - for (int x = 0; x < (int)portCount; ++x) { - ip.setPort(ports[x]); - localIfAddrs.insert(std::pair(ip, std::string(devname))); - } - break; - } - } - } - } - fclose(procf); - } + if ((flags & IFA_F_TEMPORARY) != 0) { + continue; + } + if (devname) { + ifnames.insert(devname); + InetAddress ip(ipbits, 16, 0); + if (ifChecker.shouldBindInterface(devname, ip)) { + switch (ip.ipScope()) { + default: + break; + case InetAddress::IP_SCOPE_PSEUDOPRIVATE: + case InetAddress::IP_SCOPE_GLOBAL: + case InetAddress::IP_SCOPE_SHARED: + case InetAddress::IP_SCOPE_PRIVATE: + for (int x = 0; x < (int)portCount; ++x) { + ip.setPort(ports[x]); + localIfAddrs.insert(std::pair(ip, std::string(devname))); + } + break; + } + } + } + } + fclose(procf); + } - // Get IPv4 addresses for each device - if (! ifnames.empty()) { - const int controlfd = (int)socket(AF_INET, SOCK_DGRAM, 0); - struct ifconf configuration; - configuration.ifc_len = 0; - configuration.ifc_buf = nullptr; + // Get IPv4 addresses for each device + if (! ifnames.empty()) { + const int controlfd = (int)socket(AF_INET, SOCK_DGRAM, 0); + struct ifconf configuration; + configuration.ifc_len = 0; + configuration.ifc_buf = nullptr; - if (controlfd < 0) - goto ip4_address_error; - if (ioctl(controlfd, SIOCGIFCONF, &configuration) < 0) - goto ip4_address_error; - configuration.ifc_buf = (char*)malloc(configuration.ifc_len); - if (ioctl(controlfd, SIOCGIFCONF, &configuration) < 0) - goto ip4_address_error; + if (controlfd < 0) + goto ip4_address_error; + if (ioctl(controlfd, SIOCGIFCONF, &configuration) < 0) + goto ip4_address_error; + configuration.ifc_buf = (char*)malloc(configuration.ifc_len); + if (ioctl(controlfd, SIOCGIFCONF, &configuration) < 0) + goto ip4_address_error; - for (int i = 0; i < (int)(configuration.ifc_len / sizeof(ifreq)); i++) { - struct ifreq& request = configuration.ifc_req[i]; - struct sockaddr* addr = &request.ifr_ifru.ifru_addr; - if (addr->sa_family != AF_INET) - continue; - std::string ifname = request.ifr_ifrn.ifrn_name; - // name can either be just interface name or interface name followed by ':' and arbitrary label - if (ifname.find(':') != std::string::npos) - ifname = ifname.substr(0, ifname.find(':')); + for (int i = 0; i < (int)(configuration.ifc_len / sizeof(ifreq)); i++) { + struct ifreq& request = configuration.ifc_req[i]; + struct sockaddr* addr = &request.ifr_ifru.ifru_addr; + if (addr->sa_family != AF_INET) + continue; + std::string ifname = request.ifr_ifrn.ifrn_name; + // name can either be just interface name or interface name followed by ':' and arbitrary label + if (ifname.find(':') != std::string::npos) + ifname = ifname.substr(0, ifname.find(':')); - InetAddress ip(&(((struct sockaddr_in*)addr)->sin_addr), 4, 0); - if (ifChecker.shouldBindInterface(ifname.c_str(), ip)) { - switch (ip.ipScope()) { - default: - break; - case InetAddress::IP_SCOPE_PSEUDOPRIVATE: - case InetAddress::IP_SCOPE_GLOBAL: - case InetAddress::IP_SCOPE_SHARED: - case InetAddress::IP_SCOPE_PRIVATE: - for (int x = 0; x < (int)portCount; ++x) { - ip.setPort(ports[x]); - localIfAddrs.insert(std::pair(ip, ifname)); - } - break; - } - } - } + InetAddress ip(&(((struct sockaddr_in*)addr)->sin_addr), 4, 0); + if (ifChecker.shouldBindInterface(ifname.c_str(), ip)) { + switch (ip.ipScope()) { + default: + break; + case InetAddress::IP_SCOPE_PSEUDOPRIVATE: + case InetAddress::IP_SCOPE_GLOBAL: + case InetAddress::IP_SCOPE_SHARED: + case InetAddress::IP_SCOPE_PRIVATE: + for (int x = 0; x < (int)portCount; ++x) { + ip.setPort(ports[x]); + localIfAddrs.insert(std::pair(ip, ifname)); + } + break; + } + } + } - ip4_address_error: - free(configuration.ifc_buf); - if (controlfd > 0) - close(controlfd); - } + ip4_address_error: + free(configuration.ifc_buf); + if (controlfd > 0) + close(controlfd); + } - const bool gotViaProc = (! localIfAddrs.empty()); + const bool gotViaProc = (! localIfAddrs.empty()); #else - const bool gotViaProc = false; + const bool gotViaProc = false; #endif - // - // prevent: - // warning: unused variable 'gotViaProc' - // - (void)gotViaProc; + // + // prevent: + // warning: unused variable 'gotViaProc' + // + (void)gotViaProc; -#if ! defined(__ANDROID__) // getifaddrs() freeifaddrs() not available on Android - if (! gotViaProc) { - struct ifaddrs* ifatbl = (struct ifaddrs*)0; - struct ifaddrs* ifa; -#if (defined(__unix__) || defined(__APPLE__)) && !defined(__LINUX__) && !defined(ZT_SDK) - // set up an IPv6 socket so we can check the state of interfaces via SIOCGIFAFLAG_IN6 - int infoSock = socket(AF_INET6, SOCK_DGRAM, 0); +#if ! defined(__ANDROID__) // getifaddrs() freeifaddrs() not available on Android + if (! gotViaProc) { + struct ifaddrs* ifatbl = (struct ifaddrs*)0; + struct ifaddrs* ifa; +#if (defined(__unix__) || defined(__APPLE__)) && ! defined(__LINUX__) && ! defined(ZT_SDK) + // set up an IPv6 socket so we can check the state of interfaces via SIOCGIFAFLAG_IN6 + int infoSock = socket(AF_INET6, SOCK_DGRAM, 0); #endif - if ((getifaddrs(&ifatbl) == 0) && (ifatbl)) { - ifa = ifatbl; - while (ifa) { - if ((ifa->ifa_name) && (ifa->ifa_addr)) { - InetAddress ip = *(ifa->ifa_addr); -#if (defined(__unix__) || defined(__APPLE__)) && !defined(__LINUX__) && !defined(ZT_SDK) && TARGET_OS_OSX - // Check if the address is an IPv6 Temporary Address, macOS/BSD version - if (ifa->ifa_addr->sa_family == AF_INET6) { - struct sockaddr_in6* sa6 = (struct sockaddr_in6*)ifa->ifa_addr; - struct in6_ifreq ifr6; - memset(&ifr6, 0, sizeof(ifr6)); - strcpy(ifr6.ifr_name, ifa->ifa_name); - ifr6.ifr_ifru.ifru_addr = *sa6; + if ((getifaddrs(&ifatbl) == 0) && (ifatbl)) { + ifa = ifatbl; + while (ifa) { + if ((ifa->ifa_name) && (ifa->ifa_addr)) { + InetAddress ip = *(ifa->ifa_addr); +#if (defined(__unix__) || defined(__APPLE__)) && ! defined(__LINUX__) && ! defined(ZT_SDK) && TARGET_OS_OSX + // Check if the address is an IPv6 Temporary Address, macOS/BSD version + if (ifa->ifa_addr->sa_family == AF_INET6) { + struct sockaddr_in6* sa6 = (struct sockaddr_in6*)ifa->ifa_addr; + struct in6_ifreq ifr6; + memset(&ifr6, 0, sizeof(ifr6)); + strcpy(ifr6.ifr_name, ifa->ifa_name); + ifr6.ifr_ifru.ifru_addr = *sa6; - int flags = 0; - if (ioctl(infoSock, SIOCGIFAFLAG_IN6, (unsigned long long)&ifr6) != -1) { - flags = ifr6.ifr_ifru.ifru_flags6; - } + int flags = 0; + if (ioctl(infoSock, SIOCGIFAFLAG_IN6, (unsigned long long)&ifr6) != -1) { + flags = ifr6.ifr_ifru.ifru_flags6; + } - // if this is a temporary IPv6 address, skip to the next address - if (flags & IN6_IFF_TEMPORARY) { + // if this is a temporary IPv6 address, skip to the next address + if (flags & IN6_IFF_TEMPORARY) { #ifdef ZT_TRACE - char buf[64]; - fprintf(stderr, "skip binding to temporary IPv6 address: %s\n", ip.toIpString(buf)); + char buf[64]; + fprintf(stderr, "skip binding to temporary IPv6 address: %s\n", ip.toIpString(buf)); #endif - ifa = ifa->ifa_next; - continue; - } - } + ifa = ifa->ifa_next; + continue; + } + } #endif - if (ifChecker.shouldBindInterface(ifa->ifa_name, ip)) { - switch (ip.ipScope()) { - default: - break; - case InetAddress::IP_SCOPE_PSEUDOPRIVATE: - case InetAddress::IP_SCOPE_GLOBAL: - case InetAddress::IP_SCOPE_SHARED: - case InetAddress::IP_SCOPE_PRIVATE: - for (int x = 0; x < (int)portCount; ++x) { - ip.setPort(ports[x]); - localIfAddrs.insert(std::pair(ip, std::string(ifa->ifa_name))); - } - break; - } - } - } - ifa = ifa->ifa_next; - } - freeifaddrs(ifatbl); - } - else { - interfacesEnumerated = false; - } -#if (defined(__unix__) || defined(__APPLE__)) && !defined(__LINUX__) && !defined(ZT_SDK) - close(infoSock); + if (ifChecker.shouldBindInterface(ifa->ifa_name, ip)) { + switch (ip.ipScope()) { + default: + break; + case InetAddress::IP_SCOPE_PSEUDOPRIVATE: + case InetAddress::IP_SCOPE_GLOBAL: + case InetAddress::IP_SCOPE_SHARED: + case InetAddress::IP_SCOPE_PRIVATE: + for (int x = 0; x < (int)portCount; ++x) { + ip.setPort(ports[x]); + localIfAddrs.insert(std::pair(ip, std::string(ifa->ifa_name))); + } + break; + } + } + } + ifa = ifa->ifa_next; + } + freeifaddrs(ifatbl); + } + else { + interfacesEnumerated = false; + } +#if (defined(__unix__) || defined(__APPLE__)) && ! defined(__LINUX__) && ! defined(ZT_SDK) + close(infoSock); #endif - } + } #endif #endif - } - else { - for (std::vector::const_iterator i(explicitBind.begin()); i != explicitBind.end(); ++i) { - InetAddress ip = InetAddress(*i); - for (int x = 0; x < (int)portCount; ++x) { - ip.setPort(ports[x]); - localIfAddrs.insert(std::pair(ip, std::string())); - } - } - } + } + else { + for (std::vector::const_iterator i(explicitBind.begin()); i != explicitBind.end(); ++i) { + InetAddress ip = InetAddress(*i); + for (int x = 0; x < (int)portCount; ++x) { + ip.setPort(ports[x]); + localIfAddrs.insert(std::pair(ip, std::string())); + } + } + } - // Default to binding to wildcard if we can't enumerate addresses - if (! interfacesEnumerated && localIfAddrs.empty()) { - for (int x = 0; x < (int)portCount; ++x) { - localIfAddrs.insert(std::pair(InetAddress((uint32_t)0, ports[x]), std::string())); - localIfAddrs.insert(std::pair(InetAddress((const void*)"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 16, ports[x]), std::string())); - } - } + // Default to binding to wildcard if we can't enumerate addresses + if (! interfacesEnumerated && localIfAddrs.empty()) { + for (int x = 0; x < (int)portCount; ++x) { + localIfAddrs.insert(std::pair(InetAddress((uint32_t)0, ports[x]), std::string())); + localIfAddrs.insert(std::pair(InetAddress((const void*)"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 16, ports[x]), std::string())); + } + } - const unsigned int oldBindingCount = _bindingCount; - _bindingCount = 0; + const unsigned int oldBindingCount = _bindingCount; + _bindingCount = 0; - // Save bindings that are still valid, close those that are not - for (unsigned int b = 0; b < oldBindingCount; ++b) { - if (localIfAddrs.find(_bindings[b].address) != localIfAddrs.end()) { - if (_bindingCount != b) - _bindings[(unsigned int)_bindingCount] = _bindings[b]; - ++_bindingCount; - } - else { - PhySocket* const udps = _bindings[b].udpSock; - _bindings[b].udpSock = (PhySocket*)0; - phy.close(udps, false); - } - } + // Save bindings that are still valid, close those that are not + for (unsigned int b = 0; b < oldBindingCount; ++b) { + if (localIfAddrs.find(_bindings[b].address) != localIfAddrs.end()) { + if (_bindingCount != b) + _bindings[(unsigned int)_bindingCount] = _bindings[b]; + ++_bindingCount; + } + else { + PhySocket* const udps = _bindings[b].udpSock; + _bindings[b].udpSock = (PhySocket*)0; + phy.close(udps, false); + } + } - // Create new bindings for those not already bound - for (std::map::const_iterator ii(localIfAddrs.begin()); ii != localIfAddrs.end(); ++ii) { - unsigned int bi = 0; - while (bi != _bindingCount) { - if (_bindings[bi].address == ii->first) - break; - ++bi; - } - if (bi == _bindingCount) { - udps = phy.udpBind(reinterpret_cast(&(ii->first)), (void*)0, ZT_UDP_DESIRED_BUF_SIZE); - if (udps) { + // Create new bindings for those not already bound + for (std::map::const_iterator ii(localIfAddrs.begin()); ii != localIfAddrs.end(); ++ii) { + unsigned int bi = 0; + while (bi != _bindingCount) { + if (_bindings[bi].address == ii->first) + break; + ++bi; + } + if (bi == _bindingCount) { + udps = phy.udpBind(reinterpret_cast(&(ii->first)), (void*)0, ZT_UDP_DESIRED_BUF_SIZE); + if (udps) { #ifdef __LINUX__ - // Bind Linux sockets to their device so routes that we manage do not override physical routes (wish all platforms had this!) - if (ii->second.length() > 0) { - char tmp[256]; - Utils::scopy(tmp, sizeof(tmp), ii->second.c_str()); - int fd = (int)Phy::getDescriptor(udps); - if (fd >= 0) { - setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, tmp, strlen(tmp)); - } - } -#endif // __LINUX__ - if (_bindingCount < ZT_BINDER_MAX_BINDINGS) { - _bindings[_bindingCount].udpSock = udps; - _bindings[_bindingCount].address = ii->first; - memcpy(_bindings[_bindingCount].ifname, (char*)ii->second.c_str(), (int)ii->second.length()); - ++_bindingCount; - } - } - else { - phy.close(udps, false); - } - } - } - } + // Bind Linux sockets to their device so routes that we manage do not override physical routes (wish all platforms had this!) + if (ii->second.length() > 0) { + char tmp[256]; + Utils::scopy(tmp, sizeof(tmp), ii->second.c_str()); + int fd = (int)Phy::getDescriptor(udps); + if (fd >= 0) { + setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, tmp, strlen(tmp)); + } + } +#endif // __LINUX__ + if (_bindingCount < ZT_BINDER_MAX_BINDINGS) { + _bindings[_bindingCount].udpSock = udps; + _bindings[_bindingCount].address = ii->first; + memcpy(_bindings[_bindingCount].ifname, (char*)ii->second.c_str(), (int)ii->second.length()); + ++_bindingCount; + } + } + else { + phy.close(udps, false); + } + } + } + } - /** - * @return All currently bound local interface addresses - */ - inline std::vector allBoundLocalInterfaceAddresses() const - { - std::vector aa; - Mutex::Lock _l(_lock); - for (unsigned int b = 0, c = _bindingCount; b < c; ++b) - aa.push_back(_bindings[b].address); - return aa; - } + /** + * @return All currently bound local interface addresses + */ + inline std::vector allBoundLocalInterfaceAddresses() const + { + std::vector aa; + Mutex::Lock _l(_lock); + for (unsigned int b = 0, c = _bindingCount; b < c; ++b) + aa.push_back(_bindings[b].address); + return aa; + } - /** - * Send from all bound UDP sockets - */ - template inline bool udpSendAll(Phy& phy, const struct sockaddr_storage* addr, const void* data, unsigned int len, unsigned int ttl) - { - bool r = false; - Mutex::Lock _l(_lock); - for (unsigned int b = 0, c = _bindingCount; b < c; ++b) { - if (ttl) - phy.setIp4UdpTtl(_bindings[b].udpSock, ttl); - if (phy.udpSend(_bindings[b].udpSock, (const struct sockaddr*)addr, data, len)) - r = true; - if (ttl) - phy.setIp4UdpTtl(_bindings[b].udpSock, 255); - } - return r; - } + /** + * Send from all bound UDP sockets + */ + template inline bool udpSendAll(Phy& phy, const struct sockaddr_storage* addr, const void* data, unsigned int len, unsigned int ttl) + { + bool r = false; + Mutex::Lock _l(_lock); + for (unsigned int b = 0, c = _bindingCount; b < c; ++b) { + if (ttl) + phy.setIp4UdpTtl(_bindings[b].udpSock, ttl); + if (phy.udpSend(_bindings[b].udpSock, (const struct sockaddr*)addr, data, len)) + r = true; + if (ttl) + phy.setIp4UdpTtl(_bindings[b].udpSock, 255); + } + return r; + } - /** - * @param addr Address to check - * @return True if this is a bound local interface address - */ - inline bool isBoundLocalInterfaceAddress(const InetAddress& addr) const - { - Mutex::Lock _l(_lock); - for (unsigned int b = 0; b < _bindingCount; ++b) { - if (_bindings[b].address == addr) - return true; - } - return false; - } + /** + * @param addr Address to check + * @return True if this is a bound local interface address + */ + inline bool isBoundLocalInterfaceAddress(const InetAddress& addr) const + { + Mutex::Lock _l(_lock); + for (unsigned int b = 0; b < _bindingCount; ++b) { + if (_bindings[b].address == addr) + return true; + } + return false; + } - /** - * Quickly check that a UDP socket is valid - * - * @param udpSock UDP socket to check - * @return True if socket is currently bound/allocated - */ - inline bool isUdpSocketValid(PhySocket* const udpSock) - { - for (unsigned int b = 0, c = _bindingCount; b < c; ++b) { - if (_bindings[b].udpSock == udpSock) - return (b < _bindingCount); // double check atomic which may have changed - } - return false; - } + /** + * Quickly check that a UDP socket is valid + * + * @param udpSock UDP socket to check + * @return True if socket is currently bound/allocated + */ + inline bool isUdpSocketValid(PhySocket* const udpSock) + { + for (unsigned int b = 0, c = _bindingCount; b < c; ++b) { + if (_bindings[b].udpSock == udpSock) + return (b < _bindingCount); // double check atomic which may have changed + } + return false; + } - /** - * @param s Socket object - * @param nameBuf Buffer to store name of interface which this Socket object is bound to - * @param buflen Length of buffer to copy name into - */ - void getIfName(PhySocket* s, char* nameBuf, int buflen) const - { - Mutex::Lock _l(_lock); - for (unsigned int b = 0, c = _bindingCount; b < c; ++b) { - if (_bindings[b].udpSock == s) { - memcpy(nameBuf, _bindings[b].ifname, buflen); - break; - } - } - } + /** + * @param s Socket object + * @param nameBuf Buffer to store name of interface which this Socket object is bound to + * @param buflen Length of buffer to copy name into + */ + void getIfName(PhySocket* s, char* nameBuf, int buflen) const + { + Mutex::Lock _l(_lock); + for (unsigned int b = 0, c = _bindingCount; b < c; ++b) { + if (_bindings[b].udpSock == s) { + memcpy(nameBuf, _bindings[b].ifname, buflen); + break; + } + } + } private: - _Binding _bindings[ZT_BINDER_MAX_BINDINGS]; - std::atomic _bindingCount; - Mutex _lock; + _Binding _bindings[ZT_BINDER_MAX_BINDINGS]; + std::atomic _bindingCount; + Mutex _lock; }; -} // namespace ZeroTier +} // namespace ZeroTier #endif diff --git a/osdep/BlockingQueue.hpp b/osdep/BlockingQueue.hpp index c9417b74..dfb262c5 100644 --- a/osdep/BlockingQueue.hpp +++ b/osdep/BlockingQueue.hpp @@ -14,11 +14,11 @@ #ifndef ZT_BLOCKINGQUEUE_HPP #define ZT_BLOCKINGQUEUE_HPP -#include -#include -#include -#include #include +#include +#include +#include +#include #include namespace ZeroTier { @@ -28,105 +28,101 @@ namespace ZeroTier { * * Do not use in node/ since we have not gone C++11 there yet. */ -template -class BlockingQueue -{ -public: - BlockingQueue(void) : r(true) {} +template class BlockingQueue { + public: + BlockingQueue(void) : r(true) + { + } - inline void post(T t) - { - std::lock_guard lock(m); - q.push(t); - c.notify_one(); - } + inline void post(T t) + { + std::lock_guard lock(m); + q.push(t); + c.notify_one(); + } - inline void postLimit(T t,const unsigned long limit) - { - std::unique_lock lock(m); - for(;;) { - if (q.size() < limit) { - q.push(t); - c.notify_one(); - break; - } - if (!r) - break; - gc.wait(lock); - } - } + inline void postLimit(T t, const unsigned long limit) + { + std::unique_lock lock(m); + for (;;) { + if (q.size() < limit) { + q.push(t); + c.notify_one(); + break; + } + if (! r) + break; + gc.wait(lock); + } + } - inline void stop(void) - { - std::lock_guard lock(m); - r = false; - c.notify_all(); - gc.notify_all(); - } + inline void stop(void) + { + std::lock_guard lock(m); + r = false; + c.notify_all(); + gc.notify_all(); + } - inline bool get(T &value) - { - std::unique_lock lock(m); - if (!r) - return false; - while (q.empty()) { - c.wait(lock); - if (!r) { - gc.notify_all(); - return false; - } - } - value = q.front(); - q.pop(); - gc.notify_all(); - return true; - } + inline bool get(T& value) + { + std::unique_lock lock(m); + if (! r) + return false; + while (q.empty()) { + c.wait(lock); + if (! r) { + gc.notify_all(); + return false; + } + } + value = q.front(); + q.pop(); + gc.notify_all(); + return true; + } - inline std::vector drain() - { - std::vector v; - while (!q.empty()) { - v.push_back(q.front()); - q.pop(); - } - return v; - } + inline std::vector drain() + { + std::vector v; + while (! q.empty()) { + v.push_back(q.front()); + q.pop(); + } + return v; + } - enum TimedWaitResult - { - OK, - TIMED_OUT, - STOP - }; + enum TimedWaitResult { OK, TIMED_OUT, STOP }; - inline TimedWaitResult get(T &value,const unsigned long ms) - { - const std::chrono::milliseconds ms2{ms}; - std::unique_lock lock(m); - if (!r) - return STOP; - while (q.empty()) { - if (c.wait_for(lock,ms2) == std::cv_status::timeout) - return ((r) ? TIMED_OUT : STOP); - else if (!r) - return STOP; - } - value = q.front(); - q.pop(); - return OK; - } + inline TimedWaitResult get(T& value, const unsigned long ms) + { + const std::chrono::milliseconds ms2 { ms }; + std::unique_lock lock(m); + if (! r) + return STOP; + while (q.empty()) { + if (c.wait_for(lock, ms2) == std::cv_status::timeout) + return ((r) ? TIMED_OUT : STOP); + else if (! r) + return STOP; + } + value = q.front(); + q.pop(); + return OK; + } - inline size_t size() const { - return q.size(); - } + inline size_t size() const + { + return q.size(); + } -private: - std::queue q; - mutable std::mutex m; - mutable std::condition_variable c,gc; - std::atomic_bool r; + private: + std::queue q; + mutable std::mutex m; + mutable std::condition_variable c, gc; + std::atomic_bool r; }; -} // namespace ZeroTier +} // namespace ZeroTier #endif diff --git a/osdep/EthernetTap.cpp b/osdep/EthernetTap.cpp index 0be209ec..fb2a8672 100644 --- a/osdep/EthernetTap.cpp +++ b/osdep/EthernetTap.cpp @@ -12,6 +12,7 @@ /****/ #include "EthernetTap.hpp" + #include "OSUtils.hpp" #include @@ -20,150 +21,145 @@ #ifdef ZT_SDK #include "../controller/EmbeddedNetworkController.hpp" -#include "../node/Node.hpp" #include "../include/VirtualTap.hpp" +#include "../node/Node.hpp" #else #ifdef __APPLE__ -#include #include "MacEthernetTap.hpp" #include "MacKextEthernetTap.hpp" -#endif // __APPLE__ + +#include +#endif // __APPLE__ #ifdef __LINUX__ #include "LinuxEthernetTap.hpp" -#endif // __LINUX__ +#endif // __LINUX__ #ifdef __WINDOWS__ #include "WindowsEthernetTap.hpp" -#endif // __WINDOWS__ +#endif // __WINDOWS__ #ifdef __FreeBSD__ #include "BSDEthernetTap.hpp" -#endif // __FreeBSD__ +#endif // __FreeBSD__ #ifdef __NetBSD__ #include "NetBSDEthernetTap.hpp" -#endif // __NetBSD__ +#endif // __NetBSD__ #ifdef __OpenBSD__ #include "BSDEthernetTap.hpp" -#endif // __OpenBSD__ +#endif // __OpenBSD__ #endif namespace ZeroTier { std::shared_ptr EthernetTap::newInstance( - const char *tapDeviceType, // OS-specific, NULL for default - unsigned int concurrency, - bool pinning, - const char *homePath, - const MAC &mac, - unsigned int mtu, - unsigned int metric, - uint64_t nwid, - const char *friendlyName, - void (*handler)(void *,void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int), - void *arg) + const char* tapDeviceType, // OS-specific, NULL for default + unsigned int concurrency, + bool pinning, + const char* homePath, + const MAC& mac, + unsigned int mtu, + unsigned int metric, + uint64_t nwid, + const char* friendlyName, + void (*handler)(void*, void*, uint64_t, const MAC&, const MAC&, unsigned int, unsigned int, const void*, unsigned int), + void* arg) { - #ifdef ZT_SDK - return std::shared_ptr(new VirtualTap(homePath,mac,mtu,metric,nwid,friendlyName,handler,arg)); + return std::shared_ptr(new VirtualTap(homePath, mac, mtu, metric, nwid, friendlyName, handler, arg)); -#else // not ZT_SDK +#else // not ZT_SDK #ifdef __APPLE__ - char osrelease[256]; - size_t size = sizeof(osrelease); - if (sysctlbyname("kern.osrelease",osrelease,&size,nullptr,0) == 0) { - char *dotAt = strchr(osrelease,'.'); - if (dotAt) { - *dotAt = (char)0; - // The "feth" virtual Ethernet device type appeared in Darwin 17.x.x. Older versions - // (Sierra and earlier) must use the a kernel extension. - if (strtol(osrelease,(char **)0,10) < 17) { - return std::shared_ptr(new MacKextEthernetTap(homePath,mac,mtu,metric,nwid,friendlyName,handler,arg)); - } else { - return std::shared_ptr(new MacEthernetTap(homePath,mac,mtu,metric,nwid,friendlyName,handler,arg)); - } - } - } -#endif // __APPLE__ + char osrelease[256]; + size_t size = sizeof(osrelease); + if (sysctlbyname("kern.osrelease", osrelease, &size, nullptr, 0) == 0) { + char* dotAt = strchr(osrelease, '.'); + if (dotAt) { + *dotAt = (char)0; + // The "feth" virtual Ethernet device type appeared in Darwin 17.x.x. Older versions + // (Sierra and earlier) must use the a kernel extension. + if (strtol(osrelease, (char**)0, 10) < 17) { + return std::shared_ptr(new MacKextEthernetTap(homePath, mac, mtu, metric, nwid, friendlyName, handler, arg)); + } + else { + return std::shared_ptr(new MacEthernetTap(homePath, mac, mtu, metric, nwid, friendlyName, handler, arg)); + } + } + } +#endif // __APPLE__ #ifdef __LINUX__ - return std::shared_ptr(new LinuxEthernetTap(homePath,concurrency,pinning,mac,mtu,metric,nwid,friendlyName,handler,arg)); -#endif // __LINUX__ + return std::shared_ptr(new LinuxEthernetTap(homePath, concurrency, pinning, mac, mtu, metric, nwid, friendlyName, handler, arg)); +#endif // __LINUX__ #ifdef __WINDOWS__ - HRESULT hres = CoInitializeEx(0, COINIT_MULTITHREADED); - if (FAILED(hres)) { - throw std::runtime_error("WinEthernetTap: COM initialization failed"); - } + HRESULT hres = CoInitializeEx(0, COINIT_MULTITHREADED); + if (FAILED(hres)) { + throw std::runtime_error("WinEthernetTap: COM initialization failed"); + } - static bool _comInit = false; - static Mutex _comInit_m; + static bool _comInit = false; + static Mutex _comInit_m; - { - Mutex::Lock l(_comInit_m); - if (!_comInit) { - hres = CoInitializeSecurity( - NULL, - -1, - NULL, - NULL, - RPC_C_AUTHN_LEVEL_PKT, - RPC_C_IMP_LEVEL_IMPERSONATE, - NULL, - EOAC_NONE, - NULL - ); - if (FAILED(hres)) { - CoUninitialize(); - fprintf(stderr, "WinEthernetTap: Failed to initialize security"); - throw std::runtime_error("WinEthernetTap: Failed to initialize security"); - } - _comInit = true; - } - } - return std::shared_ptr(new WindowsEthernetTap(homePath,mac,mtu,metric,nwid,friendlyName,handler,arg)); -#endif // __WINDOWS__ + { + Mutex::Lock l(_comInit_m); + if (! _comInit) { + hres = CoInitializeSecurity(NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_PKT, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE, NULL); + if (FAILED(hres)) { + CoUninitialize(); + fprintf(stderr, "WinEthernetTap: Failed to initialize security"); + throw std::runtime_error("WinEthernetTap: Failed to initialize security"); + } + _comInit = true; + } + } + return std::shared_ptr(new WindowsEthernetTap(homePath, mac, mtu, metric, nwid, friendlyName, handler, arg)); +#endif // __WINDOWS__ #ifdef __FreeBSD__ - return std::shared_ptr(new BSDEthernetTap(homePath,concurrency,pinning,mac,mtu,metric,nwid,friendlyName,handler,arg)); -#endif // __FreeBSD__ + return std::shared_ptr(new BSDEthernetTap(homePath, concurrency, pinning, mac, mtu, metric, nwid, friendlyName, handler, arg)); +#endif // __FreeBSD__ #ifdef __NetBSD__ - return std::shared_ptr(new NetBSDEthernetTap(homePath,mac,mtu,metric,nwid,friendlyName,handler,arg)); -#endif // __NetBSD__ + return std::shared_ptr(new NetBSDEthernetTap(homePath, mac, mtu, metric, nwid, friendlyName, handler, arg)); +#endif // __NetBSD__ #ifdef __OpenBSD__ - return std::shared_ptr(new BSDEthernetTap(homePath,mac,mtu,metric,nwid,friendlyName,handler,arg)); -#endif // __OpenBSD__ + return std::shared_ptr(new BSDEthernetTap(homePath, mac, mtu, metric, nwid, friendlyName, handler, arg)); +#endif // __OpenBSD__ -#endif // ZT_SDK? +#endif // ZT_SDK? - return std::shared_ptr(); + return std::shared_ptr(); } -EthernetTap::EthernetTap() {} -EthernetTap::~EthernetTap() {} +EthernetTap::EthernetTap() +{ +} +EthernetTap::~EthernetTap() +{ +} bool EthernetTap::addIps(std::vector ips) { - for(std::vector::const_iterator i(ips.begin());i!=ips.end();++i) { - if (!addIp(*i)) - return false; - } - return true; + for (std::vector::const_iterator i(ips.begin()); i != ips.end(); ++i) { + if (! addIp(*i)) + return false; + } + return true; } std::string EthernetTap::friendlyName() const { - // Most platforms do not have this. - return std::string(); + // Most platforms do not have this. + return std::string(); } -} // namespace ZeroTier +} // namespace ZeroTier diff --git a/osdep/EthernetTap.hpp b/osdep/EthernetTap.hpp index 1d97f125..e2d3e977 100644 --- a/osdep/EthernetTap.hpp +++ b/osdep/EthernetTap.hpp @@ -15,52 +15,51 @@ #define ZT_ETHERNETTAP_HPP #include "../node/Constants.hpp" -#include "../node/MAC.hpp" #include "../node/InetAddress.hpp" +#include "../node/MAC.hpp" #include "../node/MulticastGroup.hpp" -#include #include +#include #include #define GETIFADDRS_CACHE_TIME 1000 namespace ZeroTier { -class EthernetTap -{ -public: - static std::shared_ptr newInstance( - const char *tapDeviceType, // OS-specific, NULL for default - unsigned int concurrency, - bool pinning, - const char *homePath, - const MAC &mac, - unsigned int mtu, - unsigned int metric, - uint64_t nwid, - const char *friendlyName, - void (*handler)(void *,void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int), - void *arg); +class EthernetTap { + public: + static std::shared_ptr newInstance( + const char* tapDeviceType, // OS-specific, NULL for default + unsigned int concurrency, + bool pinning, + const char* homePath, + const MAC& mac, + unsigned int mtu, + unsigned int metric, + uint64_t nwid, + const char* friendlyName, + void (*handler)(void*, void*, uint64_t, const MAC&, const MAC&, unsigned int, unsigned int, const void*, unsigned int), + void* arg); - EthernetTap(); - virtual ~EthernetTap(); + EthernetTap(); + virtual ~EthernetTap(); - virtual void setEnabled(bool en) = 0; - virtual bool enabled() const = 0; - virtual bool addIp(const InetAddress &ip) = 0; - virtual bool addIps(std::vector ips); // uses addIp() unless overridden - virtual bool removeIp(const InetAddress &ip) = 0; - virtual std::vector ips() const = 0; - virtual void put(const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len) = 0; - virtual std::string deviceName() const = 0; - virtual void setFriendlyName(const char *friendlyName) = 0; - virtual std::string friendlyName() const; - virtual void scanMulticastGroups(std::vector &added,std::vector &removed) = 0; - virtual void setMtu(unsigned int mtu) = 0; - virtual void setDns(const char *domain, const std::vector &servers) = 0; + virtual void setEnabled(bool en) = 0; + virtual bool enabled() const = 0; + virtual bool addIp(const InetAddress& ip) = 0; + virtual bool addIps(std::vector ips); // uses addIp() unless overridden + virtual bool removeIp(const InetAddress& ip) = 0; + virtual std::vector ips() const = 0; + virtual void put(const MAC& from, const MAC& to, unsigned int etherType, const void* data, unsigned int len) = 0; + virtual std::string deviceName() const = 0; + virtual void setFriendlyName(const char* friendlyName) = 0; + virtual std::string friendlyName() const; + virtual void scanMulticastGroups(std::vector& added, std::vector& removed) = 0; + virtual void setMtu(unsigned int mtu) = 0; + virtual void setDns(const char* domain, const std::vector& servers) = 0; }; -} // namespace ZeroTier +} // namespace ZeroTier #endif diff --git a/osdep/Http.cpp b/osdep/Http.cpp index d392cd54..30b113db 100644 --- a/osdep/Http.cpp +++ b/osdep/Http.cpp @@ -11,15 +11,16 @@ */ /****/ -#include -#include -#include - #include "Http.hpp" -#include "Phy.hpp" -#include "OSUtils.hpp" + #include "../node/Constants.hpp" #include "../node/Utils.hpp" +#include "OSUtils.hpp" +#include "Phy.hpp" + +#include +#include +#include #ifdef ZT_USE_SYSTEM_HTTP_PARSER #include @@ -31,257 +32,258 @@ namespace ZeroTier { namespace { -static int ShttpOnMessageBegin(http_parser *parser); -static int ShttpOnUrl(http_parser *parser,const char *ptr,size_t length); +static int ShttpOnMessageBegin(http_parser* parser); +static int ShttpOnUrl(http_parser* parser, const char* ptr, size_t length); #if (HTTP_PARSER_VERSION_MAJOR >= 2) && (HTTP_PARSER_VERSION_MINOR >= 2) -static int ShttpOnStatus(http_parser *parser,const char *ptr,size_t length); +static int ShttpOnStatus(http_parser* parser, const char* ptr, size_t length); #else -static int ShttpOnStatus(http_parser *parser); +static int ShttpOnStatus(http_parser* parser); #endif -static int ShttpOnHeaderField(http_parser *parser,const char *ptr,size_t length); -static int ShttpOnValue(http_parser *parser,const char *ptr,size_t length); -static int ShttpOnHeadersComplete(http_parser *parser); -static int ShttpOnBody(http_parser *parser,const char *ptr,size_t length); -static int ShttpOnMessageComplete(http_parser *parser); +static int ShttpOnHeaderField(http_parser* parser, const char* ptr, size_t length); +static int ShttpOnValue(http_parser* parser, const char* ptr, size_t length); +static int ShttpOnHeadersComplete(http_parser* parser); +static int ShttpOnBody(http_parser* parser, const char* ptr, size_t length); +static int ShttpOnMessageComplete(http_parser* parser); #if (HTTP_PARSER_VERSION_MAJOR >= 2) && (HTTP_PARSER_VERSION_MINOR >= 1) -static const struct http_parser_settings HTTP_PARSER_SETTINGS = { - ShttpOnMessageBegin, - ShttpOnUrl, - ShttpOnStatus, - ShttpOnHeaderField, - ShttpOnValue, - ShttpOnHeadersComplete, - ShttpOnBody, - ShttpOnMessageComplete -}; +static const struct http_parser_settings HTTP_PARSER_SETTINGS = { ShttpOnMessageBegin, ShttpOnUrl, ShttpOnStatus, ShttpOnHeaderField, ShttpOnValue, ShttpOnHeadersComplete, ShttpOnBody, ShttpOnMessageComplete }; #else -static const struct http_parser_settings HTTP_PARSER_SETTINGS = { - ShttpOnMessageBegin, - ShttpOnUrl, - ShttpOnHeaderField, - ShttpOnValue, - ShttpOnHeadersComplete, - ShttpOnBody, - ShttpOnMessageComplete -}; +static const struct http_parser_settings HTTP_PARSER_SETTINGS = { ShttpOnMessageBegin, ShttpOnUrl, ShttpOnHeaderField, ShttpOnValue, ShttpOnHeadersComplete, ShttpOnBody, ShttpOnMessageComplete }; #endif -struct HttpPhyHandler -{ - // not used - inline void phyOnDatagram(PhySocket *sock,void **uptr,const struct sockaddr *localAddr,const struct sockaddr *from,void *data,unsigned long len) {} - inline void phyOnTcpAccept(PhySocket *sockL,PhySocket *sockN,void **uptrL,void **uptrN,const struct sockaddr *from) {} +struct HttpPhyHandler { + // not used + inline void phyOnDatagram(PhySocket* sock, void** uptr, const struct sockaddr* localAddr, const struct sockaddr* from, void* data, unsigned long len) + { + } + inline void phyOnTcpAccept(PhySocket* sockL, PhySocket* sockN, void** uptrL, void** uptrN, const struct sockaddr* from) + { + } - inline void phyOnTcpConnect(PhySocket *sock,void **uptr,bool success) - { - if (success) { - phy->setNotifyWritable(sock,true); - } else { - *responseBody = "connection failed"; - error = true; - done = true; - } - } + inline void phyOnTcpConnect(PhySocket* sock, void** uptr, bool success) + { + if (success) { + phy->setNotifyWritable(sock, true); + } + else { + *responseBody = "connection failed"; + error = true; + done = true; + } + } - inline void phyOnTcpClose(PhySocket *sock,void **uptr) - { - done = true; - } + inline void phyOnTcpClose(PhySocket* sock, void** uptr) + { + done = true; + } - inline void phyOnTcpData(PhySocket *sock,void **uptr,void *data,unsigned long len) - { - lastActivity = OSUtils::now(); - http_parser_execute(&parser,&HTTP_PARSER_SETTINGS,(const char *)data,len); - if ((parser.upgrade)||(parser.http_errno != HPE_OK)) - phy->close(sock); - } + inline void phyOnTcpData(PhySocket* sock, void** uptr, void* data, unsigned long len) + { + lastActivity = OSUtils::now(); + http_parser_execute(&parser, &HTTP_PARSER_SETTINGS, (const char*)data, len); + if ((parser.upgrade) || (parser.http_errno != HPE_OK)) + phy->close(sock); + } - inline void phyOnTcpWritable(PhySocket *sock,void **uptr) - { - if (writePtr < (unsigned long)writeBuf.length()) { - long n = phy->streamSend(sock,writeBuf.data() + writePtr,(unsigned long)writeBuf.length() - writePtr,true); - if (n > 0) - writePtr += n; - } - if (writePtr >= (unsigned long)writeBuf.length()) - phy->setNotifyWritable(sock,false); - } + inline void phyOnTcpWritable(PhySocket* sock, void** uptr) + { + if (writePtr < (unsigned long)writeBuf.length()) { + long n = phy->streamSend(sock, writeBuf.data() + writePtr, (unsigned long)writeBuf.length() - writePtr, true); + if (n > 0) + writePtr += n; + } + if (writePtr >= (unsigned long)writeBuf.length()) + phy->setNotifyWritable(sock, false); + } - inline void phyOnFileDescriptorActivity(PhySocket *sock,void **uptr,bool readable,bool writable) {} + inline void phyOnFileDescriptorActivity(PhySocket* sock, void** uptr, bool readable, bool writable) + { + } #ifdef __UNIX_LIKE__ - inline void phyOnUnixAccept(PhySocket *sockL,PhySocket *sockN,void **uptrL,void **uptrN) {} - inline void phyOnUnixClose(PhySocket *sock,void **uptr) {} - inline void phyOnUnixData(PhySocket *sock,void **uptr,void *data,unsigned long len) {} - inline void phyOnUnixWritable(PhySocket *sock,void **uptr) {} -#endif // __UNIX_LIKE__ + inline void phyOnUnixAccept(PhySocket* sockL, PhySocket* sockN, void** uptrL, void** uptrN) + { + } + inline void phyOnUnixClose(PhySocket* sock, void** uptr) + { + } + inline void phyOnUnixData(PhySocket* sock, void** uptr, void* data, unsigned long len) + { + } + inline void phyOnUnixWritable(PhySocket* sock, void** uptr) + { + } +#endif // __UNIX_LIKE__ - http_parser parser; - std::string currentHeaderField; - std::string currentHeaderValue; - unsigned long messageSize; - unsigned long writePtr; - uint64_t lastActivity; - std::string writeBuf; + http_parser parser; + std::string currentHeaderField; + std::string currentHeaderValue; + unsigned long messageSize; + unsigned long writePtr; + uint64_t lastActivity; + std::string writeBuf; - unsigned long maxResponseSize; - std::map *responseHeaders; - std::string *responseBody; - bool error; - bool done; + unsigned long maxResponseSize; + std::map* responseHeaders; + std::string* responseBody; + bool error; + bool done; - Phy *phy; - PhySocket *sock; + Phy* phy; + PhySocket* sock; }; -static int ShttpOnMessageBegin(http_parser *parser) +static int ShttpOnMessageBegin(http_parser* parser) { - return 0; + return 0; } -static int ShttpOnUrl(http_parser *parser,const char *ptr,size_t length) +static int ShttpOnUrl(http_parser* parser, const char* ptr, size_t length) { - return 0; + return 0; } #if (HTTP_PARSER_VERSION_MAJOR >= 2) && (HTTP_PARSER_VERSION_MINOR >= 2) -static int ShttpOnStatus(http_parser *parser,const char *ptr,size_t length) +static int ShttpOnStatus(http_parser* parser, const char* ptr, size_t length) #else -static int ShttpOnStatus(http_parser *parser) +static int ShttpOnStatus(http_parser* parser) #endif { - /* - HttpPhyHandler *hh = reinterpret_cast(parser->data); - hh->messageSize += (unsigned long)length; - if (hh->messageSize > hh->maxResponseSize) - return -1; - */ - return 0; + /* + HttpPhyHandler *hh = reinterpret_cast(parser->data); + hh->messageSize += (unsigned long)length; + if (hh->messageSize > hh->maxResponseSize) + return -1; + */ + return 0; } -static int ShttpOnHeaderField(http_parser *parser,const char *ptr,size_t length) +static int ShttpOnHeaderField(http_parser* parser, const char* ptr, size_t length) { - HttpPhyHandler *hh = reinterpret_cast(parser->data); - hh->messageSize += (unsigned long)length; - if (hh->messageSize > hh->maxResponseSize) - return -1; - if ((hh->currentHeaderField.length())&&(hh->currentHeaderValue.length())) { - (*hh->responseHeaders)[hh->currentHeaderField] = hh->currentHeaderValue; - hh->currentHeaderField = ""; - hh->currentHeaderValue = ""; - } - for(size_t i=0;icurrentHeaderField.push_back(OSUtils::toLower(ptr[i])); - return 0; + HttpPhyHandler* hh = reinterpret_cast(parser->data); + hh->messageSize += (unsigned long)length; + if (hh->messageSize > hh->maxResponseSize) + return -1; + if ((hh->currentHeaderField.length()) && (hh->currentHeaderValue.length())) { + (*hh->responseHeaders)[hh->currentHeaderField] = hh->currentHeaderValue; + hh->currentHeaderField = ""; + hh->currentHeaderValue = ""; + } + for (size_t i = 0; i < length; ++i) + hh->currentHeaderField.push_back(OSUtils::toLower(ptr[i])); + return 0; } -static int ShttpOnValue(http_parser *parser,const char *ptr,size_t length) +static int ShttpOnValue(http_parser* parser, const char* ptr, size_t length) { - HttpPhyHandler *hh = reinterpret_cast(parser->data); - hh->messageSize += (unsigned long)length; - if (hh->messageSize > hh->maxResponseSize) - return -1; - hh->currentHeaderValue.append(ptr,length); - return 0; + HttpPhyHandler* hh = reinterpret_cast(parser->data); + hh->messageSize += (unsigned long)length; + if (hh->messageSize > hh->maxResponseSize) + return -1; + hh->currentHeaderValue.append(ptr, length); + return 0; } -static int ShttpOnHeadersComplete(http_parser *parser) +static int ShttpOnHeadersComplete(http_parser* parser) { - HttpPhyHandler *hh = reinterpret_cast(parser->data); - if ((hh->currentHeaderField.length())&&(hh->currentHeaderValue.length())) - (*hh->responseHeaders)[hh->currentHeaderField] = hh->currentHeaderValue; - return 0; + HttpPhyHandler* hh = reinterpret_cast(parser->data); + if ((hh->currentHeaderField.length()) && (hh->currentHeaderValue.length())) + (*hh->responseHeaders)[hh->currentHeaderField] = hh->currentHeaderValue; + return 0; } -static int ShttpOnBody(http_parser *parser,const char *ptr,size_t length) +static int ShttpOnBody(http_parser* parser, const char* ptr, size_t length) { - HttpPhyHandler *hh = reinterpret_cast(parser->data); - hh->messageSize += (unsigned long)length; - if (hh->messageSize > hh->maxResponseSize) - return -1; - hh->responseBody->append(ptr,length); - return 0; + HttpPhyHandler* hh = reinterpret_cast(parser->data); + hh->messageSize += (unsigned long)length; + if (hh->messageSize > hh->maxResponseSize) + return -1; + hh->responseBody->append(ptr, length); + return 0; } -static int ShttpOnMessageComplete(http_parser *parser) +static int ShttpOnMessageComplete(http_parser* parser) { - HttpPhyHandler *hh = reinterpret_cast(parser->data); - hh->phy->close(hh->sock); - return 0; + HttpPhyHandler* hh = reinterpret_cast(parser->data); + hh->phy->close(hh->sock); + return 0; } -} // anonymous namespace +} // anonymous namespace unsigned int Http::_do( - const char *method, - unsigned long maxResponseSize, - unsigned long timeout, - const struct sockaddr *remoteAddress, - const char *path, - const std::map &requestHeaders, - const void *requestBody, - unsigned long requestBodyLength, - std::map &responseHeaders, - std::string &responseBody) + const char* method, + unsigned long maxResponseSize, + unsigned long timeout, + const struct sockaddr* remoteAddress, + const char* path, + const std::map& requestHeaders, + const void* requestBody, + unsigned long requestBodyLength, + std::map& responseHeaders, + std::string& responseBody) { - try { - responseHeaders.clear(); - responseBody = ""; + try { + responseHeaders.clear(); + responseBody = ""; - HttpPhyHandler handler; + HttpPhyHandler handler; - http_parser_init(&(handler.parser),HTTP_RESPONSE); - handler.parser.data = (void *)&handler; - handler.messageSize = 0; - handler.writePtr = 0; - handler.lastActivity = OSUtils::now(); + http_parser_init(&(handler.parser), HTTP_RESPONSE); + handler.parser.data = (void*)&handler; + handler.messageSize = 0; + handler.writePtr = 0; + handler.lastActivity = OSUtils::now(); - try { - char tmp[1024]; - OSUtils::ztsnprintf(tmp,sizeof(tmp),"%s %s HTTP/1.1\r\n",method,path); - handler.writeBuf.append(tmp); - for(std::map::const_iterator h(requestHeaders.begin());h!=requestHeaders.end();++h) { - OSUtils::ztsnprintf(tmp,sizeof(tmp),"%s: %s\r\n",h->first.c_str(),h->second.c_str()); - handler.writeBuf.append(tmp); - } - handler.writeBuf.append("\r\n"); - if ((requestBody)&&(requestBodyLength)) - handler.writeBuf.append((const char *)requestBody,requestBodyLength); - } catch ( ... ) { - responseBody = "request too large"; - return 0; - } + try { + char tmp[1024]; + OSUtils::ztsnprintf(tmp, sizeof(tmp), "%s %s HTTP/1.1\r\n", method, path); + handler.writeBuf.append(tmp); + for (std::map::const_iterator h(requestHeaders.begin()); h != requestHeaders.end(); ++h) { + OSUtils::ztsnprintf(tmp, sizeof(tmp), "%s: %s\r\n", h->first.c_str(), h->second.c_str()); + handler.writeBuf.append(tmp); + } + handler.writeBuf.append("\r\n"); + if ((requestBody) && (requestBodyLength)) + handler.writeBuf.append((const char*)requestBody, requestBodyLength); + } + catch (...) { + responseBody = "request too large"; + return 0; + } - if (maxResponseSize) { - handler.maxResponseSize = maxResponseSize; - } else { - handler.maxResponseSize = 2147483647; - } - handler.responseHeaders = &responseHeaders; - handler.responseBody = &responseBody; - handler.error = false; - handler.done = false; + if (maxResponseSize) { + handler.maxResponseSize = maxResponseSize; + } + else { + handler.maxResponseSize = 2147483647; + } + handler.responseHeaders = &responseHeaders; + handler.responseBody = &responseBody; + handler.error = false; + handler.done = false; - Phy phy(&handler,true,true); + Phy phy(&handler, true, true); - bool instantConnect = false; - handler.phy = &phy; - handler.sock = phy.tcpConnect((const struct sockaddr *)remoteAddress,instantConnect,(void *)0,true); - if (!handler.sock) { - responseBody = "connection failed (2)"; - return 0; - } + bool instantConnect = false; + handler.phy = &phy; + handler.sock = phy.tcpConnect((const struct sockaddr*)remoteAddress, instantConnect, (void*)0, true); + if (! handler.sock) { + responseBody = "connection failed (2)"; + return 0; + } - while (!handler.done) { - phy.poll(timeout / 2); - if ((timeout)&&((unsigned long)(OSUtils::now() - handler.lastActivity) > timeout)) { - phy.close(handler.sock); - responseBody = "timed out"; - return 0; - } - } + while (! handler.done) { + phy.poll(timeout / 2); + if ((timeout) && ((unsigned long)(OSUtils::now() - handler.lastActivity) > timeout)) { + phy.close(handler.sock); + responseBody = "timed out"; + return 0; + } + } - return ((handler.error) ? 0 : ((handler.parser.http_errno != HPE_OK) ? 0 : handler.parser.status_code)); - } catch (std::exception &exc) { - responseBody = exc.what(); - return 0; - } catch ( ... ) { - responseBody = "unknown exception"; - return 0; - } + return ((handler.error) ? 0 : ((handler.parser.http_errno != HPE_OK) ? 0 : handler.parser.status_code)); + } + catch (std::exception& exc) { + responseBody = exc.what(); + return 0; + } + catch (...) { + responseBody = "unknown exception"; + return 0; + } } -} // namespace ZeroTier +} // namespace ZeroTier diff --git a/osdep/Http.hpp b/osdep/Http.hpp index 6e669ab2..8b95302d 100644 --- a/osdep/Http.hpp +++ b/osdep/Http.hpp @@ -14,21 +14,21 @@ #ifndef ZT_HTTP_HPP #define ZT_HTTP_HPP -#include #include #include +#include #if defined(_WIN32) || defined(_WIN64) +#include #include #include -#include #else -#include -#include -#include -#include #include #include +#include +#include +#include +#include #endif namespace ZeroTier { @@ -36,147 +36,106 @@ namespace ZeroTier { /** * Simple synchronous HTTP client used for updater and cli */ -class Http -{ -public: - /** - * Make HTTP GET request - * - * The caller must set all headers, including Host. - * - * @return HTTP status code or 0 on error (responseBody will contain error message) - */ - static inline unsigned int GET( - unsigned long maxResponseSize, - unsigned long timeout, - const struct sockaddr *remoteAddress, - const char *path, - const std::map &requestHeaders, - std::map &responseHeaders, - std::string &responseBody) - { - return _do( - "GET", - maxResponseSize, - timeout, - remoteAddress, - path, - requestHeaders, - (const void *)0, - 0, - responseHeaders, - responseBody); - } +class Http { + public: + /** + * Make HTTP GET request + * + * The caller must set all headers, including Host. + * + * @return HTTP status code or 0 on error (responseBody will contain error message) + */ + static inline unsigned int + GET(unsigned long maxResponseSize, + unsigned long timeout, + const struct sockaddr* remoteAddress, + const char* path, + const std::map& requestHeaders, + std::map& responseHeaders, + std::string& responseBody) + { + return _do("GET", maxResponseSize, timeout, remoteAddress, path, requestHeaders, (const void*)0, 0, responseHeaders, responseBody); + } - /** - * Make HTTP DELETE request - * - * The caller must set all headers, including Host. - * - * @return HTTP status code or 0 on error (responseBody will contain error message) - */ - static inline unsigned int DEL( - unsigned long maxResponseSize, - unsigned long timeout, - const struct sockaddr *remoteAddress, - const char *path, - const std::map &requestHeaders, - std::map &responseHeaders, - std::string &responseBody) - { - return _do( - "DELETE", - maxResponseSize, - timeout, - remoteAddress, - path, - requestHeaders, - (const void *)0, - 0, - responseHeaders, - responseBody); - } + /** + * Make HTTP DELETE request + * + * The caller must set all headers, including Host. + * + * @return HTTP status code or 0 on error (responseBody will contain error message) + */ + static inline unsigned int + DEL(unsigned long maxResponseSize, + unsigned long timeout, + const struct sockaddr* remoteAddress, + const char* path, + const std::map& requestHeaders, + std::map& responseHeaders, + std::string& responseBody) + { + return _do("DELETE", maxResponseSize, timeout, remoteAddress, path, requestHeaders, (const void*)0, 0, responseHeaders, responseBody); + } - /** - * Make HTTP POST request - * - * It is the responsibility of the caller to set all headers. With POST, the - * Content-Length and Content-Type headers must be set or the POST will not - * work. - * - * @return HTTP status code or 0 on error (responseBody will contain error message) - */ - static inline unsigned int POST( - unsigned long maxResponseSize, - unsigned long timeout, - const struct sockaddr *remoteAddress, - const char *path, - const std::map &requestHeaders, - const void *postData, - unsigned long postDataLength, - std::map &responseHeaders, - std::string &responseBody) - { - return _do( - "POST", - maxResponseSize, - timeout, - remoteAddress, - path, - requestHeaders, - postData, - postDataLength, - responseHeaders, - responseBody); - } + /** + * Make HTTP POST request + * + * It is the responsibility of the caller to set all headers. With POST, the + * Content-Length and Content-Type headers must be set or the POST will not + * work. + * + * @return HTTP status code or 0 on error (responseBody will contain error message) + */ + static inline unsigned int POST( + unsigned long maxResponseSize, + unsigned long timeout, + const struct sockaddr* remoteAddress, + const char* path, + const std::map& requestHeaders, + const void* postData, + unsigned long postDataLength, + std::map& responseHeaders, + std::string& responseBody) + { + return _do("POST", maxResponseSize, timeout, remoteAddress, path, requestHeaders, postData, postDataLength, responseHeaders, responseBody); + } - /** - * Make HTTP PUT request - * - * It is the responsibility of the caller to set all headers. With PUT, the - * Content-Length and Content-Type headers must be set or the PUT will not - * work. - * - * @return HTTP status code or 0 on error (responseBody will contain error message) - */ - static inline unsigned int PUT( - unsigned long maxResponseSize, - unsigned long timeout, - const struct sockaddr *remoteAddress, - const char *path, - const std::map &requestHeaders, - const void *postData, - unsigned long postDataLength, - std::map &responseHeaders, - std::string &responseBody) - { - return _do( - "PUT", - maxResponseSize, - timeout, - remoteAddress, - path, - requestHeaders, - postData, - postDataLength, - responseHeaders, - responseBody); - } + /** + * Make HTTP PUT request + * + * It is the responsibility of the caller to set all headers. With PUT, the + * Content-Length and Content-Type headers must be set or the PUT will not + * work. + * + * @return HTTP status code or 0 on error (responseBody will contain error message) + */ + static inline unsigned int + PUT(unsigned long maxResponseSize, + unsigned long timeout, + const struct sockaddr* remoteAddress, + const char* path, + const std::map& requestHeaders, + const void* postData, + unsigned long postDataLength, + std::map& responseHeaders, + std::string& responseBody) + { + return _do("PUT", maxResponseSize, timeout, remoteAddress, path, requestHeaders, postData, postDataLength, responseHeaders, responseBody); + } -private: - static unsigned int _do( - const char *method, - unsigned long maxResponseSize, - unsigned long timeout, - const struct sockaddr *remoteAddress, - const char *path, - const std::map &requestHeaders, - const void *requestBody, - unsigned long requestBodyLength, - std::map &responseHeaders, - std::string &responseBody); + private: + static unsigned int + _do(const char* method, + unsigned long maxResponseSize, + unsigned long timeout, + const struct sockaddr* remoteAddress, + const char* path, + const std::map& requestHeaders, + const void* requestBody, + unsigned long requestBodyLength, + std::map& responseHeaders, + std::string& responseBody); }; -} // namespace ZeroTier +} // namespace ZeroTier #endif diff --git a/osdep/LinuxEthernetTap.cpp b/osdep/LinuxEthernetTap.cpp index 14929d17..f4c50b60 100644 --- a/osdep/LinuxEthernetTap.cpp +++ b/osdep/LinuxEthernetTap.cpp @@ -19,42 +19,39 @@ #ifdef __LINUX__ -#include "../node/Utils.hpp" -#include "../node/Mutex.hpp" #include "../node/Dictionary.hpp" -#include "OSUtils.hpp" +#include "../node/Mutex.hpp" +#include "../node/Utils.hpp" #include "LinuxEthernetTap.hpp" #include "LinuxNetLink.hpp" +#include "OSUtils.hpp" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include #include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include #include - -#include +#include +#include +#include +#include #include - +#include +#include +#include #ifndef IFNAMSIZ #define IFNAMSIZ 16 @@ -63,7 +60,7 @@ #define ZT_TAP_BUF_SIZE (1024 * 16) // ff:ff:ff:ff:ff:ff with no ADI -static const ZeroTier::MulticastGroup _blindWildcardMulticastGroup(ZeroTier::MAC(0xff),0); +static const ZeroTier::MulticastGroup _blindWildcardMulticastGroup(ZeroTier::MAC(0xff), 0); namespace ZeroTier { @@ -72,531 +69,531 @@ namespace ZeroTier { // the tap devices. // // Returns true if the kernel major version is < 3 -bool isOldLinuxKernel() { - struct utsname buffer; - char *p; - long ver[16]; - int i = 0; - if (uname(&buffer) != 0) { - perror("uname"); - exit(EXIT_FAILURE); - } +bool isOldLinuxKernel() +{ + struct utsname buffer; + char* p; + long ver[16]; + int i = 0; + if (uname(&buffer) != 0) { + perror("uname"); + exit(EXIT_FAILURE); + } - p = buffer.release; + p = buffer.release; while (*p) { if (isdigit(*p)) { ver[i] = strtol(p, &p, 10); i++; - } else { + } + else { p++; } } - return ver[0] < 3; + return ver[0] < 3; } -static const char _base32_chars[32] = { 'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','2','3','4','5','6','7' }; -static void _base32_5_to_8(const uint8_t *in,char *out) +static const char _base32_chars[32] = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '2', '3', '4', '5', '6', '7' }; +static void _base32_5_to_8(const uint8_t* in, char* out) { - out[0] = _base32_chars[(in[0]) >> 3]; - out[1] = _base32_chars[(in[0] & 0x07) << 2 | (in[1] & 0xc0) >> 6]; - out[2] = _base32_chars[(in[1] & 0x3e) >> 1]; - out[3] = _base32_chars[(in[1] & 0x01) << 4 | (in[2] & 0xf0) >> 4]; - out[4] = _base32_chars[(in[2] & 0x0f) << 1 | (in[3] & 0x80) >> 7]; - out[5] = _base32_chars[(in[3] & 0x7c) >> 2]; - out[6] = _base32_chars[(in[3] & 0x03) << 3 | (in[4] & 0xe0) >> 5]; - out[7] = _base32_chars[(in[4] & 0x1f)]; + out[0] = _base32_chars[(in[0]) >> 3]; + out[1] = _base32_chars[(in[0] & 0x07) << 2 | (in[1] & 0xc0) >> 6]; + out[2] = _base32_chars[(in[1] & 0x3e) >> 1]; + out[3] = _base32_chars[(in[1] & 0x01) << 4 | (in[2] & 0xf0) >> 4]; + out[4] = _base32_chars[(in[2] & 0x0f) << 1 | (in[3] & 0x80) >> 7]; + out[5] = _base32_chars[(in[3] & 0x7c) >> 2]; + out[6] = _base32_chars[(in[3] & 0x03) << 3 | (in[4] & 0xe0) >> 5]; + out[7] = _base32_chars[(in[4] & 0x1f)]; } LinuxEthernetTap::LinuxEthernetTap( - const char *homePath, - unsigned int concurrency, - bool pinning, - const MAC &mac, - unsigned int mtu, - unsigned int metric, - uint64_t nwid, - const char *friendlyName, - void (*handler)(void *,void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int), - void *arg) : - _handler(handler), - _arg(arg), - _nwid(nwid), - _mac(mac), - _homePath(homePath), - _mtu(mtu), - _fd(0), - _enabled(true), - _run(true), - _lastIfAddrsUpdate(0) + const char* homePath, + unsigned int concurrency, + bool pinning, + const MAC& mac, + unsigned int mtu, + unsigned int metric, + uint64_t nwid, + const char* friendlyName, + void (*handler)(void*, void*, uint64_t, const MAC&, const MAC&, unsigned int, unsigned int, const void*, unsigned int), + void* arg) + : _handler(handler) + , _arg(arg) + , _nwid(nwid) + , _mac(mac) + , _homePath(homePath) + , _mtu(mtu) + , _fd(0) + , _enabled(true) + , _run(true) + , _lastIfAddrsUpdate(0) { - static std::mutex s_tapCreateLock; - char procpath[128],nwids[32]; - struct stat sbuf; + static std::mutex s_tapCreateLock; + char procpath[128], nwids[32]; + struct stat sbuf; + // Create only one tap at a time globally. + std::lock_guard tapCreateLock(s_tapCreateLock); - // Create only one tap at a time globally. - std::lock_guard tapCreateLock(s_tapCreateLock); + // Make sure Linux netlink is initialized. + (void)LinuxNetLink::getInstance(); - // Make sure Linux netlink is initialized. - (void)LinuxNetLink::getInstance(); + OSUtils::ztsnprintf(nwids, sizeof(nwids), "%.16llx", nwid); - OSUtils::ztsnprintf(nwids,sizeof(nwids),"%.16llx",nwid); + _fd = ::open("/dev/net/tun", O_RDWR); + if (_fd <= 0) { + _fd = ::open("/dev/tun", O_RDWR); + if (_fd <= 0) + throw std::runtime_error(std::string("could not open TUN/TAP device: ") + strerror(errno)); + } - _fd = ::open("/dev/net/tun",O_RDWR); - if (_fd <= 0) { - _fd = ::open("/dev/tun",O_RDWR); - if (_fd <= 0) - throw std::runtime_error(std::string("could not open TUN/TAP device: ") + strerror(errno)); - } + struct ifreq ifr; + memset(&ifr, 0, sizeof(ifr)); - struct ifreq ifr; - memset(&ifr,0,sizeof(ifr)); + // Restore device names from legacy devicemap, but for new devices we use a base32-based + // canonical device name. + std::map globalDeviceMap; + FILE* devmapf = fopen((_homePath + ZT_PATH_SEPARATOR_S + "devicemap").c_str(), "r"); + if (devmapf) { + char buf[256]; + while (fgets(buf, sizeof(buf), devmapf)) { + char* x = (char*)0; + char* y = (char*)0; + char* saveptr = (char*)0; + for (char* f = Utils::stok(buf, "\r\n=", &saveptr); (f); f = Utils::stok((char*)0, "\r\n=", &saveptr)) { + if (! x) + x = f; + else if (! y) + y = f; + else + break; + } + if ((x) && (y) && (x[0]) && (y[0])) + globalDeviceMap[x] = y; + } + fclose(devmapf); + } + bool recalledDevice = false; + std::map::const_iterator gdmEntry = globalDeviceMap.find(nwids); + if (gdmEntry != globalDeviceMap.end()) { + Utils::scopy(ifr.ifr_name, sizeof(ifr.ifr_name), gdmEntry->second.c_str()); + OSUtils::ztsnprintf(procpath, sizeof(procpath), "/proc/sys/net/ipv4/conf/%s", ifr.ifr_name); + recalledDevice = (stat(procpath, &sbuf) != 0); + } - // Restore device names from legacy devicemap, but for new devices we use a base32-based - // canonical device name. - std::map globalDeviceMap; - FILE *devmapf = fopen((_homePath + ZT_PATH_SEPARATOR_S + "devicemap").c_str(),"r"); - if (devmapf) { - char buf[256]; - while (fgets(buf,sizeof(buf),devmapf)) { - char *x = (char *)0; - char *y = (char *)0; - char *saveptr = (char *)0; - for(char *f=Utils::stok(buf,"\r\n=",&saveptr);(f);f=Utils::stok((char *)0,"\r\n=",&saveptr)) { - if (!x) x = f; - else if (!y) y = f; - else break; - } - if ((x)&&(y)&&(x[0])&&(y[0])) - globalDeviceMap[x] = y; - } - fclose(devmapf); - } - bool recalledDevice = false; - std::map::const_iterator gdmEntry = globalDeviceMap.find(nwids); - if (gdmEntry != globalDeviceMap.end()) { - Utils::scopy(ifr.ifr_name,sizeof(ifr.ifr_name),gdmEntry->second.c_str()); - OSUtils::ztsnprintf(procpath,sizeof(procpath),"/proc/sys/net/ipv4/conf/%s",ifr.ifr_name); - recalledDevice = (stat(procpath,&sbuf) != 0); - } - - if (!recalledDevice) { + if (! recalledDevice) { #ifdef __SYNOLOGY__ - int devno = 50; - do { - OSUtils::ztsnprintf(ifr.ifr_name,sizeof(ifr.ifr_name),"eth%d",devno++); - OSUtils::ztsnprintf(procpath,sizeof(procpath),"/proc/sys/net/ipv4/conf/%s",ifr.ifr_name); - } while (stat(procpath,&sbuf) == 0); // try zt#++ until we find one that does not exist + int devno = 50; + do { + OSUtils::ztsnprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "eth%d", devno++); + OSUtils::ztsnprintf(procpath, sizeof(procpath), "/proc/sys/net/ipv4/conf/%s", ifr.ifr_name); + } while (stat(procpath, &sbuf) == 0); // try zt#++ until we find one that does not exist #else - uint64_t trial = 0; // incremented in the very unlikely event of a name collision with another network - do { - const uint64_t nwid40 = (nwid ^ (nwid >> 24)) + trial++; - uint8_t tmp2[5]; - char tmp3[11]; - tmp2[0] = (uint8_t)((nwid40 >> 32) & 0xff); - tmp2[1] = (uint8_t)((nwid40 >> 24) & 0xff); - tmp2[2] = (uint8_t)((nwid40 >> 16) & 0xff); - tmp2[3] = (uint8_t)((nwid40 >> 8) & 0xff); - tmp2[4] = (uint8_t)(nwid40 & 0xff); - tmp3[0] = 'z'; - tmp3[1] = 't'; - _base32_5_to_8(tmp2,tmp3 + 2); - tmp3[10] = (char)0; - memcpy(ifr.ifr_name,tmp3,11); - OSUtils::ztsnprintf(procpath,sizeof(procpath),"/proc/sys/net/ipv4/conf/%s",ifr.ifr_name); - } while (stat(procpath,&sbuf) == 0); + uint64_t trial = 0; // incremented in the very unlikely event of a name collision with another network + do { + const uint64_t nwid40 = (nwid ^ (nwid >> 24)) + trial++; + uint8_t tmp2[5]; + char tmp3[11]; + tmp2[0] = (uint8_t)((nwid40 >> 32) & 0xff); + tmp2[1] = (uint8_t)((nwid40 >> 24) & 0xff); + tmp2[2] = (uint8_t)((nwid40 >> 16) & 0xff); + tmp2[3] = (uint8_t)((nwid40 >> 8) & 0xff); + tmp2[4] = (uint8_t)(nwid40 & 0xff); + tmp3[0] = 'z'; + tmp3[1] = 't'; + _base32_5_to_8(tmp2, tmp3 + 2); + tmp3[10] = (char)0; + memcpy(ifr.ifr_name, tmp3, 11); + OSUtils::ztsnprintf(procpath, sizeof(procpath), "/proc/sys/net/ipv4/conf/%s", ifr.ifr_name); + } while (stat(procpath, &sbuf) == 0); #endif - } + } - ifr.ifr_flags = IFF_TAP | IFF_NO_PI; - if (ioctl(_fd,TUNSETIFF,(void *)&ifr) < 0) { - ::close(_fd); - throw std::runtime_error("unable to configure TUN/TAP device for TAP operation"); - } + ifr.ifr_flags = IFF_TAP | IFF_NO_PI; + if (ioctl(_fd, TUNSETIFF, (void*)&ifr) < 0) { + ::close(_fd); + throw std::runtime_error("unable to configure TUN/TAP device for TAP operation"); + } - ::ioctl(_fd,TUNSETPERSIST,0); // valgrind may generate a false alarm here - _dev = ifr.ifr_name; - ::fcntl(_fd,F_SETFD,fcntl(_fd,F_GETFD) | FD_CLOEXEC); + ::ioctl(_fd, TUNSETPERSIST, 0); // valgrind may generate a false alarm here + _dev = ifr.ifr_name; + ::fcntl(_fd, F_SETFD, fcntl(_fd, F_GETFD) | FD_CLOEXEC); - (void)::pipe(_shutdownSignalPipe); + (void)::pipe(_shutdownSignalPipe); - for (unsigned int i = 0; i < concurrency; ++i) { - _rxThreads.push_back(std::thread([this, i, concurrency, pinning] { + for (unsigned int i = 0; i < concurrency; ++i) { + _rxThreads.push_back(std::thread([this, i, concurrency, pinning] { + if (pinning) { + int pinCore = i % concurrency; + fprintf(stderr, "Pinning tap thread %d to core %d\n", i, pinCore); + pthread_t self = pthread_self(); + cpu_set_t cpuset; + CPU_ZERO(&cpuset); + CPU_SET(pinCore, &cpuset); + int rc = pthread_setaffinity_np(self, sizeof(cpu_set_t), &cpuset); + if (rc != 0) { + fprintf(stderr, "Failed to pin tap thread %d to core %d: %s\n", i, pinCore, strerror(errno)); + exit(1); + } + } - if (pinning) { - int pinCore = i % concurrency; - fprintf(stderr, "Pinning tap thread %d to core %d\n", i, pinCore); - pthread_t self = pthread_self(); - cpu_set_t cpuset; - CPU_ZERO(&cpuset); - CPU_SET(pinCore, &cpuset); - int rc = pthread_setaffinity_np(self, sizeof(cpu_set_t), &cpuset); - if (rc != 0) - { - fprintf(stderr, "Failed to pin tap thread %d to core %d: %s\n", i, pinCore, strerror(errno)); - exit(1); - } - } + uint8_t b[ZT_TAP_BUF_SIZE]; + fd_set readfds, nullfds; + int n, nfds, r; + if (i == 0) { + struct ifreq ifr; + memset(&ifr, 0, sizeof(ifr)); + strcpy(ifr.ifr_name, _dev.c_str()); - uint8_t b[ZT_TAP_BUF_SIZE]; - fd_set readfds, nullfds; - int n, nfds, r; - if (i == 0) { - struct ifreq ifr; - memset(&ifr, 0, sizeof(ifr)); - strcpy(ifr.ifr_name, _dev.c_str()); + const int sock = socket(AF_INET, SOCK_DGRAM, 0); + if (sock <= 0) + return; - const int sock = socket(AF_INET, SOCK_DGRAM, 0); - if (sock <= 0) - return; + if (ioctl(sock, SIOCGIFFLAGS, (void*)&ifr) < 0) { + ::close(sock); + printf("WARNING: ioctl() failed setting up Linux tap device (bring interface up)\n"); + return; + } - if (ioctl(sock, SIOCGIFFLAGS, (void*)&ifr) < 0) { - ::close(sock); - printf("WARNING: ioctl() failed setting up Linux tap device (bring interface up)\n"); - return; - } + ifr.ifr_ifru.ifru_hwaddr.sa_family = ARPHRD_ETHER; + _mac.copyTo(ifr.ifr_ifru.ifru_hwaddr.sa_data, 6); + if (ioctl(sock, SIOCSIFHWADDR, (void*)&ifr) < 0) { + ::close(sock); + printf("WARNING: ioctl() failed setting up Linux tap device (set MAC)\n"); + return; + } - ifr.ifr_ifru.ifru_hwaddr.sa_family = ARPHRD_ETHER; - _mac.copyTo(ifr.ifr_ifru.ifru_hwaddr.sa_data, 6); - if (ioctl(sock, SIOCSIFHWADDR, (void*)&ifr) < 0) { - ::close(sock); - printf("WARNING: ioctl() failed setting up Linux tap device (set MAC)\n"); - return; - } + usleep(100000); - usleep(100000); + if (isOldLinuxKernel()) { + ifr.ifr_ifru.ifru_mtu = (int)_mtu; + if (ioctl(sock, SIOCSIFMTU, (void*)&ifr) < 0) { + ::close(sock); + printf("WARNING: ioctl() failed setting up Linux tap device (set MTU)\n"); + return; + } - if (isOldLinuxKernel()) { - ifr.ifr_ifru.ifru_mtu = (int)_mtu; - if (ioctl(sock, SIOCSIFMTU, (void*)&ifr) < 0) { - ::close(sock); - printf("WARNING: ioctl() failed setting up Linux tap device (set MTU)\n"); - return; - } + usleep(100000); + } - usleep(100000); - } + ifr.ifr_flags |= IFF_MULTICAST; + ifr.ifr_flags |= IFF_UP; + if (ioctl(sock, SIOCSIFFLAGS, (void*)&ifr) < 0) { + ::close(sock); + printf("WARNING: ioctl() failed setting up Linux tap device (bring interface up)\n"); + return; + } - ifr.ifr_flags |= IFF_MULTICAST; - ifr.ifr_flags |= IFF_UP; - if (ioctl(sock, SIOCSIFFLAGS, (void*)&ifr) < 0) { - ::close(sock); - printf("WARNING: ioctl() failed setting up Linux tap device (bring interface up)\n"); - return; - } + usleep(100000); - usleep(100000); + if (! isOldLinuxKernel()) { + ifr.ifr_ifru.ifru_hwaddr.sa_family = ARPHRD_ETHER; + _mac.copyTo(ifr.ifr_ifru.ifru_hwaddr.sa_data, 6); + if (ioctl(sock, SIOCSIFHWADDR, (void*)&ifr) < 0) { + ::close(sock); + printf("WARNING: ioctl() failed setting up Linux tap device (set MAC)\n"); + return; + } - if (! isOldLinuxKernel()) { - ifr.ifr_ifru.ifru_hwaddr.sa_family = ARPHRD_ETHER; - _mac.copyTo(ifr.ifr_ifru.ifru_hwaddr.sa_data, 6); - if (ioctl(sock, SIOCSIFHWADDR, (void*)&ifr) < 0) { - ::close(sock); - printf("WARNING: ioctl() failed setting up Linux tap device (set MAC)\n"); - return; - } + ifr.ifr_ifru.ifru_mtu = (int)_mtu; + if (ioctl(sock, SIOCSIFMTU, (void*)&ifr) < 0) { + ::close(sock); + printf("WARNING: ioctl() failed setting up Linux tap device (set MTU)\n"); + return; + } + } - ifr.ifr_ifru.ifru_mtu = (int)_mtu; - if (ioctl(sock, SIOCSIFMTU, (void*)&ifr) < 0) { - ::close(sock); - printf("WARNING: ioctl() failed setting up Linux tap device (set MTU)\n"); - return; - } - } + fcntl(_fd, F_SETFL, O_NONBLOCK); - fcntl(_fd, F_SETFL, O_NONBLOCK); + ::close(sock); + } - ::close(sock); - } + if (! _run) { + return; + } - if (! _run) { - return; - } + FD_ZERO(&readfds); + FD_ZERO(&nullfds); + nfds = (int)std::max(_shutdownSignalPipe[0], _fd) + 1; - FD_ZERO(&readfds); - FD_ZERO(&nullfds); - nfds = (int)std::max(_shutdownSignalPipe[0], _fd) + 1; + r = 0; + for (;;) { + FD_SET(_shutdownSignalPipe[0], &readfds); + FD_SET(_fd, &readfds); + select(nfds, &readfds, &nullfds, &nullfds, (struct timeval*)0); - r = 0; - for (;;) { - FD_SET(_shutdownSignalPipe[0], &readfds); - FD_SET(_fd, &readfds); - select(nfds, &readfds, &nullfds, &nullfds, (struct timeval*)0); + if (FD_ISSET(_shutdownSignalPipe[0], &readfds)) { + break; + } + if (FD_ISSET(_fd, &readfds)) { + for (;;) { + // read until there are no more packets, then return to outer select() loop + n = (int)::read(_fd, b + r, ZT_TAP_BUF_SIZE - r); + if (n > 0) { + // Some tap drivers like to send the ethernet frame and the + // payload in two chunks, so handle that by accumulating + // data until we have at least a frame. + r += n; + if (r > 14) { + if (r > ((int)_mtu + 14)) // sanity check for weird TAP behavior on some platforms + r = _mtu + 14; - if (FD_ISSET(_shutdownSignalPipe[0], &readfds)) { - break; - } - if (FD_ISSET(_fd, &readfds)) { - for (;;) { - // read until there are no more packets, then return to outer select() loop - n = (int)::read(_fd, b + r, ZT_TAP_BUF_SIZE - r); - if (n > 0) { - // Some tap drivers like to send the ethernet frame and the - // payload in two chunks, so handle that by accumulating - // data until we have at least a frame. - r += n; - if (r > 14) { - if (r > ((int)_mtu + 14)) // sanity check for weird TAP behavior on some platforms - r = _mtu + 14; + if (_enabled) { + MAC to(b, 6), from(b + 6, 6); + unsigned int etherType = Utils::ntoh(((const uint16_t*)b)[6]); + _handler(_arg, nullptr, _nwid, from, to, etherType, 0, (const void*)(b + 14), (unsigned int)(r - 14)); + } - if (_enabled) { - MAC to(b, 6), from(b + 6, 6); - unsigned int etherType = Utils::ntoh(((const uint16_t*)b)[6]); - _handler(_arg, nullptr, _nwid, from, to, etherType, 0, (const void*)(b + 14), (unsigned int)(r - 14)); - } - - r = 0; - } - } - else { - r = 0; - break; - } - } - } - } - })); - } + r = 0; + } + } + else { + r = 0; + break; + } + } + } + } + })); + } } LinuxEthernetTap::~LinuxEthernetTap() { - _run = false; - (void)::write(_shutdownSignalPipe[1],"\0",1); - ::close(_fd); - ::close(_shutdownSignalPipe[0]); - ::close(_shutdownSignalPipe[1]); - for (std::thread &t : _rxThreads) { - t.join(); - } + _run = false; + (void)::write(_shutdownSignalPipe[1], "\0", 1); + ::close(_fd); + ::close(_shutdownSignalPipe[0]); + ::close(_shutdownSignalPipe[1]); + for (std::thread& t : _rxThreads) { + t.join(); + } } void LinuxEthernetTap::setEnabled(bool en) { - _enabled = en; + _enabled = en; } bool LinuxEthernetTap::enabled() const { - return _enabled; + return _enabled; } -static bool ___removeIp(const std::string &_dev,const InetAddress &ip) +static bool ___removeIp(const std::string& _dev, const InetAddress& ip) { - LinuxNetLink::getInstance().removeAddress(ip, _dev.c_str()); - return true; + LinuxNetLink::getInstance().removeAddress(ip, _dev.c_str()); + return true; } bool LinuxEthernetTap::addIps(std::vector ips) { #ifdef __SYNOLOGY__ - std::string filepath = "/etc/sysconfig/network-scripts/ifcfg-"+_dev; - std::string cfg_contents = "DEVICE="+_dev+"\nBOOTPROTO=static"; - int ip4=0,ip6=0,ip4_tot=0,ip6_tot=0; + std::string filepath = "/etc/sysconfig/network-scripts/ifcfg-" + _dev; + std::string cfg_contents = "DEVICE=" + _dev + "\nBOOTPROTO=static"; + int ip4 = 0, ip6 = 0, ip4_tot = 0, ip6_tot = 0; - for(int i=0; i<(int)ips.size(); i++) { - if (ips[i].isV4()) - ip4_tot++; - else - ip6_tot++; - } - // Assemble and write contents of ifcfg-dev file - for(int i=0; i<(int)ips.size(); i++) { - if (ips[i].isV4()) { - char iptmp[64],iptmp2[64]; - std::string numstr4 = ip4_tot > 1 ? std::to_string(ip4) : ""; - cfg_contents += "\nIPADDR"+numstr4+"="+ips[i].toIpString(iptmp) - + "\nNETMASK"+numstr4+"="+ips[i].netmask().toIpString(iptmp2)+"\n"; - ip4++; - } else { - char iptmp[64],iptmp2[64]; - std::string numstr6 = ip6_tot > 1 ? std::to_string(ip6) : ""; - cfg_contents += "\nIPV6ADDR"+numstr6+"="+ips[i].toIpString(iptmp) - + "\nNETMASK"+numstr6+"="+ips[i].netmask().toIpString(iptmp2)+"\n"; - ip6++; - } - } - OSUtils::writeFile(filepath.c_str(), cfg_contents.c_str(), cfg_contents.length()); - // Finally, add IPs - for(int i=0; i<(int)ips.size(); i++){ - LinuxNetLink::getInstance().addAddress(ips[i], _dev.c_str()); - } - return true; -#endif // __SYNOLOGY__ - return false; + for (int i = 0; i < (int)ips.size(); i++) { + if (ips[i].isV4()) + ip4_tot++; + else + ip6_tot++; + } + // Assemble and write contents of ifcfg-dev file + for (int i = 0; i < (int)ips.size(); i++) { + if (ips[i].isV4()) { + char iptmp[64], iptmp2[64]; + std::string numstr4 = ip4_tot > 1 ? std::to_string(ip4) : ""; + cfg_contents += "\nIPADDR" + numstr4 + "=" + ips[i].toIpString(iptmp) + "\nNETMASK" + numstr4 + "=" + ips[i].netmask().toIpString(iptmp2) + "\n"; + ip4++; + } + else { + char iptmp[64], iptmp2[64]; + std::string numstr6 = ip6_tot > 1 ? std::to_string(ip6) : ""; + cfg_contents += "\nIPV6ADDR" + numstr6 + "=" + ips[i].toIpString(iptmp) + "\nNETMASK" + numstr6 + "=" + ips[i].netmask().toIpString(iptmp2) + "\n"; + ip6++; + } + } + OSUtils::writeFile(filepath.c_str(), cfg_contents.c_str(), cfg_contents.length()); + // Finally, add IPs + for (int i = 0; i < (int)ips.size(); i++) { + LinuxNetLink::getInstance().addAddress(ips[i], _dev.c_str()); + } + return true; +#endif // __SYNOLOGY__ + return false; } -bool LinuxEthernetTap::addIp(const InetAddress &ip) +bool LinuxEthernetTap::addIp(const InetAddress& ip) { - if (!ip) - return false; + if (! ip) + return false; - std::vector allIps(ips()); - if (std::binary_search(allIps.begin(),allIps.end(),ip)) - return true; + std::vector allIps(ips()); + if (std::binary_search(allIps.begin(), allIps.end(), ip)) + return true; - // Remove and reconfigure if address is the same but netmask is different - for(std::vector::iterator i(allIps.begin());i!=allIps.end();++i) { - if (i->ipsEqual(ip)) - ___removeIp(_dev,*i); - } + // Remove and reconfigure if address is the same but netmask is different + for (std::vector::iterator i(allIps.begin()); i != allIps.end(); ++i) { + if (i->ipsEqual(ip)) + ___removeIp(_dev, *i); + } - LinuxNetLink::getInstance().addAddress(ip, _dev.c_str()); + LinuxNetLink::getInstance().addAddress(ip, _dev.c_str()); - return true; + return true; } -bool LinuxEthernetTap::removeIp(const InetAddress &ip) +bool LinuxEthernetTap::removeIp(const InetAddress& ip) { - if (!ip) - return true; - std::vector allIps(ips()); - if (std::find(allIps.begin(),allIps.end(),ip) != allIps.end()) { - if (___removeIp(_dev,ip)) - return true; - } - return false; + if (! ip) + return true; + std::vector allIps(ips()); + if (std::find(allIps.begin(), allIps.end(), ip) != allIps.end()) { + if (___removeIp(_dev, ip)) + return true; + } + return false; } std::vector LinuxEthernetTap::ips() const { + uint64_t now = OSUtils::now(); - uint64_t now = OSUtils::now(); + if ((now - _lastIfAddrsUpdate) <= GETIFADDRS_CACHE_TIME) { + return _ifaddrs; + } + _lastIfAddrsUpdate = now; - if ((now - _lastIfAddrsUpdate) <= GETIFADDRS_CACHE_TIME) { - return _ifaddrs; - } - _lastIfAddrsUpdate = now; + struct ifaddrs* ifa = (struct ifaddrs*)0; + if (getifaddrs(&ifa)) + return std::vector(); - struct ifaddrs *ifa = (struct ifaddrs *)0; - if (getifaddrs(&ifa)) - return std::vector(); + std::vector r; - std::vector r; + struct ifaddrs* p = ifa; + while (p) { + if ((! strcmp(p->ifa_name, _dev.c_str())) && (p->ifa_addr) && (p->ifa_netmask) && (p->ifa_addr->sa_family == p->ifa_netmask->sa_family)) { + switch (p->ifa_addr->sa_family) { + case AF_INET: { + struct sockaddr_in* sin = (struct sockaddr_in*)p->ifa_addr; + struct sockaddr_in* nm = (struct sockaddr_in*)p->ifa_netmask; + r.push_back(InetAddress(&(sin->sin_addr.s_addr), 4, Utils::countBits((uint32_t)nm->sin_addr.s_addr))); + } break; + case AF_INET6: { + struct sockaddr_in6* sin = (struct sockaddr_in6*)p->ifa_addr; + struct sockaddr_in6* nm = (struct sockaddr_in6*)p->ifa_netmask; + uint32_t b[4]; + memcpy(b, nm->sin6_addr.s6_addr, sizeof(b)); + r.push_back(InetAddress(sin->sin6_addr.s6_addr, 16, Utils::countBits(b[0]) + Utils::countBits(b[1]) + Utils::countBits(b[2]) + Utils::countBits(b[3]))); + } break; + } + } + p = p->ifa_next; + } - struct ifaddrs *p = ifa; - while (p) { - if ((!strcmp(p->ifa_name,_dev.c_str()))&&(p->ifa_addr)&&(p->ifa_netmask)&&(p->ifa_addr->sa_family == p->ifa_netmask->sa_family)) { - switch(p->ifa_addr->sa_family) { - case AF_INET: { - struct sockaddr_in *sin = (struct sockaddr_in *)p->ifa_addr; - struct sockaddr_in *nm = (struct sockaddr_in *)p->ifa_netmask; - r.push_back(InetAddress(&(sin->sin_addr.s_addr),4,Utils::countBits((uint32_t)nm->sin_addr.s_addr))); - } break; - case AF_INET6: { - struct sockaddr_in6 *sin = (struct sockaddr_in6 *)p->ifa_addr; - struct sockaddr_in6 *nm = (struct sockaddr_in6 *)p->ifa_netmask; - uint32_t b[4]; - memcpy(b,nm->sin6_addr.s6_addr,sizeof(b)); - r.push_back(InetAddress(sin->sin6_addr.s6_addr,16,Utils::countBits(b[0]) + Utils::countBits(b[1]) + Utils::countBits(b[2]) + Utils::countBits(b[3]))); - } break; - } - } - p = p->ifa_next; - } + if (ifa) + freeifaddrs(ifa); - if (ifa) - freeifaddrs(ifa); + std::sort(r.begin(), r.end()); + r.erase(std::unique(r.begin(), r.end()), r.end()); - std::sort(r.begin(),r.end()); - r.erase(std::unique(r.begin(),r.end()),r.end()); + _ifaddrs = r; - _ifaddrs = r; - - return r; + return r; } -void LinuxEthernetTap::put(const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len) +void LinuxEthernetTap::put(const MAC& from, const MAC& to, unsigned int etherType, const void* data, unsigned int len) { - char putBuf[ZT_MAX_MTU + 64]; - if ((_fd > 0)&&(len <= _mtu)&&(_enabled)) { - to.copyTo(putBuf,6); - from.copyTo(putBuf + 6,6); - *((uint16_t *)(putBuf + 12)) = htons((uint16_t)etherType); - memcpy(putBuf + 14,data,len); - len += 14; - (void)::write(_fd,putBuf,len); - } + char putBuf[ZT_MAX_MTU + 64]; + if ((_fd > 0) && (len <= _mtu) && (_enabled)) { + to.copyTo(putBuf, 6); + from.copyTo(putBuf + 6, 6); + *((uint16_t*)(putBuf + 12)) = htons((uint16_t)etherType); + memcpy(putBuf + 14, data, len); + len += 14; + (void)::write(_fd, putBuf, len); + } } std::string LinuxEthernetTap::deviceName() const { - return _dev; + return _dev; } -void LinuxEthernetTap::setFriendlyName(const char *friendlyName) +void LinuxEthernetTap::setFriendlyName(const char* friendlyName) { } -void LinuxEthernetTap::scanMulticastGroups(std::vector &added,std::vector &removed) +void LinuxEthernetTap::scanMulticastGroups(std::vector& added, std::vector& removed) { - char *ptr,*ptr2; - unsigned char mac[6]; - std::vector newGroups; + char *ptr, *ptr2; + unsigned char mac[6]; + std::vector newGroups; - int fd = ::open("/proc/net/dev_mcast",O_RDONLY); - if (fd > 0) { - char buf[131072]; - int n = (int)::read(fd,buf,sizeof(buf)); - if ((n > 0)&&(n < (int)sizeof(buf))) { - buf[n] = (char)0; - for(char *l=strtok_r(buf,"\r\n",&ptr);(l);l=strtok_r((char *)0,"\r\n",&ptr)) { - int fno = 0; - char *devname = (char *)0; - char *mcastmac = (char *)0; - for(char *f=strtok_r(l," \t",&ptr2);(f);f=strtok_r((char *)0," \t",&ptr2)) { - if (fno == 1) - devname = f; - else if (fno == 4) - mcastmac = f; - ++fno; - } - if ((devname)&&(!strcmp(devname,_dev.c_str()))&&(mcastmac)&&(Utils::unhex(mcastmac,mac,6) == 6)) - newGroups.push_back(MulticastGroup(MAC(mac,6),0)); - } - } - ::close(fd); - } + int fd = ::open("/proc/net/dev_mcast", O_RDONLY); + if (fd > 0) { + char buf[131072]; + int n = (int)::read(fd, buf, sizeof(buf)); + if ((n > 0) && (n < (int)sizeof(buf))) { + buf[n] = (char)0; + for (char* l = strtok_r(buf, "\r\n", &ptr); (l); l = strtok_r((char*)0, "\r\n", &ptr)) { + int fno = 0; + char* devname = (char*)0; + char* mcastmac = (char*)0; + for (char* f = strtok_r(l, " \t", &ptr2); (f); f = strtok_r((char*)0, " \t", &ptr2)) { + if (fno == 1) + devname = f; + else if (fno == 4) + mcastmac = f; + ++fno; + } + if ((devname) && (! strcmp(devname, _dev.c_str())) && (mcastmac) && (Utils::unhex(mcastmac, mac, 6) == 6)) + newGroups.push_back(MulticastGroup(MAC(mac, 6), 0)); + } + } + ::close(fd); + } - std::vector allIps(ips()); - for(std::vector::iterator ip(allIps.begin());ip!=allIps.end();++ip) - newGroups.push_back(MulticastGroup::deriveMulticastGroupForAddressResolution(*ip)); + std::vector allIps(ips()); + for (std::vector::iterator ip(allIps.begin()); ip != allIps.end(); ++ip) + newGroups.push_back(MulticastGroup::deriveMulticastGroupForAddressResolution(*ip)); - std::sort(newGroups.begin(),newGroups.end()); - newGroups.erase(std::unique(newGroups.begin(),newGroups.end()),newGroups.end()); + std::sort(newGroups.begin(), newGroups.end()); + newGroups.erase(std::unique(newGroups.begin(), newGroups.end()), newGroups.end()); - for(std::vector::iterator m(newGroups.begin());m!=newGroups.end();++m) { - if (!std::binary_search(_multicastGroups.begin(),_multicastGroups.end(),*m)) - added.push_back(*m); - } - for(std::vector::iterator m(_multicastGroups.begin());m!=_multicastGroups.end();++m) { - if (!std::binary_search(newGroups.begin(),newGroups.end(),*m)) - removed.push_back(*m); - } + for (std::vector::iterator m(newGroups.begin()); m != newGroups.end(); ++m) { + if (! std::binary_search(_multicastGroups.begin(), _multicastGroups.end(), *m)) + added.push_back(*m); + } + for (std::vector::iterator m(_multicastGroups.begin()); m != _multicastGroups.end(); ++m) { + if (! std::binary_search(newGroups.begin(), newGroups.end(), *m)) + removed.push_back(*m); + } - _multicastGroups.swap(newGroups); + _multicastGroups.swap(newGroups); } void LinuxEthernetTap::setMtu(unsigned int mtu) { - if (_mtu != mtu) { - _mtu = mtu; - int sock = socket(AF_INET,SOCK_DGRAM,0); - if (sock > 0) { - struct ifreq ifr; - memset(&ifr,0,sizeof(ifr)); - strcpy(ifr.ifr_name,_dev.c_str()); - ifr.ifr_ifru.ifru_mtu = (int)mtu; - if (ioctl(sock,SIOCSIFMTU,(void *)&ifr) < 0) { - printf("WARNING: ioctl() failed updating existing Linux tap device (set MTU)\n"); - } - close(sock); - } - } + if (_mtu != mtu) { + _mtu = mtu; + int sock = socket(AF_INET, SOCK_DGRAM, 0); + if (sock > 0) { + struct ifreq ifr; + memset(&ifr, 0, sizeof(ifr)); + strcpy(ifr.ifr_name, _dev.c_str()); + ifr.ifr_ifru.ifru_mtu = (int)mtu; + if (ioctl(sock, SIOCSIFMTU, (void*)&ifr) < 0) { + printf("WARNING: ioctl() failed updating existing Linux tap device (set MTU)\n"); + } + close(sock); + } + } } -} // namespace ZeroTier +} // namespace ZeroTier -#endif // __LINUX__ +#endif // __LINUX__ diff --git a/osdep/LinuxEthernetTap.hpp b/osdep/LinuxEthernetTap.hpp index 41e29982..31e683e1 100644 --- a/osdep/LinuxEthernetTap.hpp +++ b/osdep/LinuxEthernetTap.hpp @@ -14,70 +14,71 @@ #ifndef ZT_LINUXETHERNETTAP_HPP #define ZT_LINUXETHERNETTAP_HPP +#include "../node/MulticastGroup.hpp" +#include "BlockingQueue.hpp" +#include "EthernetTap.hpp" + +#include +#include +#include +#include #include #include - #include -#include -#include -#include -#include #include -#include -#include "../node/MulticastGroup.hpp" -#include "EthernetTap.hpp" -#include "BlockingQueue.hpp" +#include namespace ZeroTier { -class LinuxEthernetTap : public EthernetTap -{ -public: - LinuxEthernetTap( - const char *homePath, - unsigned int concurrency, - bool pinning, - const MAC &mac, - unsigned int mtu, - unsigned int metric, - uint64_t nwid, - const char *friendlyName, - void (*handler)(void *,void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int), - void *arg); +class LinuxEthernetTap : public EthernetTap { + public: + LinuxEthernetTap( + const char* homePath, + unsigned int concurrency, + bool pinning, + const MAC& mac, + unsigned int mtu, + unsigned int metric, + uint64_t nwid, + const char* friendlyName, + void (*handler)(void*, void*, uint64_t, const MAC&, const MAC&, unsigned int, unsigned int, const void*, unsigned int), + void* arg); - virtual ~LinuxEthernetTap(); + virtual ~LinuxEthernetTap(); - virtual void setEnabled(bool en); - virtual bool enabled() const; - virtual bool addIp(const InetAddress &ip); - virtual bool addIps(std::vector ips); - virtual bool removeIp(const InetAddress &ip); - virtual std::vector ips() const; - virtual void put(const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len); - virtual std::string deviceName() const; - virtual void setFriendlyName(const char *friendlyName); - virtual void scanMulticastGroups(std::vector &added,std::vector &removed); - virtual void setMtu(unsigned int mtu); - virtual void setDns(const char *domain, const std::vector &servers) {} + virtual void setEnabled(bool en); + virtual bool enabled() const; + virtual bool addIp(const InetAddress& ip); + virtual bool addIps(std::vector ips); + virtual bool removeIp(const InetAddress& ip); + virtual std::vector ips() const; + virtual void put(const MAC& from, const MAC& to, unsigned int etherType, const void* data, unsigned int len); + virtual std::string deviceName() const; + virtual void setFriendlyName(const char* friendlyName); + virtual void scanMulticastGroups(std::vector& added, std::vector& removed); + virtual void setMtu(unsigned int mtu); + virtual void setDns(const char* domain, const std::vector& servers) + { + } -private: - void (*_handler)(void *,void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int); - void *_arg; - uint64_t _nwid; - MAC _mac; - std::string _homePath; - std::string _dev; - std::vector _multicastGroups; - unsigned int _mtu; - int _fd; - int _shutdownSignalPipe[2]; - std::atomic_bool _enabled; - std::atomic_bool _run; - mutable std::vector _ifaddrs; - mutable uint64_t _lastIfAddrsUpdate; - std::vector _rxThreads; + private: + void (*_handler)(void*, void*, uint64_t, const MAC&, const MAC&, unsigned int, unsigned int, const void*, unsigned int); + void* _arg; + uint64_t _nwid; + MAC _mac; + std::string _homePath; + std::string _dev; + std::vector _multicastGroups; + unsigned int _mtu; + int _fd; + int _shutdownSignalPipe[2]; + std::atomic_bool _enabled; + std::atomic_bool _run; + mutable std::vector _ifaddrs; + mutable uint64_t _lastIfAddrsUpdate; + std::vector _rxThreads; }; -} // namespace ZeroTier +} // namespace ZeroTier #endif diff --git a/osdep/LinuxNetLink.cpp b/osdep/LinuxNetLink.cpp index 00b79b1a..f15558ba 100644 --- a/osdep/LinuxNetLink.cpp +++ b/osdep/LinuxNetLink.cpp @@ -15,14 +15,14 @@ #include -//#define ZT_NETLINK_TRACE +// #define ZT_NETLINK_TRACE #ifdef __LINUX__ #include "LinuxNetLink.hpp" -#include #include +#include #ifndef IFNAMSIZ #define IFNAMSIZ 16 @@ -32,1175 +32,1181 @@ const int ZT_RTE_METRIC = 5000; namespace ZeroTier { struct nl_route_req { - struct nlmsghdr nl; - struct rtmsg rt; - char buf[8192]; + struct nlmsghdr nl; + struct rtmsg rt; + char buf[8192]; }; struct nl_if_req { - struct nlmsghdr nl; - struct ifinfomsg ifa; - char buf[8192]; + struct nlmsghdr nl; + struct ifinfomsg ifa; + char buf[8192]; }; struct nl_adr_req { - struct nlmsghdr nl; - struct ifaddrmsg ifa; - char buf[8192]; + struct nlmsghdr nl; + struct ifaddrmsg ifa; + char buf[8192]; }; -LinuxNetLink::LinuxNetLink() - : _t() - , _running(false) - , _seq(0) - , _interfaces() - , _if_m() - , _fd(socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) - , _la({0}) +LinuxNetLink::LinuxNetLink() : _t(), _running(false), _seq(0), _interfaces(), _if_m(), _fd(socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE)), _la({ 0 }) { - // set socket timeout to 1 sec so we're not permablocking recv() calls - _setSocketTimeout(_fd, 1); + // set socket timeout to 1 sec so we're not permablocking recv() calls + _setSocketTimeout(_fd, 1); - _la.nl_family = AF_NETLINK; - _la.nl_pid = 0; //getpid()+1; - _la.nl_groups = RTMGRP_LINK|RTMGRP_IPV4_IFADDR|RTMGRP_IPV6_IFADDR|RTMGRP_IPV4_ROUTE|RTMGRP_IPV6_ROUTE|RTMGRP_NOTIFY; - if (bind(_fd, (struct sockaddr*)&_la, sizeof(_la))) { - fprintf(stderr, "Error connecting to RTNETLINK: %s\n", strerror(errno)); - ::exit(1); - } + _la.nl_family = AF_NETLINK; + _la.nl_pid = 0; // getpid()+1; + _la.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR | RTMGRP_IPV6_IFADDR | RTMGRP_IPV4_ROUTE | RTMGRP_IPV6_ROUTE | RTMGRP_NOTIFY; + if (bind(_fd, (struct sockaddr*)&_la, sizeof(_la))) { + fprintf(stderr, "Error connecting to RTNETLINK: %s\n", strerror(errno)); + ::exit(1); + } - _requestIPv4Routes(); - _requestIPv6Routes(); - _requestInterfaceList(); + _requestIPv4Routes(); + _requestIPv6Routes(); + _requestInterfaceList(); - _running = true; - _t = Thread::start(this); + _running = true; + _t = Thread::start(this); } LinuxNetLink::~LinuxNetLink() { - _running = false; - Thread::join(_t); - ::close(_fd); + _running = false; + Thread::join(_t); + ::close(_fd); } void LinuxNetLink::_setSocketTimeout(int fd, int seconds) { - struct timeval tv; - tv.tv_sec = seconds; - tv.tv_usec = 0; - if(setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, (const char*)&tv, sizeof(tv)) != 0) { + struct timeval tv; + tv.tv_sec = seconds; + tv.tv_usec = 0; + if (setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, (const char*)&tv, sizeof(tv)) != 0) { #ifdef ZT_NETLINK_TRACE - fprintf(stderr, "setsockopt failed: %s\n", strerror(errno)); + fprintf(stderr, "setsockopt failed: %s\n", strerror(errno)); #endif - } + } } #define ZT_NL_BUF_SIZE 16384 int LinuxNetLink::_doRecv(int fd) { - char *buf = nullptr; - if (posix_memalign((void **)&buf,16,ZT_NL_BUF_SIZE) != 0) { - fprintf(stderr,"malloc failed!\n"); - ::exit(1); - } - if (!buf) { - fprintf(stderr,"malloc failed!\n"); - ::exit(1); - } + char* buf = nullptr; + if (posix_memalign((void**)&buf, 16, ZT_NL_BUF_SIZE) != 0) { + fprintf(stderr, "malloc failed!\n"); + ::exit(1); + } + if (! buf) { + fprintf(stderr, "malloc failed!\n"); + ::exit(1); + } - char *p = NULL; - struct nlmsghdr *nlp; - int nll = 0; - int rtn = 0; - p = buf; + char* p = NULL; + struct nlmsghdr* nlp; + int nll = 0; + int rtn = 0; + p = buf; - for(;;) { - rtn = recv(fd, p, ZT_NL_BUF_SIZE - nll, 0); + for (;;) { + rtn = recv(fd, p, ZT_NL_BUF_SIZE - nll, 0); - if (rtn > 0) { - nlp = (struct nlmsghdr *)p; + if (rtn > 0) { + nlp = (struct nlmsghdr*)p; - if(nlp->nlmsg_type == NLMSG_ERROR && (nlp->nlmsg_flags & NLM_F_ACK) != NLM_F_ACK) { - struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(nlp); - if (err->error != 0) { + if (nlp->nlmsg_type == NLMSG_ERROR && (nlp->nlmsg_flags & NLM_F_ACK) != NLM_F_ACK) { + struct nlmsgerr* err = (struct nlmsgerr*)NLMSG_DATA(nlp); + if (err->error != 0) { #ifdef ZT_NETLINK_TRACE - fprintf(stderr, "rtnetlink error: %s\n", strerror(-(err->error))); + fprintf(stderr, "rtnetlink error: %s\n", strerror(-(err->error))); #endif - } - p = buf; - nll = 0; - break; - } + } + p = buf; + nll = 0; + break; + } - if (nlp->nlmsg_type == NLMSG_NOOP) { - break; - } + if (nlp->nlmsg_type == NLMSG_NOOP) { + break; + } - if( (nlp->nlmsg_flags & NLM_F_MULTI) == NLM_F_MULTI || (nlp->nlmsg_type == NLMSG_DONE)) - { - if (nlp->nlmsg_type == NLMSG_DONE) { - _processMessage(nlp, nll); - p = buf; - nll = 0; - break; - } - p += rtn; - nll += rtn; - } + if ((nlp->nlmsg_flags & NLM_F_MULTI) == NLM_F_MULTI || (nlp->nlmsg_type == NLMSG_DONE)) { + if (nlp->nlmsg_type == NLMSG_DONE) { + _processMessage(nlp, nll); + p = buf; + nll = 0; + break; + } + p += rtn; + nll += rtn; + } - if (nlp->nlmsg_type == NLMSG_OVERRUN) { + if (nlp->nlmsg_type == NLMSG_OVERRUN) { #ifdef ZT_NETLINK_TRACE - fprintf(stderr, "NLMSG_OVERRUN: Data lost\n"); + fprintf(stderr, "NLMSG_OVERRUN: Data lost\n"); #endif - p = buf; - nll = 0; - break; - } + p = buf; + nll = 0; + break; + } - nll += rtn; + nll += rtn; - _processMessage(nlp, nll); + _processMessage(nlp, nll); - p = buf; - nll = 0; - break; - } else { - break; - } - } + p = buf; + nll = 0; + break; + } + else { + break; + } + } - free(buf); + free(buf); - return rtn; + return rtn; } void LinuxNetLink::threadMain() throw() { - int rtn = 0; - while(_running) { - rtn = _doRecv(_fd); - if (rtn <= 0) { - Thread::sleep(250); - continue; - } - } + int rtn = 0; + while (_running) { + rtn = _doRecv(_fd); + if (rtn <= 0) { + Thread::sleep(250); + continue; + } + } } -void LinuxNetLink::_processMessage(struct nlmsghdr *nlp, int nll) +void LinuxNetLink::_processMessage(struct nlmsghdr* nlp, int nll) { - for(; NLMSG_OK(nlp, nll); nlp=NLMSG_NEXT(nlp, nll)) - { - switch(nlp->nlmsg_type) - { - case RTM_NEWLINK: - _linkAdded(nlp); - break; - case RTM_DELLINK: - _linkDeleted(nlp); - break; - case RTM_NEWADDR: - _ipAddressAdded(nlp); - break; - case RTM_DELADDR: - _ipAddressDeleted(nlp); - break; - case RTM_NEWROUTE: - _routeAdded(nlp); - break; - case RTM_DELROUTE: - _routeDeleted(nlp); - break; - default: - break; - } - } + for (; NLMSG_OK(nlp, nll); nlp = NLMSG_NEXT(nlp, nll)) { + switch (nlp->nlmsg_type) { + case RTM_NEWLINK: + _linkAdded(nlp); + break; + case RTM_DELLINK: + _linkDeleted(nlp); + break; + case RTM_NEWADDR: + _ipAddressAdded(nlp); + break; + case RTM_DELADDR: + _ipAddressDeleted(nlp); + break; + case RTM_NEWROUTE: + _routeAdded(nlp); + break; + case RTM_DELROUTE: + _routeDeleted(nlp); + break; + default: + break; + } + } } -void LinuxNetLink::_ipAddressAdded(struct nlmsghdr *nlp) +void LinuxNetLink::_ipAddressAdded(struct nlmsghdr* nlp) { #ifdef ZT_NETLINK_TRACE - struct ifaddrmsg *ifap = (struct ifaddrmsg *)NLMSG_DATA(nlp); - struct rtattr *rtap = (struct rtattr *)IFA_RTA(ifap); - int ifal = IFA_PAYLOAD(nlp); + struct ifaddrmsg* ifap = (struct ifaddrmsg*)NLMSG_DATA(nlp); + struct rtattr* rtap = (struct rtattr*)IFA_RTA(ifap); + int ifal = IFA_PAYLOAD(nlp); - char addr[40] = {0}; - char local[40] = {0}; - char label[40] = {0}; - char bcast[40] = {0}; + char addr[40] = { 0 }; + char local[40] = { 0 }; + char label[40] = { 0 }; + char bcast[40] = { 0 }; - for(;RTA_OK(rtap, ifal); rtap=RTA_NEXT(rtap,ifal)) - { - switch(rtap->rta_type) { - case IFA_ADDRESS: - inet_ntop(ifap->ifa_family, RTA_DATA(rtap), addr, 40); - break; - case IFA_LOCAL: - inet_ntop(ifap->ifa_family, RTA_DATA(rtap), local, 40); - break; - case IFA_LABEL: - memcpy(label, RTA_DATA(rtap), 40); - break; - case IFA_BROADCAST: - inet_ntop(ifap->ifa_family, RTA_DATA(rtap), bcast, 40); - break; - } - } + for (; RTA_OK(rtap, ifal); rtap = RTA_NEXT(rtap, ifal)) { + switch (rtap->rta_type) { + case IFA_ADDRESS: + inet_ntop(ifap->ifa_family, RTA_DATA(rtap), addr, 40); + break; + case IFA_LOCAL: + inet_ntop(ifap->ifa_family, RTA_DATA(rtap), local, 40); + break; + case IFA_LABEL: + memcpy(label, RTA_DATA(rtap), 40); + break; + case IFA_BROADCAST: + inet_ntop(ifap->ifa_family, RTA_DATA(rtap), bcast, 40); + break; + } + } - fprintf(stderr,"Added IP Address %s local: %s label: %s broadcast: %s\n", addr, local, label, bcast); + fprintf(stderr, "Added IP Address %s local: %s label: %s broadcast: %s\n", addr, local, label, bcast); #endif } -void LinuxNetLink::_ipAddressDeleted(struct nlmsghdr *nlp) +void LinuxNetLink::_ipAddressDeleted(struct nlmsghdr* nlp) { #ifdef ZT_NETLINK_TRACE - struct ifaddrmsg *ifap = (struct ifaddrmsg *)NLMSG_DATA(nlp); - struct rtattr *rtap = (struct rtattr *)IFA_RTA(ifap); - int ifal = IFA_PAYLOAD(nlp); + struct ifaddrmsg* ifap = (struct ifaddrmsg*)NLMSG_DATA(nlp); + struct rtattr* rtap = (struct rtattr*)IFA_RTA(ifap); + int ifal = IFA_PAYLOAD(nlp); - char addr[40] = {0}; - char local[40] = {0}; - char label[40] = {0}; - char bcast[40] = {0}; + char addr[40] = { 0 }; + char local[40] = { 0 }; + char label[40] = { 0 }; + char bcast[40] = { 0 }; - for(;RTA_OK(rtap, ifal); rtap=RTA_NEXT(rtap,ifal)) - { - switch(rtap->rta_type) { - case IFA_ADDRESS: - inet_ntop(ifap->ifa_family, RTA_DATA(rtap), addr, 40); - break; - case IFA_LOCAL: - inet_ntop(ifap->ifa_family, RTA_DATA(rtap), local, 40); - break; - case IFA_LABEL: - memcpy(label, RTA_DATA(rtap), 40); - break; - case IFA_BROADCAST: - inet_ntop(ifap->ifa_family, RTA_DATA(rtap), bcast, 40); - break; - } - } + for (; RTA_OK(rtap, ifal); rtap = RTA_NEXT(rtap, ifal)) { + switch (rtap->rta_type) { + case IFA_ADDRESS: + inet_ntop(ifap->ifa_family, RTA_DATA(rtap), addr, 40); + break; + case IFA_LOCAL: + inet_ntop(ifap->ifa_family, RTA_DATA(rtap), local, 40); + break; + case IFA_LABEL: + memcpy(label, RTA_DATA(rtap), 40); + break; + case IFA_BROADCAST: + inet_ntop(ifap->ifa_family, RTA_DATA(rtap), bcast, 40); + break; + } + } - fprintf(stderr, "Removed IP Address %s local: %s label: %s broadcast: %s\n", addr, local, label, bcast); + fprintf(stderr, "Removed IP Address %s local: %s label: %s broadcast: %s\n", addr, local, label, bcast); #endif } -void LinuxNetLink::_routeAdded(struct nlmsghdr *nlp) +void LinuxNetLink::_routeAdded(struct nlmsghdr* nlp) { - char dsts[40] = {0}; - char gws[40] = {0}; - char srcs[40] = {0}; - char ifs[16] = {0}; - char ms[24] = {0}; + char dsts[40] = { 0 }; + char gws[40] = { 0 }; + char srcs[40] = { 0 }; + char ifs[16] = { 0 }; + char ms[24] = { 0 }; - struct rtmsg *rtp = (struct rtmsg *)NLMSG_DATA(nlp); - struct rtattr *rtap = (struct rtattr *)RTM_RTA(rtp); - int rtl = RTM_PAYLOAD(nlp); + struct rtmsg* rtp = (struct rtmsg*)NLMSG_DATA(nlp); + struct rtattr* rtap = (struct rtattr*)RTM_RTA(rtp); + int rtl = RTM_PAYLOAD(nlp); - Route r; - bool wecare = false; + Route r; + bool wecare = false; - for(;RTA_OK(rtap, rtl); rtap=RTA_NEXT(rtap, rtl)) - { - switch(rtap->rta_type) - { - case RTA_DST: - switch(rtp->rtm_family) { - case AF_INET: - inet_ntop(rtp->rtm_family, RTA_DATA(rtap), dsts, 24); - r.target.set(RTA_DATA(rtap), 4, 0); - wecare = true; - break; - case AF_INET6: - inet_ntop(rtp->rtm_family, RTA_DATA(rtap), dsts, 24); - r.target.set(RTA_DATA(rtap), 16, 0); - wecare = true; - break; - } - break; - case RTA_SRC: - switch(rtp->rtm_family) { - case AF_INET: - inet_ntop(rtp->rtm_family, RTA_DATA(rtap), srcs, 24); - r.src.set(RTA_DATA(rtap), 4, 0); - wecare = true; - break; - case AF_INET6: - inet_ntop(rtp->rtm_family, RTA_DATA(rtap), srcs, 24); - r.src.set(RTA_DATA(rtap), 16, 0); - wecare = true; - break; - } - break; - case RTA_GATEWAY: - switch(rtp->rtm_family) { - case AF_INET: - inet_ntop(rtp->rtm_family, RTA_DATA(rtap), gws, 24); - r.via.set(RTA_DATA(rtap), 4, 0); - wecare = true; - break; - case AF_INET6: - inet_ntop(rtp->rtm_family, RTA_DATA(rtap), gws, 24); - r.via.set(RTA_DATA(rtap), 16, 0); - wecare = true; - break; - } - break; - case RTA_OIF: - switch(rtp->rtm_family) { - case AF_INET: - r.ifidx = *((int*)RTA_DATA(rtap)); - wecare = true; - break; - case AF_INET6: - r.ifidx = *((int*)RTA_DATA(rtap)); - wecare = true; - break; - } - sprintf(ifs, "%d", *((int*)RTA_DATA(rtap))); - break; - } - } + for (; RTA_OK(rtap, rtl); rtap = RTA_NEXT(rtap, rtl)) { + switch (rtap->rta_type) { + case RTA_DST: + switch (rtp->rtm_family) { + case AF_INET: + inet_ntop(rtp->rtm_family, RTA_DATA(rtap), dsts, 24); + r.target.set(RTA_DATA(rtap), 4, 0); + wecare = true; + break; + case AF_INET6: + inet_ntop(rtp->rtm_family, RTA_DATA(rtap), dsts, 24); + r.target.set(RTA_DATA(rtap), 16, 0); + wecare = true; + break; + } + break; + case RTA_SRC: + switch (rtp->rtm_family) { + case AF_INET: + inet_ntop(rtp->rtm_family, RTA_DATA(rtap), srcs, 24); + r.src.set(RTA_DATA(rtap), 4, 0); + wecare = true; + break; + case AF_INET6: + inet_ntop(rtp->rtm_family, RTA_DATA(rtap), srcs, 24); + r.src.set(RTA_DATA(rtap), 16, 0); + wecare = true; + break; + } + break; + case RTA_GATEWAY: + switch (rtp->rtm_family) { + case AF_INET: + inet_ntop(rtp->rtm_family, RTA_DATA(rtap), gws, 24); + r.via.set(RTA_DATA(rtap), 4, 0); + wecare = true; + break; + case AF_INET6: + inet_ntop(rtp->rtm_family, RTA_DATA(rtap), gws, 24); + r.via.set(RTA_DATA(rtap), 16, 0); + wecare = true; + break; + } + break; + case RTA_OIF: + switch (rtp->rtm_family) { + case AF_INET: + r.ifidx = *((int*)RTA_DATA(rtap)); + wecare = true; + break; + case AF_INET6: + r.ifidx = *((int*)RTA_DATA(rtap)); + wecare = true; + break; + } + sprintf(ifs, "%d", *((int*)RTA_DATA(rtap))); + break; + } + } - if (wecare) { - Mutex::Lock rl(_routes_m); - _routes[r.target].insert(r); - } + if (wecare) { + Mutex::Lock rl(_routes_m); + _routes[r.target].insert(r); + } #ifdef ZT_NETLINK_TRACE - sprintf(ms, "%d", rtp->rtm_dst_len); - fprintf(stderr, "Route Added: dst %s/%s gw %s src %s if %s\n", dsts, ms, gws, srcs, ifs); + sprintf(ms, "%d", rtp->rtm_dst_len); + fprintf(stderr, "Route Added: dst %s/%s gw %s src %s if %s\n", dsts, ms, gws, srcs, ifs); #endif } -void LinuxNetLink::_routeDeleted(struct nlmsghdr *nlp) +void LinuxNetLink::_routeDeleted(struct nlmsghdr* nlp) { - char dsts[40] = {0}; - char gws[40] = {0}; - char srcs[40] = {0}; - char ifs[16] = {0}; - char ms[24] = {0}; + char dsts[40] = { 0 }; + char gws[40] = { 0 }; + char srcs[40] = { 0 }; + char ifs[16] = { 0 }; + char ms[24] = { 0 }; - struct rtmsg *rtp = (struct rtmsg *) NLMSG_DATA(nlp); - struct rtattr *rtap = (struct rtattr *)RTM_RTA(rtp); - int rtl = RTM_PAYLOAD(nlp); + struct rtmsg* rtp = (struct rtmsg*)NLMSG_DATA(nlp); + struct rtattr* rtap = (struct rtattr*)RTM_RTA(rtp); + int rtl = RTM_PAYLOAD(nlp); - Route r; - bool wecare = false; + Route r; + bool wecare = false; - for(;RTA_OK(rtap, rtl); rtap=RTA_NEXT(rtap, rtl)) - { - switch(rtap->rta_type) - { - case RTA_DST: - switch(rtp->rtm_family) { - case AF_INET: - inet_ntop(rtp->rtm_family, RTA_DATA(rtap), dsts, 24); - r.target.set(RTA_DATA(rtap), 4, 0); - wecare = true; - break; - case AF_INET6: - inet_ntop(rtp->rtm_family, RTA_DATA(rtap), dsts, 24); - r.target.set(RTA_DATA(rtap), 16, 0); - wecare = true; - break; - } - break; - case RTA_SRC: - switch(rtp->rtm_family) { - case AF_INET: - inet_ntop(rtp->rtm_family, RTA_DATA(rtap), srcs, 24); - r.src.set(RTA_DATA(rtap), 4, 0); - wecare = true; - break; - case AF_INET6: - inet_ntop(rtp->rtm_family, RTA_DATA(rtap), srcs, 24); - r.src.set(RTA_DATA(rtap), 16, 0); - wecare = true; - break; - } - break; - case RTA_GATEWAY: - switch(rtp->rtm_family) { - case AF_INET: - inet_ntop(rtp->rtm_family, RTA_DATA(rtap), gws, 24); - r.via.set(RTA_DATA(rtap), 4, 0); - wecare = true; - break; - case AF_INET6: - inet_ntop(rtp->rtm_family, RTA_DATA(rtap), gws, 24); - r.via.set(RTA_DATA(rtap), 16, 0); - wecare = true; - break; - } - break; - case RTA_OIF: - switch(rtp->rtm_family) { - case AF_INET: - r.ifidx = *((int*)RTA_DATA(rtap)); - wecare = true; - break; - case AF_INET6: - r.ifidx = *((int*)RTA_DATA(rtap)); - wecare = true; - break; - } - sprintf(ifs, "%d", *((int*)RTA_DATA(rtap))); - break; - } - } + for (; RTA_OK(rtap, rtl); rtap = RTA_NEXT(rtap, rtl)) { + switch (rtap->rta_type) { + case RTA_DST: + switch (rtp->rtm_family) { + case AF_INET: + inet_ntop(rtp->rtm_family, RTA_DATA(rtap), dsts, 24); + r.target.set(RTA_DATA(rtap), 4, 0); + wecare = true; + break; + case AF_INET6: + inet_ntop(rtp->rtm_family, RTA_DATA(rtap), dsts, 24); + r.target.set(RTA_DATA(rtap), 16, 0); + wecare = true; + break; + } + break; + case RTA_SRC: + switch (rtp->rtm_family) { + case AF_INET: + inet_ntop(rtp->rtm_family, RTA_DATA(rtap), srcs, 24); + r.src.set(RTA_DATA(rtap), 4, 0); + wecare = true; + break; + case AF_INET6: + inet_ntop(rtp->rtm_family, RTA_DATA(rtap), srcs, 24); + r.src.set(RTA_DATA(rtap), 16, 0); + wecare = true; + break; + } + break; + case RTA_GATEWAY: + switch (rtp->rtm_family) { + case AF_INET: + inet_ntop(rtp->rtm_family, RTA_DATA(rtap), gws, 24); + r.via.set(RTA_DATA(rtap), 4, 0); + wecare = true; + break; + case AF_INET6: + inet_ntop(rtp->rtm_family, RTA_DATA(rtap), gws, 24); + r.via.set(RTA_DATA(rtap), 16, 0); + wecare = true; + break; + } + break; + case RTA_OIF: + switch (rtp->rtm_family) { + case AF_INET: + r.ifidx = *((int*)RTA_DATA(rtap)); + wecare = true; + break; + case AF_INET6: + r.ifidx = *((int*)RTA_DATA(rtap)); + wecare = true; + break; + } + sprintf(ifs, "%d", *((int*)RTA_DATA(rtap))); + break; + } + } - if (wecare) { - Mutex::Lock rl(_routes_m); - _routes[r.target].erase(r); - } + if (wecare) { + Mutex::Lock rl(_routes_m); + _routes[r.target].erase(r); + } #ifdef ZT_NETLINK_TRACE - sprintf(ms, "%d", rtp->rtm_dst_len); - fprintf(stderr, "Route Deleted: dst %s/%s gw %s src %s if %s\n", dsts, ms, gws, srcs, ifs); + sprintf(ms, "%d", rtp->rtm_dst_len); + fprintf(stderr, "Route Deleted: dst %s/%s gw %s src %s if %s\n", dsts, ms, gws, srcs, ifs); #endif } -void LinuxNetLink::_linkAdded(struct nlmsghdr *nlp) +void LinuxNetLink::_linkAdded(struct nlmsghdr* nlp) { - unsigned char mac_bin[6] = {0}; - unsigned int mtu = 0; - char ifname[IFNAMSIZ] = {0}; + unsigned char mac_bin[6] = { 0 }; + unsigned int mtu = 0; + char ifname[IFNAMSIZ] = { 0 }; - struct ifinfomsg *ifip = (struct ifinfomsg *)NLMSG_DATA(nlp); - struct rtattr *rtap = (struct rtattr *)IFLA_RTA(ifip); - int ifil = RTM_PAYLOAD(nlp); + struct ifinfomsg* ifip = (struct ifinfomsg*)NLMSG_DATA(nlp); + struct rtattr* rtap = (struct rtattr*)IFLA_RTA(ifip); + int ifil = RTM_PAYLOAD(nlp); - const char *ptr = (const char *)0; - for(;RTA_OK(rtap, ifil);rtap=RTA_NEXT(rtap, ifil)) - { - switch(rtap->rta_type) { - case IFLA_ADDRESS: - ptr = (const char *)RTA_DATA(rtap); - memcpy(mac_bin, ptr, 6); - break; - case IFLA_IFNAME: - ptr = (const char *)RTA_DATA(rtap); - memcpy(ifname, ptr, strlen(ptr)); - break; - case IFLA_MTU: - memcpy(&mtu, RTA_DATA(rtap), sizeof(unsigned int)); - break; - } - } + const char* ptr = (const char*)0; + for (; RTA_OK(rtap, ifil); rtap = RTA_NEXT(rtap, ifil)) { + switch (rtap->rta_type) { + case IFLA_ADDRESS: + ptr = (const char*)RTA_DATA(rtap); + memcpy(mac_bin, ptr, 6); + break; + case IFLA_IFNAME: + ptr = (const char*)RTA_DATA(rtap); + memcpy(ifname, ptr, strlen(ptr)); + break; + case IFLA_MTU: + memcpy(&mtu, RTA_DATA(rtap), sizeof(unsigned int)); + break; + } + } - { - Mutex::Lock l(_if_m); - struct iface_entry &entry = _interfaces[ifip->ifi_index]; - entry.index = ifip->ifi_index; - memcpy(entry.ifacename, ifname, sizeof(ifname)); - snprintf(entry.mac,sizeof(entry.mac),"%.02x:%.02x:%.02x:%.02x:%.02x:%.02x",(unsigned int)mac_bin[0],(unsigned int)mac_bin[1],(unsigned int)mac_bin[2],(unsigned int)mac_bin[3],(unsigned int)mac_bin[4],(unsigned int)mac_bin[5]); - memcpy(entry.mac_bin, mac_bin, 6); - entry.mtu = mtu; - } + { + Mutex::Lock l(_if_m); + struct iface_entry& entry = _interfaces[ifip->ifi_index]; + entry.index = ifip->ifi_index; + memcpy(entry.ifacename, ifname, sizeof(ifname)); + snprintf( + entry.mac, + sizeof(entry.mac), + "%.02x:%.02x:%.02x:%.02x:%.02x:%.02x", + (unsigned int)mac_bin[0], + (unsigned int)mac_bin[1], + (unsigned int)mac_bin[2], + (unsigned int)mac_bin[3], + (unsigned int)mac_bin[4], + (unsigned int)mac_bin[5]); + memcpy(entry.mac_bin, mac_bin, 6); + entry.mtu = mtu; + } } -void LinuxNetLink::_linkDeleted(struct nlmsghdr *nlp) +void LinuxNetLink::_linkDeleted(struct nlmsghdr* nlp) { - unsigned int mtu = 0; - char ifname[40] = {0}; + unsigned int mtu = 0; + char ifname[40] = { 0 }; - struct ifinfomsg *ifip = (struct ifinfomsg *)NLMSG_DATA(nlp); - struct rtattr *rtap = (struct rtattr *)IFLA_RTA(ifip); - int ifil = RTM_PAYLOAD(nlp); + struct ifinfomsg* ifip = (struct ifinfomsg*)NLMSG_DATA(nlp); + struct rtattr* rtap = (struct rtattr*)IFLA_RTA(ifip); + int ifil = RTM_PAYLOAD(nlp); - const char *ptr = (const char *)0; - for(;RTA_OK(rtap, ifil);rtap=RTA_NEXT(rtap, ifil)) - { - switch(rtap->rta_type) { - case IFLA_IFNAME: - ptr = (const char*)RTA_DATA(rtap); - memcpy(ifname, ptr, strlen(ptr)); - break; - case IFLA_MTU: - memcpy(&mtu, RTA_DATA(rtap), sizeof(unsigned int)); - break; - } - } + const char* ptr = (const char*)0; + for (; RTA_OK(rtap, ifil); rtap = RTA_NEXT(rtap, ifil)) { + switch (rtap->rta_type) { + case IFLA_IFNAME: + ptr = (const char*)RTA_DATA(rtap); + memcpy(ifname, ptr, strlen(ptr)); + break; + case IFLA_MTU: + memcpy(&mtu, RTA_DATA(rtap), sizeof(unsigned int)); + break; + } + } - { - Mutex::Lock l(_if_m); - if(_interfaces.contains(ifip->ifi_index)) { - _interfaces.erase(ifip->ifi_index); - } - } + { + Mutex::Lock l(_if_m); + if (_interfaces.contains(ifip->ifi_index)) { + _interfaces.erase(ifip->ifi_index); + } + } } void LinuxNetLink::_requestIPv4Routes() { - int fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); - if (fd == -1) { - fprintf(stderr, "Error opening RTNETLINK socket: %s\n", strerror(errno)); - return; - } + int fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); + if (fd == -1) { + fprintf(stderr, "Error opening RTNETLINK socket: %s\n", strerror(errno)); + return; + } - _setSocketTimeout(fd); + _setSocketTimeout(fd); - struct sockaddr_nl la; - la.nl_family = AF_NETLINK; - la.nl_pid = 0; //getpid(); - la.nl_groups = RTMGRP_IPV4_ROUTE; - if(bind(fd, (struct sockaddr*)&la, sizeof(la))) { - fprintf(stderr, "Error binding RTNETLINK (_requestIPv4Routes #1): %s\n", strerror(errno)); - close(fd); - return; - } + struct sockaddr_nl la; + la.nl_family = AF_NETLINK; + la.nl_pid = 0; // getpid(); + la.nl_groups = RTMGRP_IPV4_ROUTE; + if (bind(fd, (struct sockaddr*)&la, sizeof(la))) { + fprintf(stderr, "Error binding RTNETLINK (_requestIPv4Routes #1): %s\n", strerror(errno)); + close(fd); + return; + } - struct nl_route_req req; - bzero(&req, sizeof(req)); - req.nl.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); - req.nl.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP; - req.nl.nlmsg_type = RTM_GETROUTE; - req.nl.nlmsg_pid = 0; - req.nl.nlmsg_seq = ++_seq; - req.rt.rtm_family = AF_INET; - req.rt.rtm_table = RT_TABLE_MAIN; + struct nl_route_req req; + bzero(&req, sizeof(req)); + req.nl.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); + req.nl.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP; + req.nl.nlmsg_type = RTM_GETROUTE; + req.nl.nlmsg_pid = 0; + req.nl.nlmsg_seq = ++_seq; + req.rt.rtm_family = AF_INET; + req.rt.rtm_table = RT_TABLE_MAIN; - struct sockaddr_nl pa; - bzero(&pa, sizeof(pa)); - pa.nl_family = AF_NETLINK; + struct sockaddr_nl pa; + bzero(&pa, sizeof(pa)); + pa.nl_family = AF_NETLINK; - struct msghdr msg; - bzero(&msg, sizeof(msg)); - msg.msg_name = (void*)&pa; - msg.msg_namelen = sizeof(pa); + struct msghdr msg; + bzero(&msg, sizeof(msg)); + msg.msg_name = (void*)&pa; + msg.msg_namelen = sizeof(pa); - struct iovec iov; - bzero(&iov, sizeof(iov)); - iov.iov_base = (void*)&req.nl; - iov.iov_len = req.nl.nlmsg_len; - msg.msg_iov = &iov; - msg.msg_iovlen = 1; + struct iovec iov; + bzero(&iov, sizeof(iov)); + iov.iov_base = (void*)&req.nl; + iov.iov_len = req.nl.nlmsg_len; + msg.msg_iov = &iov; + msg.msg_iovlen = 1; - sendmsg(fd, &msg, 0); + sendmsg(fd, &msg, 0); - _doRecv(fd); + _doRecv(fd); - close(fd); + close(fd); } void LinuxNetLink::_requestIPv6Routes() { - int fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); - if (fd == -1) { - fprintf(stderr, "Error opening RTNETLINK socket: %s\n", strerror(errno)); - return; - } + int fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); + if (fd == -1) { + fprintf(stderr, "Error opening RTNETLINK socket: %s\n", strerror(errno)); + return; + } - _setSocketTimeout(fd); + _setSocketTimeout(fd); - struct sockaddr_nl la; - la.nl_family = AF_NETLINK; - la.nl_pid = 0; //getpid(); - la.nl_groups = RTMGRP_IPV6_ROUTE; - if(bind(fd, (struct sockaddr*)&la, sizeof(struct sockaddr_nl))) { - fprintf(stderr, "Error binding RTNETLINK (_requestIPv6Routes #1): %s\n", strerror(errno)); - close(fd); - return; - } + struct sockaddr_nl la; + la.nl_family = AF_NETLINK; + la.nl_pid = 0; // getpid(); + la.nl_groups = RTMGRP_IPV6_ROUTE; + if (bind(fd, (struct sockaddr*)&la, sizeof(struct sockaddr_nl))) { + fprintf(stderr, "Error binding RTNETLINK (_requestIPv6Routes #1): %s\n", strerror(errno)); + close(fd); + return; + } - struct nl_route_req req; - bzero(&req, sizeof(req)); - req.nl.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); - req.nl.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP; - req.nl.nlmsg_type = RTM_GETROUTE; - req.nl.nlmsg_pid = 0; - req.nl.nlmsg_seq = ++_seq; - req.rt.rtm_family = AF_INET6; - req.rt.rtm_table = RT_TABLE_MAIN; + struct nl_route_req req; + bzero(&req, sizeof(req)); + req.nl.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); + req.nl.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP; + req.nl.nlmsg_type = RTM_GETROUTE; + req.nl.nlmsg_pid = 0; + req.nl.nlmsg_seq = ++_seq; + req.rt.rtm_family = AF_INET6; + req.rt.rtm_table = RT_TABLE_MAIN; - struct sockaddr_nl pa; - bzero(&pa, sizeof(pa)); - pa.nl_family = AF_NETLINK; + struct sockaddr_nl pa; + bzero(&pa, sizeof(pa)); + pa.nl_family = AF_NETLINK; - struct msghdr msg; - bzero(&msg, sizeof(msg)); - msg.msg_name = (void*)&pa; - msg.msg_namelen = sizeof(pa); + struct msghdr msg; + bzero(&msg, sizeof(msg)); + msg.msg_name = (void*)&pa; + msg.msg_namelen = sizeof(pa); - struct iovec iov; - bzero(&iov, sizeof(iov)); - iov.iov_base = (void*)&req.nl; - iov.iov_len = req.nl.nlmsg_len; - msg.msg_iov = &iov; - msg.msg_iovlen = 1; + struct iovec iov; + bzero(&iov, sizeof(iov)); + iov.iov_base = (void*)&req.nl; + iov.iov_len = req.nl.nlmsg_len; + msg.msg_iov = &iov; + msg.msg_iovlen = 1; - sendmsg(fd, &msg, 0); + sendmsg(fd, &msg, 0); - _doRecv(fd); + _doRecv(fd); - close(fd); + close(fd); } void LinuxNetLink::_requestInterfaceList() { - int fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); - if (fd == -1) { - fprintf(stderr, "Error opening RTNETLINK socket: %s\n", strerror(errno)); - return; - } + int fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); + if (fd == -1) { + fprintf(stderr, "Error opening RTNETLINK socket: %s\n", strerror(errno)); + return; + } - _setSocketTimeout(fd); + _setSocketTimeout(fd); - struct sockaddr_nl la; - la.nl_family = AF_NETLINK; - la.nl_pid = 0; //getpid(); - la.nl_groups = RTMGRP_LINK; - if(bind(fd, (struct sockaddr*)&la, sizeof(struct sockaddr_nl))) { - fprintf(stderr, "Error binding RTNETLINK (_requestInterfaceList #1): %s\n", strerror(errno)); - close(fd); - return; - } + struct sockaddr_nl la; + la.nl_family = AF_NETLINK; + la.nl_pid = 0; // getpid(); + la.nl_groups = RTMGRP_LINK; + if (bind(fd, (struct sockaddr*)&la, sizeof(struct sockaddr_nl))) { + fprintf(stderr, "Error binding RTNETLINK (_requestInterfaceList #1): %s\n", strerror(errno)); + close(fd); + return; + } - struct nl_if_req req; - bzero(&req, sizeof(req)); - req.nl.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); - req.nl.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP; - req.nl.nlmsg_type = RTM_GETLINK; - req.nl.nlmsg_pid = 0; - req.nl.nlmsg_seq = ++_seq; - req.ifa.ifi_family = AF_UNSPEC; + struct nl_if_req req; + bzero(&req, sizeof(req)); + req.nl.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); + req.nl.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP; + req.nl.nlmsg_type = RTM_GETLINK; + req.nl.nlmsg_pid = 0; + req.nl.nlmsg_seq = ++_seq; + req.ifa.ifi_family = AF_UNSPEC; - struct sockaddr_nl pa; - bzero(&pa, sizeof(pa)); - pa.nl_family = AF_NETLINK; + struct sockaddr_nl pa; + bzero(&pa, sizeof(pa)); + pa.nl_family = AF_NETLINK; - struct msghdr msg; - bzero(&msg, sizeof(msg)); - msg.msg_name = (void*)&pa; - msg.msg_namelen = sizeof(pa); + struct msghdr msg; + bzero(&msg, sizeof(msg)); + msg.msg_name = (void*)&pa; + msg.msg_namelen = sizeof(pa); - struct iovec iov; - bzero(&iov, sizeof(iov)); - iov.iov_base = (void*)&req.nl; - iov.iov_len = req.nl.nlmsg_len; - msg.msg_iov = &iov; - msg.msg_iovlen = 1; - sendmsg(fd, &msg, 0); + struct iovec iov; + bzero(&iov, sizeof(iov)); + iov.iov_base = (void*)&req.nl; + iov.iov_len = req.nl.nlmsg_len; + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + sendmsg(fd, &msg, 0); - _doRecv(fd); + _doRecv(fd); - close(fd); + close(fd); } -void LinuxNetLink::addRoute(const InetAddress &target, const InetAddress &via, const InetAddress &src, const char *ifaceName) +void LinuxNetLink::addRoute(const InetAddress& target, const InetAddress& via, const InetAddress& src, const char* ifaceName) { - if (!target) return; + if (! target) + return; - int fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); - if (fd == -1) { - fprintf(stderr, "Error opening RTNETLINK socket: %s\n", strerror(errno)); - return; - } + int fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); + if (fd == -1) { + fprintf(stderr, "Error opening RTNETLINK socket: %s\n", strerror(errno)); + return; + } - _setSocketTimeout(fd); + _setSocketTimeout(fd); - struct sockaddr_nl la; - bzero(&la, sizeof(la)); - la.nl_family = AF_NETLINK; - la.nl_pid = 0; //getpid(); + struct sockaddr_nl la; + bzero(&la, sizeof(la)); + la.nl_family = AF_NETLINK; + la.nl_pid = 0; // getpid(); - if(bind(fd, (struct sockaddr*)&la, sizeof(struct sockaddr_nl))) { - fprintf(stderr, "Error binding RTNETLINK (addRoute #1): %s\n", strerror(errno)); - close(fd); - return; - } + if (bind(fd, (struct sockaddr*)&la, sizeof(struct sockaddr_nl))) { + fprintf(stderr, "Error binding RTNETLINK (addRoute #1): %s\n", strerror(errno)); + close(fd); + return; + } #ifdef ZT_NETLINK_TRACE - char tmp[64]; - char tmp2[64]; - char tmp3[64]; - fprintf(stderr, "Adding Route. target: %s via: %s src: %s iface: %s\n", target.toString(tmp), via.toString(tmp2), src.toString(tmp3), ifaceName); + char tmp[64]; + char tmp2[64]; + char tmp3[64]; + fprintf(stderr, "Adding Route. target: %s via: %s src: %s iface: %s\n", target.toString(tmp), via.toString(tmp2), src.toString(tmp3), ifaceName); #endif - int rtl = sizeof(struct rtmsg); - struct nl_route_req req; - bzero(&req, sizeof(req)); + int rtl = sizeof(struct rtmsg); + struct nl_route_req req; + bzero(&req, sizeof(req)); - struct rtattr *rtap = (struct rtattr *)req.buf; - rtap->rta_type = RTA_DST; - if (target.isV4()) { - rtap->rta_len = RTA_LENGTH(sizeof(struct in_addr)); - memcpy(RTA_DATA(rtap), &((struct sockaddr_in*)&target)->sin_addr, sizeof(struct in_addr)); - } else { - rtap->rta_len = RTA_LENGTH(sizeof(struct in6_addr)); - memcpy(RTA_DATA(rtap), &((struct sockaddr_in6*)&target)->sin6_addr, sizeof(struct in6_addr)); - } - rtl += rtap->rta_len; + struct rtattr* rtap = (struct rtattr*)req.buf; + rtap->rta_type = RTA_DST; + if (target.isV4()) { + rtap->rta_len = RTA_LENGTH(sizeof(struct in_addr)); + memcpy(RTA_DATA(rtap), &((struct sockaddr_in*)&target)->sin_addr, sizeof(struct in_addr)); + } + else { + rtap->rta_len = RTA_LENGTH(sizeof(struct in6_addr)); + memcpy(RTA_DATA(rtap), &((struct sockaddr_in6*)&target)->sin6_addr, sizeof(struct in6_addr)); + } + rtl += rtap->rta_len; - if(via) { - /* - * Setting a metric keeps zerotier routes from taking priority over physical - * At best the computer would use zerotier through the router instead of the LAN. - * At worst it stops working at all. - * - * default via 192.168.82.1 dev eth0 proto dhcp src 192.168.82.169 metric 202 - * 10.147.17.0/24 dev zt5u4uptmb proto kernel scope link src 10.147.17.94 - * 192.168.82.0/24 dev eth0 proto dhcp scope link src 192.168.82.169 metric 202 - * 192.168.82.0/24 via 10.147.17.1 dev zt5u4uptmb proto static metric 5000 - * - */ - rtap = (struct rtattr*)(((char*)rtap) + rtap->rta_len); - rtap->rta_type = RTA_PRIORITY; - rtap->rta_len = RTA_LENGTH(sizeof(ZT_RTE_METRIC)); - memcpy(RTA_DATA(rtap), &ZT_RTE_METRIC, sizeof(ZT_RTE_METRIC)); - rtl += rtap->rta_len; + if (via) { + /* + * Setting a metric keeps zerotier routes from taking priority over physical + * At best the computer would use zerotier through the router instead of the LAN. + * At worst it stops working at all. + * + * default via 192.168.82.1 dev eth0 proto dhcp src 192.168.82.169 metric 202 + * 10.147.17.0/24 dev zt5u4uptmb proto kernel scope link src 10.147.17.94 + * 192.168.82.0/24 dev eth0 proto dhcp scope link src 192.168.82.169 metric 202 + * 192.168.82.0/24 via 10.147.17.1 dev zt5u4uptmb proto static metric 5000 + * + */ + rtap = (struct rtattr*)(((char*)rtap) + rtap->rta_len); + rtap->rta_type = RTA_PRIORITY; + rtap->rta_len = RTA_LENGTH(sizeof(ZT_RTE_METRIC)); + memcpy(RTA_DATA(rtap), &ZT_RTE_METRIC, sizeof(ZT_RTE_METRIC)); + rtl += rtap->rta_len; - rtap = (struct rtattr *)(((char*)rtap)+rtap->rta_len); - rtap->rta_type = RTA_GATEWAY; - if(via.isV4()) { - rtap->rta_len = RTA_LENGTH(sizeof(struct in_addr)); - memcpy(RTA_DATA(rtap), &((struct sockaddr_in*)&via)->sin_addr, sizeof(struct in_addr)); - } else { - rtap->rta_len = RTA_LENGTH(sizeof(struct in6_addr)); - memcpy(RTA_DATA(rtap), &((struct sockaddr_in6*)&via)->sin6_addr, sizeof(struct in6_addr)); - } - rtl += rtap->rta_len; - } else if (src) { - rtap = (struct rtattr *)(((char*)rtap)+rtap->rta_len); - rtap->rta_type = RTA_SRC; - if(src.isV4()) { - rtap->rta_len = RTA_LENGTH(sizeof(struct in_addr)); - memcpy(RTA_DATA(rtap), &((struct sockaddr_in*)&src)->sin_addr, sizeof(struct in_addr)); + rtap = (struct rtattr*)(((char*)rtap) + rtap->rta_len); + rtap->rta_type = RTA_GATEWAY; + if (via.isV4()) { + rtap->rta_len = RTA_LENGTH(sizeof(struct in_addr)); + memcpy(RTA_DATA(rtap), &((struct sockaddr_in*)&via)->sin_addr, sizeof(struct in_addr)); + } + else { + rtap->rta_len = RTA_LENGTH(sizeof(struct in6_addr)); + memcpy(RTA_DATA(rtap), &((struct sockaddr_in6*)&via)->sin6_addr, sizeof(struct in6_addr)); + } + rtl += rtap->rta_len; + } + else if (src) { + rtap = (struct rtattr*)(((char*)rtap) + rtap->rta_len); + rtap->rta_type = RTA_SRC; + if (src.isV4()) { + rtap->rta_len = RTA_LENGTH(sizeof(struct in_addr)); + memcpy(RTA_DATA(rtap), &((struct sockaddr_in*)&src)->sin_addr, sizeof(struct in_addr)); + } + else { + rtap->rta_len = RTA_LENGTH(sizeof(struct in6_addr)); + memcpy(RTA_DATA(rtap), &((struct sockaddr_in6*)&src)->sin6_addr, sizeof(struct in6_addr)); + } + req.rt.rtm_src_len = src.netmaskBits(); + } - } else { - rtap->rta_len = RTA_LENGTH(sizeof(struct in6_addr)); - memcpy(RTA_DATA(rtap), &((struct sockaddr_in6*)&src)->sin6_addr, sizeof(struct in6_addr)); - } - req.rt.rtm_src_len = src.netmaskBits(); - } + if (ifaceName != NULL) { + int interface_index = _indexForInterface(ifaceName); + if (interface_index != -1) { + rtap = (struct rtattr*)(((char*)rtap) + rtap->rta_len); + rtap->rta_type = RTA_OIF; + rtap->rta_len = RTA_LENGTH(sizeof(int)); + memcpy(RTA_DATA(rtap), &interface_index, sizeof(int)); + rtl += rtap->rta_len; + } + } - if (ifaceName != NULL) { - int interface_index = _indexForInterface(ifaceName); - if (interface_index != -1) { - rtap = (struct rtattr *) (((char*)rtap) + rtap->rta_len); - rtap->rta_type = RTA_OIF; - rtap->rta_len = RTA_LENGTH(sizeof(int)); - memcpy(RTA_DATA(rtap), &interface_index, sizeof(int)); - rtl += rtap->rta_len; - } - } + req.nl.nlmsg_len = NLMSG_LENGTH(rtl); + req.nl.nlmsg_flags = NLM_F_REQUEST | NLM_F_EXCL | NLM_F_CREATE | NLM_F_ACK; + req.nl.nlmsg_type = RTM_NEWROUTE; + req.nl.nlmsg_pid = 0; + req.nl.nlmsg_seq = ++_seq; + req.rt.rtm_family = target.ss_family; + req.rt.rtm_table = RT_TABLE_MAIN; + req.rt.rtm_protocol = RTPROT_STATIC; + req.rt.rtm_scope = RT_SCOPE_UNIVERSE; + req.rt.rtm_type = RTN_UNICAST; + req.rt.rtm_dst_len = target.netmaskBits(); + req.rt.rtm_flags = 0; - req.nl.nlmsg_len = NLMSG_LENGTH(rtl); - req.nl.nlmsg_flags = NLM_F_REQUEST | NLM_F_EXCL | NLM_F_CREATE | NLM_F_ACK; - req.nl.nlmsg_type = RTM_NEWROUTE; - req.nl.nlmsg_pid = 0; - req.nl.nlmsg_seq = ++_seq; - req.rt.rtm_family = target.ss_family; - req.rt.rtm_table = RT_TABLE_MAIN; - req.rt.rtm_protocol = RTPROT_STATIC; - req.rt.rtm_scope = RT_SCOPE_UNIVERSE; - req.rt.rtm_type = RTN_UNICAST; - req.rt.rtm_dst_len = target.netmaskBits(); - req.rt.rtm_flags = 0; + struct sockaddr_nl pa; + bzero(&pa, sizeof(pa)); + pa.nl_family = AF_NETLINK; - struct sockaddr_nl pa; - bzero(&pa, sizeof(pa)); - pa.nl_family = AF_NETLINK; + struct msghdr msg; + bzero(&msg, sizeof(msg)); + msg.msg_name = (void*)&pa; + msg.msg_namelen = sizeof(pa); - struct msghdr msg; - bzero(&msg, sizeof(msg)); - msg.msg_name = (void*)&pa; - msg.msg_namelen = sizeof(pa); + struct iovec iov; + bzero(&iov, sizeof(iov)); + iov.iov_base = (void*)&req.nl; + iov.iov_len = req.nl.nlmsg_len; + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + sendmsg(fd, &msg, 0); - struct iovec iov; - bzero(&iov, sizeof(iov)); - iov.iov_base = (void*)&req.nl; - iov.iov_len = req.nl.nlmsg_len; - msg.msg_iov = &iov; - msg.msg_iovlen = 1; - sendmsg(fd, &msg, 0); + _doRecv(fd); - _doRecv(fd); - - close(fd); + close(fd); } -void LinuxNetLink::delRoute(const InetAddress &target, const InetAddress &via, const InetAddress &src, const char *ifaceName) +void LinuxNetLink::delRoute(const InetAddress& target, const InetAddress& via, const InetAddress& src, const char* ifaceName) { - if (!target) return; + if (! target) + return; - int fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); - if (fd == -1) { - fprintf(stderr, "Error opening RTNETLINK socket: %s\n", strerror(errno)); - return; - } + int fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); + if (fd == -1) { + fprintf(stderr, "Error opening RTNETLINK socket: %s\n", strerror(errno)); + return; + } - _setSocketTimeout(fd); + _setSocketTimeout(fd); - struct sockaddr_nl la; - la.nl_family = AF_NETLINK; - la.nl_pid = 0; //getpid(); + struct sockaddr_nl la; + la.nl_family = AF_NETLINK; + la.nl_pid = 0; // getpid(); - if(bind(fd, (struct sockaddr*)&la, sizeof(struct sockaddr_nl))) { - fprintf(stderr, "Error binding RTNETLINK (delRoute #1): %s\n", strerror(errno)); - close(fd); - return; - } + if (bind(fd, (struct sockaddr*)&la, sizeof(struct sockaddr_nl))) { + fprintf(stderr, "Error binding RTNETLINK (delRoute #1): %s\n", strerror(errno)); + close(fd); + return; + } #ifdef ZT_NETLINK_TRACE - char tmp[64]; - char tmp2[64]; - char tmp3[64]; - fprintf(stderr, "Removing Route. target: %s via: %s src: %s iface: %s\n", target.toString(tmp), via.toString(tmp2), src.toString(tmp3), ifaceName); + char tmp[64]; + char tmp2[64]; + char tmp3[64]; + fprintf(stderr, "Removing Route. target: %s via: %s src: %s iface: %s\n", target.toString(tmp), via.toString(tmp2), src.toString(tmp3), ifaceName); #endif - int rtl = sizeof(struct rtmsg); - struct nl_route_req req; - bzero(&req, sizeof(req)); + int rtl = sizeof(struct rtmsg); + struct nl_route_req req; + bzero(&req, sizeof(req)); - struct rtattr *rtap = (struct rtattr *)req.buf; - rtap->rta_type = RTA_DST; - if (target.isV4()) { - rtap->rta_len = RTA_LENGTH(sizeof(struct in_addr)); - memcpy(RTA_DATA(rtap), &((struct sockaddr_in*)&target)->sin_addr, sizeof(struct in_addr)); - } else { - rtap->rta_len = RTA_LENGTH(sizeof(struct in6_addr)); - memcpy(RTA_DATA(rtap), &((struct sockaddr_in6*)&target)->sin6_addr, sizeof(struct in6_addr)); - } - rtl += rtap->rta_len; + struct rtattr* rtap = (struct rtattr*)req.buf; + rtap->rta_type = RTA_DST; + if (target.isV4()) { + rtap->rta_len = RTA_LENGTH(sizeof(struct in_addr)); + memcpy(RTA_DATA(rtap), &((struct sockaddr_in*)&target)->sin_addr, sizeof(struct in_addr)); + } + else { + rtap->rta_len = RTA_LENGTH(sizeof(struct in6_addr)); + memcpy(RTA_DATA(rtap), &((struct sockaddr_in6*)&target)->sin6_addr, sizeof(struct in6_addr)); + } + rtl += rtap->rta_len; - if(via) { - rtap = (struct rtattr *)(((char*)rtap)+rtap->rta_len); - rtap->rta_type = RTA_GATEWAY; - if(via.isV4()) { - rtap->rta_len = RTA_LENGTH(sizeof(struct in_addr)); - memcpy(RTA_DATA(rtap), &((struct sockaddr_in*)&via)->sin_addr, sizeof(struct in_addr)); - } else { - rtap->rta_len = RTA_LENGTH(sizeof(struct in6_addr)); - memcpy(RTA_DATA(rtap), &((struct sockaddr_in6*)&via)->sin6_addr, sizeof(struct in6_addr)); - } - rtl += rtap->rta_len; - } else if (src) { - rtap = (struct rtattr *)(((char*)rtap)+rtap->rta_len); - rtap->rta_type = RTA_SRC; - if(src.isV4()) { - rtap->rta_len = RTA_LENGTH(sizeof(struct in_addr)); - memcpy(RTA_DATA(rtap), &((struct sockaddr_in*)&src)->sin_addr, sizeof(struct in_addr)); + if (via) { + rtap = (struct rtattr*)(((char*)rtap) + rtap->rta_len); + rtap->rta_type = RTA_GATEWAY; + if (via.isV4()) { + rtap->rta_len = RTA_LENGTH(sizeof(struct in_addr)); + memcpy(RTA_DATA(rtap), &((struct sockaddr_in*)&via)->sin_addr, sizeof(struct in_addr)); + } + else { + rtap->rta_len = RTA_LENGTH(sizeof(struct in6_addr)); + memcpy(RTA_DATA(rtap), &((struct sockaddr_in6*)&via)->sin6_addr, sizeof(struct in6_addr)); + } + rtl += rtap->rta_len; + } + else if (src) { + rtap = (struct rtattr*)(((char*)rtap) + rtap->rta_len); + rtap->rta_type = RTA_SRC; + if (src.isV4()) { + rtap->rta_len = RTA_LENGTH(sizeof(struct in_addr)); + memcpy(RTA_DATA(rtap), &((struct sockaddr_in*)&src)->sin_addr, sizeof(struct in_addr)); + } + else { + rtap->rta_len = RTA_LENGTH(sizeof(struct in6_addr)); + memcpy(RTA_DATA(rtap), &((struct sockaddr_in6*)&src)->sin6_addr, sizeof(struct in6_addr)); + } + req.rt.rtm_src_len = src.netmaskBits(); + } - } else { - rtap->rta_len = RTA_LENGTH(sizeof(struct in6_addr)); - memcpy(RTA_DATA(rtap), &((struct sockaddr_in6*)&src)->sin6_addr, sizeof(struct in6_addr)); - } - req.rt.rtm_src_len = src.netmaskBits(); - } + if (ifaceName != NULL) { + int interface_index = _indexForInterface(ifaceName); + if (interface_index != -1) { + rtap = (struct rtattr*)(((char*)rtap) + rtap->rta_len); + rtap->rta_type = RTA_OIF; + rtap->rta_len = RTA_LENGTH(sizeof(int)); + memcpy(RTA_DATA(rtap), &interface_index, sizeof(int)); + rtl += rtap->rta_len; + } + } - if (ifaceName != NULL) { - int interface_index = _indexForInterface(ifaceName); - if (interface_index != -1) { - rtap = (struct rtattr *) (((char*)rtap) + rtap->rta_len); - rtap->rta_type = RTA_OIF; - rtap->rta_len = RTA_LENGTH(sizeof(int)); - memcpy(RTA_DATA(rtap), &interface_index, sizeof(int)); - rtl += rtap->rta_len; - } - } + req.nl.nlmsg_len = NLMSG_LENGTH(rtl); + req.nl.nlmsg_flags = NLM_F_REQUEST; + req.nl.nlmsg_type = RTM_DELROUTE; + req.nl.nlmsg_pid = 0; + req.nl.nlmsg_seq = ++_seq; + req.rt.rtm_family = target.ss_family; + req.rt.rtm_table = RT_TABLE_MAIN; + req.rt.rtm_protocol = RTPROT_STATIC; + req.rt.rtm_scope = RT_SCOPE_UNIVERSE; + req.rt.rtm_type = RTN_UNICAST; + req.rt.rtm_dst_len = target.netmaskBits(); + req.rt.rtm_flags = 0; - req.nl.nlmsg_len = NLMSG_LENGTH(rtl); - req.nl.nlmsg_flags = NLM_F_REQUEST; - req.nl.nlmsg_type = RTM_DELROUTE; - req.nl.nlmsg_pid = 0; - req.nl.nlmsg_seq = ++_seq; - req.rt.rtm_family = target.ss_family; - req.rt.rtm_table = RT_TABLE_MAIN; - req.rt.rtm_protocol = RTPROT_STATIC; - req.rt.rtm_scope = RT_SCOPE_UNIVERSE; - req.rt.rtm_type = RTN_UNICAST; - req.rt.rtm_dst_len = target.netmaskBits(); - req.rt.rtm_flags = 0; + struct sockaddr_nl pa; + bzero(&pa, sizeof(pa)); + pa.nl_family = AF_NETLINK; - struct sockaddr_nl pa; - bzero(&pa, sizeof(pa)); - pa.nl_family = AF_NETLINK; + struct msghdr msg; + bzero(&msg, sizeof(msg)); + msg.msg_name = (void*)&pa; + msg.msg_namelen = sizeof(pa); - struct msghdr msg; - bzero(&msg, sizeof(msg)); - msg.msg_name = (void*)&pa; - msg.msg_namelen = sizeof(pa); + struct iovec iov; + bzero(&iov, sizeof(iov)); + iov.iov_base = (void*)&req.nl; + iov.iov_len = req.nl.nlmsg_len; + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + sendmsg(fd, &msg, 0); - struct iovec iov; - bzero(&iov, sizeof(iov)); - iov.iov_base = (void*)&req.nl; - iov.iov_len = req.nl.nlmsg_len; - msg.msg_iov = &iov; - msg.msg_iovlen = 1; - sendmsg(fd, &msg, 0); + _doRecv(fd); - _doRecv(fd); - - close(fd); + close(fd); } -void LinuxNetLink::addAddress(const InetAddress &addr, const char *iface) +void LinuxNetLink::addAddress(const InetAddress& addr, const char* iface) { - int fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); - if (fd == -1) { - fprintf(stderr, "Error opening RTNETLINK socket: %s\n", strerror(errno)); - return; - } + int fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); + if (fd == -1) { + fprintf(stderr, "Error opening RTNETLINK socket: %s\n", strerror(errno)); + return; + } - _setSocketTimeout(fd); + _setSocketTimeout(fd); - struct sockaddr_nl la; - memset(&la,0,sizeof(la)); - la.nl_family = AF_NETLINK; - la.nl_pid = 0; //getpid(); - if (addr.isV4()) { - la.nl_groups = RTMGRP_IPV4_IFADDR; - } else { - la.nl_groups = RTMGRP_IPV6_IFADDR; - } + struct sockaddr_nl la; + memset(&la, 0, sizeof(la)); + la.nl_family = AF_NETLINK; + la.nl_pid = 0; // getpid(); + if (addr.isV4()) { + la.nl_groups = RTMGRP_IPV4_IFADDR; + } + else { + la.nl_groups = RTMGRP_IPV6_IFADDR; + } - if(bind(fd, (struct sockaddr*)&la, sizeof(struct sockaddr_nl))) { - fprintf(stderr, "Error binding RTNETLINK (addAddress #1): %s\n", strerror(errno)); - close(fd); - return; - } + if (bind(fd, (struct sockaddr*)&la, sizeof(struct sockaddr_nl))) { + fprintf(stderr, "Error binding RTNETLINK (addAddress #1): %s\n", strerror(errno)); + close(fd); + return; + } #ifdef ZT_NETLINK_TRACE - char tmp[128]; - fprintf(stderr, "Adding IP address %s to interface %s\n", addr.toString(tmp), iface); + char tmp[128]; + fprintf(stderr, "Adding IP address %s to interface %s\n", addr.toString(tmp), iface); #endif - int interface_index = _indexForInterface(iface); - for (int reps = 0; interface_index == -1 && reps < 10; ++reps) { - Thread::sleep(100); - interface_index = _indexForInterface(iface); - } + int interface_index = _indexForInterface(iface); + for (int reps = 0; interface_index == -1 && reps < 10; ++reps) { + Thread::sleep(100); + interface_index = _indexForInterface(iface); + } - if (interface_index == -1) { - fprintf(stderr, "Unable to find index for interface %s\n", iface); - close(fd); - return; - } + if (interface_index == -1) { + fprintf(stderr, "Unable to find index for interface %s\n", iface); + close(fd); + return; + } - int rtl = sizeof(struct ifaddrmsg); - struct nl_adr_req req; - bzero(&req, sizeof(struct nl_adr_req)); + int rtl = sizeof(struct ifaddrmsg); + struct nl_adr_req req; + bzero(&req, sizeof(struct nl_adr_req)); - struct rtattr *rtap = (struct rtattr *)req.buf;; - if(addr.isV4()) { - struct sockaddr_in *addr_v4 = (struct sockaddr_in*)&addr; - rtap->rta_type = IFA_ADDRESS; - rtap->rta_len = RTA_LENGTH(sizeof(struct in_addr)); - memcpy(RTA_DATA(rtap), &addr_v4->sin_addr, sizeof(struct in_addr)); - rtl += rtap->rta_len; + struct rtattr* rtap = (struct rtattr*)req.buf; + ; + if (addr.isV4()) { + struct sockaddr_in* addr_v4 = (struct sockaddr_in*)&addr; + rtap->rta_type = IFA_ADDRESS; + rtap->rta_len = RTA_LENGTH(sizeof(struct in_addr)); + memcpy(RTA_DATA(rtap), &addr_v4->sin_addr, sizeof(struct in_addr)); + rtl += rtap->rta_len; - rtap = (struct rtattr*)(((char*)rtap) + rtap->rta_len); - rtap->rta_type = IFA_LOCAL; - rtap->rta_len = RTA_LENGTH(sizeof(struct in_addr)); - memcpy(RTA_DATA(rtap), &addr_v4->sin_addr, sizeof(struct in_addr)); - rtl += rtap->rta_len; + rtap = (struct rtattr*)(((char*)rtap) + rtap->rta_len); + rtap->rta_type = IFA_LOCAL; + rtap->rta_len = RTA_LENGTH(sizeof(struct in_addr)); + memcpy(RTA_DATA(rtap), &addr_v4->sin_addr, sizeof(struct in_addr)); + rtl += rtap->rta_len; - InetAddress broadcast = addr.broadcast(); - if(broadcast) { - rtap = (struct rtattr*)(((char*)rtap)+rtap->rta_len); - struct sockaddr_in *bcast = (struct sockaddr_in*)&broadcast; - rtap->rta_type = IFA_BROADCAST; - rtap->rta_len = RTA_LENGTH(sizeof(struct in_addr)); - memcpy(RTA_DATA(rtap), &bcast->sin_addr, sizeof(struct in_addr)); - rtl += rtap->rta_len; - } - } else { //V6 - rtap->rta_type = IFA_ADDRESS; - struct sockaddr_in6 *addr_v6 = (struct sockaddr_in6*)&addr; - rtap->rta_len = RTA_LENGTH(sizeof(struct in6_addr)); - memcpy(RTA_DATA(rtap), &addr_v6->sin6_addr, sizeof(struct in6_addr)); - rtl += rtap->rta_len; - } + InetAddress broadcast = addr.broadcast(); + if (broadcast) { + rtap = (struct rtattr*)(((char*)rtap) + rtap->rta_len); + struct sockaddr_in* bcast = (struct sockaddr_in*)&broadcast; + rtap->rta_type = IFA_BROADCAST; + rtap->rta_len = RTA_LENGTH(sizeof(struct in_addr)); + memcpy(RTA_DATA(rtap), &bcast->sin_addr, sizeof(struct in_addr)); + rtl += rtap->rta_len; + } + } + else { // V6 + rtap->rta_type = IFA_ADDRESS; + struct sockaddr_in6* addr_v6 = (struct sockaddr_in6*)&addr; + rtap->rta_len = RTA_LENGTH(sizeof(struct in6_addr)); + memcpy(RTA_DATA(rtap), &addr_v6->sin6_addr, sizeof(struct in6_addr)); + rtl += rtap->rta_len; + } - if (iface) { - rtap = (struct rtattr*)(((char*)rtap)+rtap->rta_len); - rtap->rta_type = IFA_LABEL; - rtap->rta_len = RTA_LENGTH(strlen(iface)); - memcpy(RTA_DATA(rtap), iface, strlen(iface)); - rtl += rtap->rta_len; - } + if (iface) { + rtap = (struct rtattr*)(((char*)rtap) + rtap->rta_len); + rtap->rta_type = IFA_LABEL; + rtap->rta_len = RTA_LENGTH(strlen(iface)); + memcpy(RTA_DATA(rtap), iface, strlen(iface)); + rtl += rtap->rta_len; + } - req.nl.nlmsg_len = NLMSG_LENGTH(rtl); - req.nl.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL; - req.nl.nlmsg_type = RTM_NEWADDR; - req.nl.nlmsg_pid = 0; - req.nl.nlmsg_seq = ++_seq; - req.ifa.ifa_family = addr.ss_family; - req.ifa.ifa_prefixlen = addr.port(); - req.ifa.ifa_flags = IFA_F_PERMANENT; - req.ifa.ifa_scope = 0; - req.ifa.ifa_index = interface_index; + req.nl.nlmsg_len = NLMSG_LENGTH(rtl); + req.nl.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL; + req.nl.nlmsg_type = RTM_NEWADDR; + req.nl.nlmsg_pid = 0; + req.nl.nlmsg_seq = ++_seq; + req.ifa.ifa_family = addr.ss_family; + req.ifa.ifa_prefixlen = addr.port(); + req.ifa.ifa_flags = IFA_F_PERMANENT; + req.ifa.ifa_scope = 0; + req.ifa.ifa_index = interface_index; - struct sockaddr_nl pa; - bzero(&pa, sizeof(sockaddr_nl)); - pa.nl_family = AF_NETLINK; + struct sockaddr_nl pa; + bzero(&pa, sizeof(sockaddr_nl)); + pa.nl_family = AF_NETLINK; - struct msghdr msg; - bzero(&msg, sizeof(msg)); - msg.msg_name = (void*)&pa; - msg.msg_namelen = sizeof(pa); + struct msghdr msg; + bzero(&msg, sizeof(msg)); + msg.msg_name = (void*)&pa; + msg.msg_namelen = sizeof(pa); - struct iovec iov; - iov.iov_base = (void*)&req.nl; - iov.iov_len = req.nl.nlmsg_len; - msg.msg_iov = &iov; - msg.msg_iovlen = 1; - sendmsg(fd, &msg, 0); + struct iovec iov; + iov.iov_base = (void*)&req.nl; + iov.iov_len = req.nl.nlmsg_len; + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + sendmsg(fd, &msg, 0); - _doRecv(fd); + _doRecv(fd); - close(fd); + close(fd); } -void LinuxNetLink::removeAddress(const InetAddress &addr, const char *iface) +void LinuxNetLink::removeAddress(const InetAddress& addr, const char* iface) { - int fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); - if (fd == -1) { - fprintf(stderr, "Error opening RTNETLINK socket: %s\n", strerror(errno)); - return; - } + int fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); + if (fd == -1) { + fprintf(stderr, "Error opening RTNETLINK socket: %s\n", strerror(errno)); + return; + } - _setSocketTimeout(fd); + _setSocketTimeout(fd); - struct sockaddr_nl la; - la.nl_family = AF_NETLINK; - la.nl_pid = 0; //getpid(); - if (addr.isV4()) { - la.nl_groups = RTMGRP_IPV4_IFADDR; - } else { - la.nl_groups = RTMGRP_IPV6_IFADDR; - } - if(bind(fd, (struct sockaddr*)&la, sizeof(struct sockaddr_nl))) { - fprintf(stderr, "Error binding RTNETLINK (removeAddress #1): %s\n", strerror(errno)); - close(fd); - return; - } + struct sockaddr_nl la; + la.nl_family = AF_NETLINK; + la.nl_pid = 0; // getpid(); + if (addr.isV4()) { + la.nl_groups = RTMGRP_IPV4_IFADDR; + } + else { + la.nl_groups = RTMGRP_IPV6_IFADDR; + } + if (bind(fd, (struct sockaddr*)&la, sizeof(struct sockaddr_nl))) { + fprintf(stderr, "Error binding RTNETLINK (removeAddress #1): %s\n", strerror(errno)); + close(fd); + return; + } #ifdef ZT_NETLINK_TRACE - char tmp[128]; - fprintf(stderr, "Removing IP address %s from interface %s\n", addr.toString(tmp), iface); + char tmp[128]; + fprintf(stderr, "Removing IP address %s from interface %s\n", addr.toString(tmp), iface); #endif - int interface_index = _indexForInterface(iface); + int interface_index = _indexForInterface(iface); - if (interface_index == -1) { - fprintf(stderr, "Unable to find index for interface %s\n", iface); - close(fd); - return; - } + if (interface_index == -1) { + fprintf(stderr, "Unable to find index for interface %s\n", iface); + close(fd); + return; + } - int rtl = sizeof(struct ifaddrmsg); - struct nl_adr_req req; - bzero(&req, sizeof(struct nl_adr_req)); + int rtl = sizeof(struct ifaddrmsg); + struct nl_adr_req req; + bzero(&req, sizeof(struct nl_adr_req)); - struct rtattr *rtap = (struct rtattr *)req.buf; - if(addr.isV4()) { - struct sockaddr_in *addr_v4 = (struct sockaddr_in*)&addr; - rtap->rta_type = IFA_ADDRESS; - rtap->rta_len = RTA_LENGTH(sizeof(struct in_addr)); - memcpy(RTA_DATA(rtap), &addr_v4->sin_addr, sizeof(struct in_addr)); - rtl += rtap->rta_len; + struct rtattr* rtap = (struct rtattr*)req.buf; + if (addr.isV4()) { + struct sockaddr_in* addr_v4 = (struct sockaddr_in*)&addr; + rtap->rta_type = IFA_ADDRESS; + rtap->rta_len = RTA_LENGTH(sizeof(struct in_addr)); + memcpy(RTA_DATA(rtap), &addr_v4->sin_addr, sizeof(struct in_addr)); + rtl += rtap->rta_len; - rtap = (struct rtattr*)(((char*)rtap) + rtap->rta_len); - rtap->rta_type = IFA_LOCAL; - rtap->rta_len = RTA_LENGTH(sizeof(struct in_addr)); - memcpy(RTA_DATA(rtap), &addr_v4->sin_addr, sizeof(struct in_addr)); - rtl += rtap->rta_len; + rtap = (struct rtattr*)(((char*)rtap) + rtap->rta_len); + rtap->rta_type = IFA_LOCAL; + rtap->rta_len = RTA_LENGTH(sizeof(struct in_addr)); + memcpy(RTA_DATA(rtap), &addr_v4->sin_addr, sizeof(struct in_addr)); + rtl += rtap->rta_len; - InetAddress broadcast = addr.broadcast(); - if(broadcast) { - rtap = (struct rtattr*)(((char*)rtap)+rtap->rta_len); - struct sockaddr_in *bcast = (struct sockaddr_in*)&broadcast; - rtap->rta_type = IFA_BROADCAST; - rtap->rta_len = RTA_LENGTH(sizeof(struct in_addr)); - memcpy(RTA_DATA(rtap), &bcast->sin_addr, sizeof(struct in_addr)); - rtl += rtap->rta_len; - } - } else { //V6 - rtap->rta_type = IFA_ADDRESS; - struct sockaddr_in6 *addr_v6 = (struct sockaddr_in6*)&addr; - rtap->rta_len = RTA_LENGTH(sizeof(struct in6_addr)); - memcpy(RTA_DATA(rtap), &addr_v6->sin6_addr, sizeof(struct in6_addr)); - rtl += rtap->rta_len; - } + InetAddress broadcast = addr.broadcast(); + if (broadcast) { + rtap = (struct rtattr*)(((char*)rtap) + rtap->rta_len); + struct sockaddr_in* bcast = (struct sockaddr_in*)&broadcast; + rtap->rta_type = IFA_BROADCAST; + rtap->rta_len = RTA_LENGTH(sizeof(struct in_addr)); + memcpy(RTA_DATA(rtap), &bcast->sin_addr, sizeof(struct in_addr)); + rtl += rtap->rta_len; + } + } + else { // V6 + rtap->rta_type = IFA_ADDRESS; + struct sockaddr_in6* addr_v6 = (struct sockaddr_in6*)&addr; + rtap->rta_len = RTA_LENGTH(sizeof(struct in6_addr)); + memcpy(RTA_DATA(rtap), &addr_v6->sin6_addr, sizeof(struct in6_addr)); + rtl += rtap->rta_len; + } - if (iface) { - rtap = (struct rtattr*)(((char*)rtap)+rtap->rta_len); - rtap->rta_type = IFA_LABEL; - rtap->rta_len = RTA_LENGTH(strlen(iface)); - memcpy(RTA_DATA(rtap), iface, strlen(iface)); - rtl += rtap->rta_len; - } + if (iface) { + rtap = (struct rtattr*)(((char*)rtap) + rtap->rta_len); + rtap->rta_type = IFA_LABEL; + rtap->rta_len = RTA_LENGTH(strlen(iface)); + memcpy(RTA_DATA(rtap), iface, strlen(iface)); + rtl += rtap->rta_len; + } - req.nl.nlmsg_len = NLMSG_LENGTH(rtl); - req.nl.nlmsg_flags = NLM_F_REQUEST; - req.nl.nlmsg_type = RTM_DELADDR; - req.nl.nlmsg_pid = 0; - req.nl.nlmsg_seq = ++_seq; - req.ifa.ifa_family = addr.ss_family; - req.ifa.ifa_prefixlen = addr.port(); - req.ifa.ifa_flags = IFA_F_PERMANENT; - req.ifa.ifa_scope = 0; - req.ifa.ifa_index = interface_index; + req.nl.nlmsg_len = NLMSG_LENGTH(rtl); + req.nl.nlmsg_flags = NLM_F_REQUEST; + req.nl.nlmsg_type = RTM_DELADDR; + req.nl.nlmsg_pid = 0; + req.nl.nlmsg_seq = ++_seq; + req.ifa.ifa_family = addr.ss_family; + req.ifa.ifa_prefixlen = addr.port(); + req.ifa.ifa_flags = IFA_F_PERMANENT; + req.ifa.ifa_scope = 0; + req.ifa.ifa_index = interface_index; - struct sockaddr_nl pa; - bzero(&pa, sizeof(sockaddr_nl)); - pa.nl_family = AF_NETLINK; + struct sockaddr_nl pa; + bzero(&pa, sizeof(sockaddr_nl)); + pa.nl_family = AF_NETLINK; - struct msghdr msg; - bzero(&msg, sizeof(msg)); - msg.msg_name = (void*)&pa; - msg.msg_namelen = sizeof(pa); + struct msghdr msg; + bzero(&msg, sizeof(msg)); + msg.msg_name = (void*)&pa; + msg.msg_namelen = sizeof(pa); - struct iovec iov; - iov.iov_base = (void*)&req.nl; - iov.iov_len = req.nl.nlmsg_len; - msg.msg_iov = &iov; - msg.msg_iovlen = 1; - sendmsg(fd, &msg, 0); + struct iovec iov; + iov.iov_base = (void*)&req.nl; + iov.iov_len = req.nl.nlmsg_len; + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + sendmsg(fd, &msg, 0); - _doRecv(fd); + _doRecv(fd); - close(fd); + close(fd); } -bool LinuxNetLink::routeIsSet(const InetAddress &target, const InetAddress &via, const InetAddress &src, const char *ifname) +bool LinuxNetLink::routeIsSet(const InetAddress& target, const InetAddress& via, const InetAddress& src, const char* ifname) { - Mutex::Lock rl(_routes_m); - const std::set &rs = _routes[target]; - for(std::set::const_iterator ri(rs.begin());ri!=rs.end();++ri) { - if ((ri->via == via)&&(ri->src == src)) { - if (ifname) { - Mutex::Lock ifl(_if_m); - const iface_entry *ife = _interfaces.get(ri->ifidx); - if ((ife)&&(!strncmp(ife->ifacename,ifname,IFNAMSIZ))) - return true; - } else { - return true; - } - } - } - return false; + Mutex::Lock rl(_routes_m); + const std::set& rs = _routes[target]; + for (std::set::const_iterator ri(rs.begin()); ri != rs.end(); ++ri) { + if ((ri->via == via) && (ri->src == src)) { + if (ifname) { + Mutex::Lock ifl(_if_m); + const iface_entry* ife = _interfaces.get(ri->ifidx); + if ((ife) && (! strncmp(ife->ifacename, ifname, IFNAMSIZ))) + return true; + } + else { + return true; + } + } + } + return false; } -int LinuxNetLink::_indexForInterface(const char *iface) +int LinuxNetLink::_indexForInterface(const char* iface) { - Mutex::Lock l(_if_m); - int interface_index = -1; - Hashtable::Iterator iter(_interfaces); - int *k = NULL; - iface_entry *v = NULL; - while(iter.next(k,v)) { - if(strcmp(iface, v->ifacename) == 0) { - interface_index = v->index; - break; - } - } - return interface_index; + Mutex::Lock l(_if_m); + int interface_index = -1; + Hashtable::Iterator iter(_interfaces); + int* k = NULL; + iface_entry* v = NULL; + while (iter.next(k, v)) { + if (strcmp(iface, v->ifacename) == 0) { + interface_index = v->index; + break; + } + } + return interface_index; } -} // namespace ZeroTier +} // namespace ZeroTier #endif diff --git a/osdep/LinuxNetLink.hpp b/osdep/LinuxNetLink.hpp index f7d8ba2d..935a656a 100644 --- a/osdep/LinuxNetLink.hpp +++ b/osdep/LinuxNetLink.hpp @@ -18,135 +18,146 @@ #ifdef __LINUX__ -#include -#include -#include - -#include #include #include +#include +#include #include -//#include +#include +// #include +#include "../node/Hashtable.hpp" #include "../node/InetAddress.hpp" #include "../node/MAC.hpp" -#include "Thread.hpp" -#include "../node/Hashtable.hpp" #include "../node/Mutex.hpp" - +#include "Thread.hpp" namespace ZeroTier { /** * Interface with Linux's RTNETLINK */ -class LinuxNetLink -{ -private: - LinuxNetLink(); - ~LinuxNetLink(); +class LinuxNetLink { + private: + LinuxNetLink(); + ~LinuxNetLink(); -public: - struct Route { - InetAddress target; - InetAddress via; - InetAddress src; - int ifidx; + public: + struct Route { + InetAddress target; + InetAddress via; + InetAddress src; + int ifidx; - inline bool operator==(const Route &r) const - { return ((target == r.target)&&(via == r.via)&&(src == r.src)&&(ifidx == r.ifidx)); } - inline bool operator!=(const Route &r) const - { return (!(*this == r)); } - inline bool operator<(const Route &r) const - { - if (target < r.target) { - return true; - } else if (target == r.target) { - if (via < r.via) { - return true; - } else if (via == r.via) { - if (src < r.src) { - return true; - } else if (src == r.src) { - return (ifidx < r.ifidx); - } - } - } - return false; - } - inline bool operator>(const Route &r) const - { return (r < *this); } - inline bool operator<=(const Route &r) const - { return !(r < *this); } - inline bool operator>=(const Route &r) const - { return !(*this < r); } - }; + inline bool operator==(const Route& r) const + { + return ((target == r.target) && (via == r.via) && (src == r.src) && (ifidx == r.ifidx)); + } + inline bool operator!=(const Route& r) const + { + return (! (*this == r)); + } + inline bool operator<(const Route& r) const + { + if (target < r.target) { + return true; + } + else if (target == r.target) { + if (via < r.via) { + return true; + } + else if (via == r.via) { + if (src < r.src) { + return true; + } + else if (src == r.src) { + return (ifidx < r.ifidx); + } + } + } + return false; + } + inline bool operator>(const Route& r) const + { + return (r < *this); + } + inline bool operator<=(const Route& r) const + { + return ! (r < *this); + } + inline bool operator>=(const Route& r) const + { + return ! (*this < r); + } + }; - static LinuxNetLink& getInstance() - { - static LinuxNetLink instance; - return instance; - } + static LinuxNetLink& getInstance() + { + static LinuxNetLink instance; + return instance; + } - LinuxNetLink(LinuxNetLink const&) = delete; - void operator=(LinuxNetLink const&) = delete; + LinuxNetLink(LinuxNetLink const&) = delete; + void operator=(LinuxNetLink const&) = delete; - void addRoute(const InetAddress &target, const InetAddress &via, const InetAddress &src, const char *ifaceName); - void delRoute(const InetAddress &target, const InetAddress &via, const InetAddress &src, const char *ifaceName); + void addRoute(const InetAddress& target, const InetAddress& via, const InetAddress& src, const char* ifaceName); + void delRoute(const InetAddress& target, const InetAddress& via, const InetAddress& src, const char* ifaceName); - void addAddress(const InetAddress &addr, const char *iface); - void removeAddress(const InetAddress &addr, const char *iface); + void addAddress(const InetAddress& addr, const char* iface); + void removeAddress(const InetAddress& addr, const char* iface); - bool routeIsSet(const InetAddress &target, const InetAddress &via, const InetAddress &src, const char *ifname); + bool routeIsSet(const InetAddress& target, const InetAddress& via, const InetAddress& src, const char* ifname); - void threadMain() throw(); + void threadMain() throw(); -private: - int _doRecv(int fd); + private: + int _doRecv(int fd); - void _processMessage(struct nlmsghdr *nlp, int nll); - void _routeAdded(struct nlmsghdr *nlp); - void _routeDeleted(struct nlmsghdr *nlp); - void _linkAdded(struct nlmsghdr *nlp); - void _linkDeleted(struct nlmsghdr *nlp); - void _ipAddressAdded(struct nlmsghdr *nlp); - void _ipAddressDeleted(struct nlmsghdr *nlp); + void _processMessage(struct nlmsghdr* nlp, int nll); + void _routeAdded(struct nlmsghdr* nlp); + void _routeDeleted(struct nlmsghdr* nlp); + void _linkAdded(struct nlmsghdr* nlp); + void _linkDeleted(struct nlmsghdr* nlp); + void _ipAddressAdded(struct nlmsghdr* nlp); + void _ipAddressDeleted(struct nlmsghdr* nlp); - void _requestInterfaceList(); - void _requestIPv4Routes(); - void _requestIPv6Routes(); + void _requestInterfaceList(); + void _requestIPv4Routes(); + void _requestIPv6Routes(); - int _indexForInterface(const char *iface); + int _indexForInterface(const char* iface); - void _setSocketTimeout(int fd, int seconds = 1); + void _setSocketTimeout(int fd, int seconds = 1); - Thread _t; - bool _running; + Thread _t; + bool _running; - uint32_t _seq; + uint32_t _seq; - std::map< InetAddress,std::set > _routes; - Mutex _routes_m; + std::map > _routes; + Mutex _routes_m; - struct iface_entry { - iface_entry() - { memset(this,0,sizeof(iface_entry)); } - int index; - char ifacename[16]; // IFNAMSIZ on Linux == 16 - char mac[18]; - char mac_bin[6]; - unsigned int mtu; - }; - Hashtable _interfaces; - Mutex _if_m; + struct iface_entry { + iface_entry() + { + memset(this, 0, sizeof(iface_entry)); + } + int index; + char ifacename[16]; // IFNAMSIZ on Linux == 16 + char mac[18]; + char mac_bin[6]; + unsigned int mtu; + }; + Hashtable _interfaces; + Mutex _if_m; - // socket communication vars; - int _fd; - struct sockaddr_nl _la; + // socket communication vars; + int _fd; + struct sockaddr_nl _la; }; -} +} // namespace ZeroTier #endif -#endif // ZT_LINUX_NETLINK_HPPS \ No newline at end of file +#endif // ZT_LINUX_NETLINK_HPPS \ No newline at end of file diff --git a/osdep/MacDNSHelper.hpp b/osdep/MacDNSHelper.hpp index fafbeec5..abe7cdd6 100644 --- a/osdep/MacDNSHelper.hpp +++ b/osdep/MacDNSHelper.hpp @@ -1,23 +1,23 @@ #ifndef MAC_DNS_HELPER #define MAC_DNS_HELPER -#include #include "../node/InetAddress.hpp" #include "../node/MAC.hpp" +#include + namespace ZeroTier { -class MacDNSHelper -{ -public: - static void setDNS(uint64_t nwid, const char *domain, const std::vector &servers); +class MacDNSHelper { + public: + static void setDNS(uint64_t nwid, const char* domain, const std::vector& servers); static void removeDNS(uint64_t nwid); - static bool addIps4(uint64_t nwid, const MAC mac, const char *dev, const std::vector &addrs); - static bool addIps6(uint64_t nwid, const MAC mac, const char *dev, const std::vector &addrs); + static bool addIps4(uint64_t nwid, const MAC mac, const char* dev, const std::vector& addrs); + static bool addIps6(uint64_t nwid, const MAC mac, const char* dev, const std::vector& addrs); static bool removeIps4(uint64_t nwid); static bool removeIps6(uint64_t nwid); }; -} +} // namespace ZeroTier #endif diff --git a/osdep/MacEthernetTap.cpp b/osdep/MacEthernetTap.cpp index fdb584ee..18f2ae18 100644 --- a/osdep/MacEthernetTap.cpp +++ b/osdep/MacEthernetTap.cpp @@ -15,49 +15,45 @@ #ifdef __APPLE__ -#include "../node/Utils.hpp" -#include "../node/Mutex.hpp" #include "../node/Dictionary.hpp" -#include "OSUtils.hpp" +#include "../node/Mutex.hpp" +#include "../node/Utils.hpp" +#include "MacDNSHelper.hpp" #include "MacEthernetTap.hpp" #include "MacEthernetTapAgent.h" -#include "MacDNSHelper.hpp" +#include "OSUtils.hpp" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include #include #include -#include - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - #include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include -static const ZeroTier::MulticastGroup _blindWildcardMulticastGroup(ZeroTier::MAC(0xff),0); +static const ZeroTier::MulticastGroup _blindWildcardMulticastGroup(ZeroTier::MAC(0xff), 0); #define MACOS_FETH_MAX_MTU_SYSCTL "net.link.fake.max_mtu" @@ -68,487 +64,504 @@ static bool globalTapInitialized = false; static bool fethMaxMtuAdjusted = false; MacEthernetTap::MacEthernetTap( - const char *homePath, - const MAC &mac, - unsigned int mtu, - unsigned int metric, - uint64_t nwid, - const char *friendlyName, - void (*handler)(void *,void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *data,unsigned int len), - void *arg) : - _handler(handler), - _arg(arg), - _nwid(nwid), - _homePath(homePath), - _mtu(mtu), - _metric(metric), - _devNo(0), - _agentStdin(-1), - _agentStdout(-1), - _agentStderr(-1), - _agentStdin2(-1), - _agentStdout2(-1), - _agentStderr2(-1), - _agentPid(-1), - _enabled(true), - _lastIfAddrsUpdate(0) + const char* homePath, + const MAC& mac, + unsigned int mtu, + unsigned int metric, + uint64_t nwid, + const char* friendlyName, + void (*handler)(void*, void*, uint64_t, const MAC&, const MAC&, unsigned int, unsigned int, const void* data, unsigned int len), + void* arg) + : _handler(handler) + , _arg(arg) + , _nwid(nwid) + , _homePath(homePath) + , _mtu(mtu) + , _metric(metric) + , _devNo(0) + , _agentStdin(-1) + , _agentStdout(-1) + , _agentStderr(-1) + , _agentStdin2(-1) + , _agentStdout2(-1) + , _agentStderr2(-1) + , _agentPid(-1) + , _enabled(true) + , _lastIfAddrsUpdate(0) { - char ethaddr[64],mtustr[16],devnostr[16],devstr[16],metricstr[16]; - OSUtils::ztsnprintf(ethaddr,sizeof(ethaddr),"%.2x:%.2x:%.2x:%.2x:%.2x:%.2x",(int)mac[0],(int)mac[1],(int)mac[2],(int)mac[3],(int)mac[4],(int)mac[5]); - OSUtils::ztsnprintf(mtustr,sizeof(mtustr),"%u",mtu); - OSUtils::ztsnprintf(metricstr,sizeof(metricstr),"%u",metric); + char ethaddr[64], mtustr[16], devnostr[16], devstr[16], metricstr[16]; + OSUtils::ztsnprintf(ethaddr, sizeof(ethaddr), "%.2x:%.2x:%.2x:%.2x:%.2x:%.2x", (int)mac[0], (int)mac[1], (int)mac[2], (int)mac[3], (int)mac[4], (int)mac[5]); + OSUtils::ztsnprintf(mtustr, sizeof(mtustr), "%u", mtu); + OSUtils::ztsnprintf(metricstr, sizeof(metricstr), "%u", metric); - std::string agentPath(homePath); - agentPath.push_back(ZT_PATH_SEPARATOR); - agentPath.append("MacEthernetTapAgent"); - if (!OSUtils::fileExists(agentPath.c_str())) - throw std::runtime_error("MacEthernetTapAgent not present in ZeroTier home"); + std::string agentPath(homePath); + agentPath.push_back(ZT_PATH_SEPARATOR); + agentPath.append("MacEthernetTapAgent"); + if (! OSUtils::fileExists(agentPath.c_str())) + throw std::runtime_error("MacEthernetTapAgent not present in ZeroTier home"); - Mutex::Lock _gl(globalTapCreateLock); // only make one at a time + Mutex::Lock _gl(globalTapCreateLock); // only make one at a time - if (!fethMaxMtuAdjusted) { - fethMaxMtuAdjusted = true; - int old_mtu = 0; - size_t old_mtu_len = sizeof(old_mtu); - int mtu = 10000; - sysctlbyname(MACOS_FETH_MAX_MTU_SYSCTL, &old_mtu, &old_mtu_len, &mtu, sizeof(mtu)); - } + if (! fethMaxMtuAdjusted) { + fethMaxMtuAdjusted = true; + int old_mtu = 0; + size_t old_mtu_len = sizeof(old_mtu); + int mtu = 10000; + sysctlbyname(MACOS_FETH_MAX_MTU_SYSCTL, &old_mtu, &old_mtu_len, &mtu, sizeof(mtu)); + } - // Destroy all feth devices on first tap start in case ZeroTier did not exit cleanly last time. - // We leave interfaces less than feth100 alone in case something else is messing with feth devices. - if (!globalTapInitialized) { - globalTapInitialized = true; - struct ifaddrs *ifa = (struct ifaddrs *)0; - std::set deleted; - if (!getifaddrs(&ifa)) { - struct ifaddrs *p = ifa; - while (p) { - int nameLen = (int)strlen(p->ifa_name); - // Delete feth# from feth0 to feth9999, but don't touch >10000. - if ((!strncmp(p->ifa_name,"feth",4))&&(nameLen >= 5)&&(nameLen <= 8)&&(deleted.count(std::string(p->ifa_name)) == 0)) { - deleted.insert(std::string(p->ifa_name)); - const char *args[4]; - args[0] = "/sbin/ifconfig"; - args[1] = p->ifa_name; - args[2] = "destroy"; - args[3] = (char *)0; - const pid_t pid = vfork(); - if (pid == 0) { - execv(args[0],const_cast(args)); - _exit(-1); - } else if (pid > 0) { - int rv = 0; - waitpid(pid,&rv,0); - } - } - p = p->ifa_next; - } - freeifaddrs(ifa); - } - } + // Destroy all feth devices on first tap start in case ZeroTier did not exit cleanly last time. + // We leave interfaces less than feth100 alone in case something else is messing with feth devices. + if (! globalTapInitialized) { + globalTapInitialized = true; + struct ifaddrs* ifa = (struct ifaddrs*)0; + std::set deleted; + if (! getifaddrs(&ifa)) { + struct ifaddrs* p = ifa; + while (p) { + int nameLen = (int)strlen(p->ifa_name); + // Delete feth# from feth0 to feth9999, but don't touch >10000. + if ((! strncmp(p->ifa_name, "feth", 4)) && (nameLen >= 5) && (nameLen <= 8) && (deleted.count(std::string(p->ifa_name)) == 0)) { + deleted.insert(std::string(p->ifa_name)); + const char* args[4]; + args[0] = "/sbin/ifconfig"; + args[1] = p->ifa_name; + args[2] = "destroy"; + args[3] = (char*)0; + const pid_t pid = vfork(); + if (pid == 0) { + execv(args[0], const_cast(args)); + _exit(-1); + } + else if (pid > 0) { + int rv = 0; + waitpid(pid, &rv, 0); + } + } + p = p->ifa_next; + } + freeifaddrs(ifa); + } + } - unsigned int devNo = 100 + ((nwid ^ (nwid >> 32) ^ (nwid >> 48)) % 4900); - for(;;) { - OSUtils::ztsnprintf(devnostr,sizeof(devnostr),"%u",devNo); - OSUtils::ztsnprintf(devstr,sizeof(devstr),"feth%u",devNo); - bool duplicate = false; - struct ifaddrs *ifa = (struct ifaddrs *)0; - if (!getifaddrs(&ifa)) { - struct ifaddrs *p = ifa; - while (p) { - if (!strcmp(p->ifa_name,devstr)) { - duplicate = true; - break; - } - p = p->ifa_next; - } - freeifaddrs(ifa); - } - if (duplicate) { - devNo = (devNo + 1) % 5000; - if (devNo < 100) - devNo = 100; - } else { - _dev = devstr; - _devNo = devNo; - break; - } - } + unsigned int devNo = 100 + ((nwid ^ (nwid >> 32) ^ (nwid >> 48)) % 4900); + for (;;) { + OSUtils::ztsnprintf(devnostr, sizeof(devnostr), "%u", devNo); + OSUtils::ztsnprintf(devstr, sizeof(devstr), "feth%u", devNo); + bool duplicate = false; + struct ifaddrs* ifa = (struct ifaddrs*)0; + if (! getifaddrs(&ifa)) { + struct ifaddrs* p = ifa; + while (p) { + if (! strcmp(p->ifa_name, devstr)) { + duplicate = true; + break; + } + p = p->ifa_next; + } + freeifaddrs(ifa); + } + if (duplicate) { + devNo = (devNo + 1) % 5000; + if (devNo < 100) + devNo = 100; + } + else { + _dev = devstr; + _devNo = devNo; + break; + } + } - if (::pipe(_shutdownSignalPipe)) - throw std::runtime_error("pipe creation failed"); + if (::pipe(_shutdownSignalPipe)) + throw std::runtime_error("pipe creation failed"); - int agentStdin[2]; - int agentStdout[2]; - int agentStderr[2]; - if (::pipe(agentStdin)) - throw std::runtime_error("pipe creation failed"); - if (::pipe(agentStdout)) - throw std::runtime_error("pipe creation failed"); - if (::pipe(agentStderr)) - throw std::runtime_error("pipe creation failed"); - _agentStdin = agentStdin[1]; - _agentStdout = agentStdout[0]; - _agentStderr = agentStderr[0]; - _agentStdin2 = agentStdin[0]; - _agentStdout2 = agentStdout[1]; - _agentStderr2 = agentStderr[1]; - long apid = (long)fork(); - if (apid < 0) { - throw std::runtime_error("fork failed"); - } else if (apid == 0) { - ::dup2(agentStdin[0],STDIN_FILENO); - ::dup2(agentStdout[1],STDOUT_FILENO); - ::dup2(agentStderr[1],STDERR_FILENO); - ::close(agentStdin[0]); - ::close(agentStdin[1]); - ::close(agentStdout[0]); - ::close(agentStdout[1]); - ::close(agentStderr[0]); - ::close(agentStderr[1]); - ::execl(agentPath.c_str(),agentPath.c_str(),devnostr,ethaddr,mtustr,metricstr,(char *)0); - ::_exit(-1); - } else { - _agentPid = apid; + int agentStdin[2]; + int agentStdout[2]; + int agentStderr[2]; + if (::pipe(agentStdin)) + throw std::runtime_error("pipe creation failed"); + if (::pipe(agentStdout)) + throw std::runtime_error("pipe creation failed"); + if (::pipe(agentStderr)) + throw std::runtime_error("pipe creation failed"); + _agentStdin = agentStdin[1]; + _agentStdout = agentStdout[0]; + _agentStderr = agentStderr[0]; + _agentStdin2 = agentStdin[0]; + _agentStdout2 = agentStdout[1]; + _agentStderr2 = agentStderr[1]; + long apid = (long)fork(); + if (apid < 0) { + throw std::runtime_error("fork failed"); + } + else if (apid == 0) { + ::dup2(agentStdin[0], STDIN_FILENO); + ::dup2(agentStdout[1], STDOUT_FILENO); + ::dup2(agentStderr[1], STDERR_FILENO); + ::close(agentStdin[0]); + ::close(agentStdin[1]); + ::close(agentStdout[0]); + ::close(agentStdout[1]); + ::close(agentStderr[0]); + ::close(agentStderr[1]); + ::execl(agentPath.c_str(), agentPath.c_str(), devnostr, ethaddr, mtustr, metricstr, (char*)0); + ::_exit(-1); + } + else { + _agentPid = apid; - // Wait up to 10 seconds for the subprocess to actually create the device. This prevents - // things like routes from being created before the device exists. - for(int waitLoops=0;;++waitLoops) { - struct ifaddrs *ifa = (struct ifaddrs *)0; - if (!getifaddrs(&ifa)) { - struct ifaddrs *p = ifa; - while (p) { - if ((p->ifa_name)&&(!strcmp(devstr, p->ifa_name))) { - waitLoops = -1; - break; - } - p = p->ifa_next; - } - freeifaddrs(ifa); - } - if (waitLoops == -1) { - break; - } else if (waitLoops >= 100) { // 10 seconds - throw std::runtime_error("feth device creation timed out"); - } - Thread::sleep(100); - } - } + // Wait up to 10 seconds for the subprocess to actually create the device. This prevents + // things like routes from being created before the device exists. + for (int waitLoops = 0;; ++waitLoops) { + struct ifaddrs* ifa = (struct ifaddrs*)0; + if (! getifaddrs(&ifa)) { + struct ifaddrs* p = ifa; + while (p) { + if ((p->ifa_name) && (! strcmp(devstr, p->ifa_name))) { + waitLoops = -1; + break; + } + p = p->ifa_next; + } + freeifaddrs(ifa); + } + if (waitLoops == -1) { + break; + } + else if (waitLoops >= 100) { // 10 seconds + throw std::runtime_error("feth device creation timed out"); + } + Thread::sleep(100); + } + } - _thread = Thread::start(this); + _thread = Thread::start(this); } MacEthernetTap::~MacEthernetTap() { - char tmp[64]; - const char *args[4]; - pid_t pid0,pid1; + char tmp[64]; + const char* args[4]; + pid_t pid0, pid1; - MacDNSHelper::removeDNS(_nwid); - MacDNSHelper::removeIps4(_nwid); - MacDNSHelper::removeIps6(_nwid); + MacDNSHelper::removeDNS(_nwid); + MacDNSHelper::removeIps4(_nwid); + MacDNSHelper::removeIps6(_nwid); - Mutex::Lock _gl(globalTapCreateLock); - ::write(_shutdownSignalPipe[1],"\0",1); // causes thread to exit + Mutex::Lock _gl(globalTapCreateLock); + ::write(_shutdownSignalPipe[1], "\0", 1); // causes thread to exit - int ec = 0; - ::kill(_agentPid,SIGKILL); - ::waitpid(_agentPid,&ec,0); + int ec = 0; + ::kill(_agentPid, SIGKILL); + ::waitpid(_agentPid, &ec, 0); - args[0] = "/sbin/ifconfig"; - args[1] = _dev.c_str(); - args[2] = "destroy"; - args[3] = (char *)0; - pid0 = vfork(); - if (pid0 == 0) { - execv(args[0],const_cast(args)); - _exit(-1); - } + args[0] = "/sbin/ifconfig"; + args[1] = _dev.c_str(); + args[2] = "destroy"; + args[3] = (char*)0; + pid0 = vfork(); + if (pid0 == 0) { + execv(args[0], const_cast(args)); + _exit(-1); + } - snprintf(tmp,sizeof(tmp),"feth%u",_devNo + 5000); - //args[0] = "/sbin/ifconfig"; - args[1] = tmp; - //args[2] = "destroy"; - //args[3] = (char *)0; - pid1 = vfork(); - if (pid1 == 0) { - execv(args[0],const_cast(args)); - _exit(-1); - } + snprintf(tmp, sizeof(tmp), "feth%u", _devNo + 5000); + // args[0] = "/sbin/ifconfig"; + args[1] = tmp; + // args[2] = "destroy"; + // args[3] = (char *)0; + pid1 = vfork(); + if (pid1 == 0) { + execv(args[0], const_cast(args)); + _exit(-1); + } - if (pid0 > 0) { - int rv = 0; - waitpid(pid0,&rv,0); - } - if (pid1 > 0) { - int rv = 0; - waitpid(pid1,&rv,0); - } + if (pid0 > 0) { + int rv = 0; + waitpid(pid0, &rv, 0); + } + if (pid1 > 0) { + int rv = 0; + waitpid(pid1, &rv, 0); + } - Thread::join(_thread); + Thread::join(_thread); } -void MacEthernetTap::setEnabled(bool en) { _enabled = en; } -bool MacEthernetTap::enabled() const { return _enabled; } - -bool MacEthernetTap::addIp(const InetAddress &ip) +void MacEthernetTap::setEnabled(bool en) { - char tmp[128]; - - if (!ip) - return false; - - std::string cmd; - cmd.push_back((char)ZT_MACETHERNETTAPAGENT_STDIN_CMD_IFCONFIG); - cmd.append((ip.ss_family == AF_INET6) ? "inet6" : "inet"); - cmd.push_back(0); - cmd.append(ip.toString(tmp)); - cmd.push_back(0); - cmd.append("alias"); - cmd.push_back(0); - - uint16_t l = (uint16_t)cmd.length(); - _putLock.lock(); - write(_agentStdin,&l,2); - write(_agentStdin,cmd.data(),cmd.length()); - _putLock.unlock(); - - return true; + _enabled = en; +} +bool MacEthernetTap::enabled() const +{ + return _enabled; } -bool MacEthernetTap::removeIp(const InetAddress &ip) +bool MacEthernetTap::addIp(const InetAddress& ip) { - char tmp[128]; + char tmp[128]; - if (!ip) - return false; + if (! ip) + return false; - std::string cmd; - cmd.push_back((char)ZT_MACETHERNETTAPAGENT_STDIN_CMD_IFCONFIG); - cmd.append((ip.ss_family == AF_INET6) ? "inet6" : "inet"); - cmd.push_back(0); - cmd.append(ip.toString(tmp)); - cmd.push_back(0); - cmd.append("-alias"); - cmd.push_back(0); + std::string cmd; + cmd.push_back((char)ZT_MACETHERNETTAPAGENT_STDIN_CMD_IFCONFIG); + cmd.append((ip.ss_family == AF_INET6) ? "inet6" : "inet"); + cmd.push_back(0); + cmd.append(ip.toString(tmp)); + cmd.push_back(0); + cmd.append("alias"); + cmd.push_back(0); - uint16_t l = (uint16_t)cmd.length(); - _putLock.lock(); - write(_agentStdin,&l,2); - write(_agentStdin,cmd.data(),cmd.length()); - _putLock.unlock(); + uint16_t l = (uint16_t)cmd.length(); + _putLock.lock(); + write(_agentStdin, &l, 2); + write(_agentStdin, cmd.data(), cmd.length()); + _putLock.unlock(); - return true; + return true; +} + +bool MacEthernetTap::removeIp(const InetAddress& ip) +{ + char tmp[128]; + + if (! ip) + return false; + + std::string cmd; + cmd.push_back((char)ZT_MACETHERNETTAPAGENT_STDIN_CMD_IFCONFIG); + cmd.append((ip.ss_family == AF_INET6) ? "inet6" : "inet"); + cmd.push_back(0); + cmd.append(ip.toString(tmp)); + cmd.push_back(0); + cmd.append("-alias"); + cmd.push_back(0); + + uint16_t l = (uint16_t)cmd.length(); + _putLock.lock(); + write(_agentStdin, &l, 2); + write(_agentStdin, cmd.data(), cmd.length()); + _putLock.unlock(); + + return true; } std::vector MacEthernetTap::ips() const { - uint64_t now = OSUtils::now(); + uint64_t now = OSUtils::now(); - if ((now - _lastIfAddrsUpdate) <= GETIFADDRS_CACHE_TIME) { - return _ifaddrs; - } - _lastIfAddrsUpdate = now; + if ((now - _lastIfAddrsUpdate) <= GETIFADDRS_CACHE_TIME) { + return _ifaddrs; + } + _lastIfAddrsUpdate = now; - struct ifaddrs *ifa = (struct ifaddrs *)0; - std::vector r; + struct ifaddrs* ifa = (struct ifaddrs*)0; + std::vector r; - if (!getifaddrs(&ifa)) { - struct ifaddrs *p = ifa; - while (p) { - if ((p->ifa_name)&&(!strcmp(p->ifa_name,_dev.c_str()))&&(p->ifa_addr)) { - switch(p->ifa_addr->sa_family) { - case AF_INET: { - struct sockaddr_in *sin = (struct sockaddr_in *)p->ifa_addr; - struct sockaddr_in *nm = (struct sockaddr_in *)p->ifa_netmask; - r.push_back(InetAddress(&(sin->sin_addr.s_addr),4,Utils::countBits((uint32_t)nm->sin_addr.s_addr))); - } break; - case AF_INET6: { - struct sockaddr_in6 *sin = (struct sockaddr_in6 *)p->ifa_addr; - struct sockaddr_in6 *nm = (struct sockaddr_in6 *)p->ifa_netmask; - uint32_t b[4]; - memcpy(b,nm->sin6_addr.s6_addr,sizeof(b)); - r.push_back(InetAddress(sin->sin6_addr.s6_addr,16,Utils::countBits(b[0]) + Utils::countBits(b[1]) + Utils::countBits(b[2]) + Utils::countBits(b[3]))); - } break; - } - } - p = p->ifa_next; - } - freeifaddrs(ifa); - } - std::sort(r.begin(),r.end()); - r.erase(std::unique(r.begin(),r.end()),r.end()); + if (! getifaddrs(&ifa)) { + struct ifaddrs* p = ifa; + while (p) { + if ((p->ifa_name) && (! strcmp(p->ifa_name, _dev.c_str())) && (p->ifa_addr)) { + switch (p->ifa_addr->sa_family) { + case AF_INET: { + struct sockaddr_in* sin = (struct sockaddr_in*)p->ifa_addr; + struct sockaddr_in* nm = (struct sockaddr_in*)p->ifa_netmask; + r.push_back(InetAddress(&(sin->sin_addr.s_addr), 4, Utils::countBits((uint32_t)nm->sin_addr.s_addr))); + } break; + case AF_INET6: { + struct sockaddr_in6* sin = (struct sockaddr_in6*)p->ifa_addr; + struct sockaddr_in6* nm = (struct sockaddr_in6*)p->ifa_netmask; + uint32_t b[4]; + memcpy(b, nm->sin6_addr.s6_addr, sizeof(b)); + r.push_back(InetAddress(sin->sin6_addr.s6_addr, 16, Utils::countBits(b[0]) + Utils::countBits(b[1]) + Utils::countBits(b[2]) + Utils::countBits(b[3]))); + } break; + } + } + p = p->ifa_next; + } + freeifaddrs(ifa); + } + std::sort(r.begin(), r.end()); + r.erase(std::unique(r.begin(), r.end()), r.end()); - _ifaddrs = r; + _ifaddrs = r; - return r; + return r; } -void MacEthernetTap::put(const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len) +void MacEthernetTap::put(const MAC& from, const MAC& to, unsigned int etherType, const void* data, unsigned int len) { - struct iovec iov[3]; - unsigned char hdr[15]; - uint16_t l; - if ((_agentStdin > 0)&&(len <= _mtu)&&(_enabled)) { - hdr[0] = ZT_MACETHERNETTAPAGENT_STDIN_CMD_PACKET; - to.copyTo(hdr + 1,6); - from.copyTo(hdr + 7,6); - hdr[13] = (unsigned char)((etherType >> 8) & 0xff); - hdr[14] = (unsigned char)(etherType & 0xff); - l = (uint16_t)(len + 15); - iov[0].iov_base = &l; - iov[0].iov_len = 2; - iov[1].iov_base = hdr; - iov[1].iov_len = 15; - iov[2].iov_base = const_cast(data); - iov[2].iov_len = len; - _putLock.lock(); - writev(_agentStdin,iov,3); - _putLock.unlock(); - } + struct iovec iov[3]; + unsigned char hdr[15]; + uint16_t l; + if ((_agentStdin > 0) && (len <= _mtu) && (_enabled)) { + hdr[0] = ZT_MACETHERNETTAPAGENT_STDIN_CMD_PACKET; + to.copyTo(hdr + 1, 6); + from.copyTo(hdr + 7, 6); + hdr[13] = (unsigned char)((etherType >> 8) & 0xff); + hdr[14] = (unsigned char)(etherType & 0xff); + l = (uint16_t)(len + 15); + iov[0].iov_base = &l; + iov[0].iov_len = 2; + iov[1].iov_base = hdr; + iov[1].iov_len = 15; + iov[2].iov_base = const_cast(data); + iov[2].iov_len = len; + _putLock.lock(); + writev(_agentStdin, iov, 3); + _putLock.unlock(); + } } -std::string MacEthernetTap::deviceName() const { return _dev; } -void MacEthernetTap::setFriendlyName(const char *friendlyName) {} - -void MacEthernetTap::scanMulticastGroups(std::vector &added,std::vector &removed) +std::string MacEthernetTap::deviceName() const { - std::vector newGroups; + return _dev; +} +void MacEthernetTap::setFriendlyName(const char* friendlyName) +{ +} - struct ifmaddrs *ifmap = (struct ifmaddrs *)0; - if (!getifmaddrs(&ifmap)) { - struct ifmaddrs *p = ifmap; - while (p) { - if (p->ifma_addr->sa_family == AF_LINK) { - struct sockaddr_dl *in = (struct sockaddr_dl *)p->ifma_name; - struct sockaddr_dl *la = (struct sockaddr_dl *)p->ifma_addr; - if ((la->sdl_alen == 6)&&(in->sdl_nlen <= _dev.length())&&(!memcmp(_dev.data(),in->sdl_data,in->sdl_nlen))) - newGroups.push_back(MulticastGroup(MAC(la->sdl_data + la->sdl_nlen,6),0)); - } - p = p->ifma_next; - } - freeifmaddrs(ifmap); - } +void MacEthernetTap::scanMulticastGroups(std::vector& added, std::vector& removed) +{ + std::vector newGroups; - std::vector allIps(ips()); - for(std::vector::iterator ip(allIps.begin());ip!=allIps.end();++ip) - newGroups.push_back(MulticastGroup::deriveMulticastGroupForAddressResolution(*ip)); + struct ifmaddrs* ifmap = (struct ifmaddrs*)0; + if (! getifmaddrs(&ifmap)) { + struct ifmaddrs* p = ifmap; + while (p) { + if (p->ifma_addr->sa_family == AF_LINK) { + struct sockaddr_dl* in = (struct sockaddr_dl*)p->ifma_name; + struct sockaddr_dl* la = (struct sockaddr_dl*)p->ifma_addr; + if ((la->sdl_alen == 6) && (in->sdl_nlen <= _dev.length()) && (! memcmp(_dev.data(), in->sdl_data, in->sdl_nlen))) + newGroups.push_back(MulticastGroup(MAC(la->sdl_data + la->sdl_nlen, 6), 0)); + } + p = p->ifma_next; + } + freeifmaddrs(ifmap); + } - std::sort(newGroups.begin(),newGroups.end()); - newGroups.erase(std::unique(newGroups.begin(),newGroups.end()),newGroups.end()); + std::vector allIps(ips()); + for (std::vector::iterator ip(allIps.begin()); ip != allIps.end(); ++ip) + newGroups.push_back(MulticastGroup::deriveMulticastGroupForAddressResolution(*ip)); - for(std::vector::iterator m(newGroups.begin());m!=newGroups.end();++m) { - if (!std::binary_search(_multicastGroups.begin(),_multicastGroups.end(),*m)) - added.push_back(*m); - } - for(std::vector::iterator m(_multicastGroups.begin());m!=_multicastGroups.end();++m) { - if (!std::binary_search(newGroups.begin(),newGroups.end(),*m)) - removed.push_back(*m); - } + std::sort(newGroups.begin(), newGroups.end()); + newGroups.erase(std::unique(newGroups.begin(), newGroups.end()), newGroups.end()); - _multicastGroups.swap(newGroups); + for (std::vector::iterator m(newGroups.begin()); m != newGroups.end(); ++m) { + if (! std::binary_search(_multicastGroups.begin(), _multicastGroups.end(), *m)) + added.push_back(*m); + } + for (std::vector::iterator m(_multicastGroups.begin()); m != _multicastGroups.end(); ++m) { + if (! std::binary_search(newGroups.begin(), newGroups.end(), *m)) + removed.push_back(*m); + } + + _multicastGroups.swap(newGroups); } void MacEthernetTap::setMtu(unsigned int mtu) { - if (_mtu != mtu) { - char tmp[16]; - std::string cmd; - cmd.push_back((char)ZT_MACETHERNETTAPAGENT_STDIN_CMD_IFCONFIG); - cmd.append("mtu"); - cmd.push_back(0); - OSUtils::ztsnprintf(tmp,sizeof(tmp),"%u",mtu); - cmd.append(tmp); - cmd.push_back(0); - uint16_t l = (uint16_t)cmd.length(); - _putLock.lock(); - write(_agentStdin,&l,2); - write(_agentStdin,cmd.data(),cmd.length()); - _putLock.unlock(); - _mtu = mtu; - } + if (_mtu != mtu) { + char tmp[16]; + std::string cmd; + cmd.push_back((char)ZT_MACETHERNETTAPAGENT_STDIN_CMD_IFCONFIG); + cmd.append("mtu"); + cmd.push_back(0); + OSUtils::ztsnprintf(tmp, sizeof(tmp), "%u", mtu); + cmd.append(tmp); + cmd.push_back(0); + uint16_t l = (uint16_t)cmd.length(); + _putLock.lock(); + write(_agentStdin, &l, 2); + write(_agentStdin, cmd.data(), cmd.length()); + _putLock.unlock(); + _mtu = mtu; + } } #define ZT_MACETHERNETTAP_AGENT_READ_BUF_SIZE 131072 -void MacEthernetTap::threadMain() - throw() +void MacEthernetTap::threadMain() throw() { - char agentReadBuf[ZT_MACETHERNETTAP_AGENT_READ_BUF_SIZE]; - char agentStderrBuf[256]; - fd_set readfds,nullfds; - MAC to,from; + char agentReadBuf[ZT_MACETHERNETTAP_AGENT_READ_BUF_SIZE]; + char agentStderrBuf[256]; + fd_set readfds, nullfds; + MAC to, from; - Thread::sleep(250); + Thread::sleep(250); - const int nfds = std::max(std::max(_shutdownSignalPipe[0],_agentStdout),_agentStderr) + 1; - long agentReadPtr = 0; - fcntl(_agentStdout,F_SETFL,fcntl(_agentStdout,F_GETFL)|O_NONBLOCK); - fcntl(_agentStderr,F_SETFL,fcntl(_agentStderr,F_GETFL)|O_NONBLOCK); + const int nfds = std::max(std::max(_shutdownSignalPipe[0], _agentStdout), _agentStderr) + 1; + long agentReadPtr = 0; + fcntl(_agentStdout, F_SETFL, fcntl(_agentStdout, F_GETFL) | O_NONBLOCK); + fcntl(_agentStderr, F_SETFL, fcntl(_agentStderr, F_GETFL) | O_NONBLOCK); - FD_ZERO(&readfds); - FD_ZERO(&nullfds); - for(;;) { - FD_SET(_shutdownSignalPipe[0],&readfds); - FD_SET(_agentStdout,&readfds); - FD_SET(_agentStderr,&readfds); - select(nfds,&readfds,&nullfds,&nullfds,(struct timeval *)0); + FD_ZERO(&readfds); + FD_ZERO(&nullfds); + for (;;) { + FD_SET(_shutdownSignalPipe[0], &readfds); + FD_SET(_agentStdout, &readfds); + FD_SET(_agentStderr, &readfds); + select(nfds, &readfds, &nullfds, &nullfds, (struct timeval*)0); - if (FD_ISSET(_shutdownSignalPipe[0],&readfds)) - break; + if (FD_ISSET(_shutdownSignalPipe[0], &readfds)) + break; - if (FD_ISSET(_agentStdout,&readfds)) { - long n = (long)read(_agentStdout,agentReadBuf + agentReadPtr,ZT_MACETHERNETTAP_AGENT_READ_BUF_SIZE - agentReadPtr); - if (n > 0) { - agentReadPtr += n; - while (agentReadPtr >= 2) { - long len = *((uint16_t *)agentReadBuf); - if (agentReadPtr >= (len + 2)) { - char *msg = agentReadBuf + 2; + if (FD_ISSET(_agentStdout, &readfds)) { + long n = (long)read(_agentStdout, agentReadBuf + agentReadPtr, ZT_MACETHERNETTAP_AGENT_READ_BUF_SIZE - agentReadPtr); + if (n > 0) { + agentReadPtr += n; + while (agentReadPtr >= 2) { + long len = *((uint16_t*)agentReadBuf); + if (agentReadPtr >= (len + 2)) { + char* msg = agentReadBuf + 2; - if ((len > 14)&&(_enabled)) { - to.setTo(msg,6); - from.setTo(msg + 6,6); - _handler(_arg,(void *)0,_nwid,from,to,ntohs(((const uint16_t *)msg)[6]),0,(const void *)(msg + 14),(unsigned int)len - 14); - } + if ((len > 14) && (_enabled)) { + to.setTo(msg, 6); + from.setTo(msg + 6, 6); + _handler(_arg, (void*)0, _nwid, from, to, ntohs(((const uint16_t*)msg)[6]), 0, (const void*)(msg + 14), (unsigned int)len - 14); + } - if (agentReadPtr > (len + 2)) { - memmove(agentReadBuf,agentReadBuf + len + 2,agentReadPtr -= (len + 2)); - } else { - agentReadPtr = 0; - } - } else { - break; - } - } - } - } + if (agentReadPtr > (len + 2)) { + memmove(agentReadBuf, agentReadBuf + len + 2, agentReadPtr -= (len + 2)); + } + else { + agentReadPtr = 0; + } + } + else { + break; + } + } + } + } - if (FD_ISSET(_agentStderr,&readfds)) { - read(_agentStderr,agentStderrBuf,sizeof(agentStderrBuf)); - /* - const ssize_t n = read(_agentStderr,agentStderrBuf,sizeof(agentStderrBuf)); - if (n > 0) - write(STDERR_FILENO,agentStderrBuf,(size_t)n); - */ - } - } + if (FD_ISSET(_agentStderr, &readfds)) { + read(_agentStderr, agentStderrBuf, sizeof(agentStderrBuf)); + /* + const ssize_t n = read(_agentStderr,agentStderrBuf,sizeof(agentStderrBuf)); + if (n > 0) + write(STDERR_FILENO,agentStderrBuf,(size_t)n); + */ + } + } - ::close(_agentStdin); - ::close(_agentStdout); - ::close(_agentStderr); - ::close(_agentStdin2); - ::close(_agentStdout2); - ::close(_agentStderr2); - ::close(_shutdownSignalPipe[0]); - ::close(_shutdownSignalPipe[1]); + ::close(_agentStdin); + ::close(_agentStdout); + ::close(_agentStderr); + ::close(_agentStdin2); + ::close(_agentStdout2); + ::close(_agentStderr2); + ::close(_shutdownSignalPipe[0]); + ::close(_shutdownSignalPipe[1]); } -void MacEthernetTap::setDns(const char *domain, const std::vector &servers) +void MacEthernetTap::setDns(const char* domain, const std::vector& servers) { - MacDNSHelper::setDNS(this->_nwid, domain, servers); + MacDNSHelper::setDNS(this->_nwid, domain, servers); } -} // namespace ZeroTier +} // namespace ZeroTier -#endif // __APPLE__ +#endif // __APPLE__ diff --git a/osdep/MacEthernetTap.hpp b/osdep/MacEthernetTap.hpp index e9ea0879..eea1ff94 100644 --- a/osdep/MacEthernetTap.hpp +++ b/osdep/MacEthernetTap.hpp @@ -15,73 +15,69 @@ #define ZT_OSXETHERNETTAP_HPP #include "../node/Constants.hpp" -#include "../node/MAC.hpp" #include "../node/InetAddress.hpp" +#include "../node/MAC.hpp" #include "../node/MulticastGroup.hpp" #include "../node/Mutex.hpp" -#include "Thread.hpp" #include "EthernetTap.hpp" - -#include -#include +#include "Thread.hpp" #include +#include +#include #include #include namespace ZeroTier { -class MacEthernetTap : public EthernetTap -{ -public: - MacEthernetTap( - const char *homePath, - const MAC &mac, - unsigned int mtu, - unsigned int metric, - uint64_t nwid, - const char *friendlyName, - void (*handler)(void *,void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int), - void *arg); +class MacEthernetTap : public EthernetTap { + public: + MacEthernetTap( + const char* homePath, + const MAC& mac, + unsigned int mtu, + unsigned int metric, + uint64_t nwid, + const char* friendlyName, + void (*handler)(void*, void*, uint64_t, const MAC&, const MAC&, unsigned int, unsigned int, const void*, unsigned int), + void* arg); - virtual ~MacEthernetTap(); + virtual ~MacEthernetTap(); - virtual void setEnabled(bool en); - virtual bool enabled() const; - virtual bool addIp(const InetAddress &ip); - virtual bool removeIp(const InetAddress &ip); - virtual std::vector ips() const; - virtual void put(const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len); - virtual std::string deviceName() const; - virtual void setFriendlyName(const char *friendlyName); - virtual void scanMulticastGroups(std::vector &added,std::vector &removed); - virtual void setMtu(unsigned int mtu); - virtual void setDns(const char *domain, const std::vector &servers); + virtual void setEnabled(bool en); + virtual bool enabled() const; + virtual bool addIp(const InetAddress& ip); + virtual bool removeIp(const InetAddress& ip); + virtual std::vector ips() const; + virtual void put(const MAC& from, const MAC& to, unsigned int etherType, const void* data, unsigned int len); + virtual std::string deviceName() const; + virtual void setFriendlyName(const char* friendlyName); + virtual void scanMulticastGroups(std::vector& added, std::vector& removed); + virtual void setMtu(unsigned int mtu); + virtual void setDns(const char* domain, const std::vector& servers); - void threadMain() - throw(); - -private: - void (*_handler)(void *,void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int); - void *_arg; - uint64_t _nwid; - Thread _thread; - std::string _homePath; - std::string _dev; - std::vector _multicastGroups; - Mutex _putLock; - unsigned int _mtu; - unsigned int _metric; - unsigned int _devNo; - int _shutdownSignalPipe[2]; - int _agentStdin,_agentStdout,_agentStderr,_agentStdin2,_agentStdout2,_agentStderr2; - long _agentPid; - volatile bool _enabled; - mutable std::vector _ifaddrs; - mutable uint64_t _lastIfAddrsUpdate; + void threadMain() throw(); + private: + void (*_handler)(void*, void*, uint64_t, const MAC&, const MAC&, unsigned int, unsigned int, const void*, unsigned int); + void* _arg; + uint64_t _nwid; + Thread _thread; + std::string _homePath; + std::string _dev; + std::vector _multicastGroups; + Mutex _putLock; + unsigned int _mtu; + unsigned int _metric; + unsigned int _devNo; + int _shutdownSignalPipe[2]; + int _agentStdin, _agentStdout, _agentStderr, _agentStdin2, _agentStdout2, _agentStderr2; + long _agentPid; + volatile bool _enabled; + mutable std::vector _ifaddrs; + mutable uint64_t _lastIfAddrsUpdate; }; -} // namespace ZeroTier +} // namespace ZeroTier #endif diff --git a/osdep/MacKextEthernetTap.cpp b/osdep/MacKextEthernetTap.cpp index e0656030..8c643885 100644 --- a/osdep/MacKextEthernetTap.cpp +++ b/osdep/MacKextEthernetTap.cpp @@ -11,56 +11,53 @@ */ /****/ -#include -#include -#include -#include -#include +#include "MacDNSHelper.hpp" -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include -#include +#include +#include #include #include #include #include -#include -#include -#include +#include #include - -#include "MacDNSHelper.hpp" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include // OSX compile fix... in6_var defines this in a struct which namespaces it for C++ ... why?!? struct prf_ra { - u_char onlink : 1; - u_char autonomous : 1; - u_char reserved : 6; + u_char onlink : 1; + u_char autonomous : 1; + u_char reserved : 6; } prf_ra; -#include #include +#include // These are KERNEL_PRIVATE... why? #ifndef SIOCAUTOCONF_START -#define SIOCAUTOCONF_START _IOWR('i', 132, struct in6_ifreq) /* accept rtadvd on this interface */ +#define SIOCAUTOCONF_START _IOWR('i', 132, struct in6_ifreq) /* accept rtadvd on this interface */ #endif #ifndef SIOCAUTOCONF_STOP -#define SIOCAUTOCONF_STOP _IOWR('i', 133, struct in6_ifreq) /* stop accepting rtadv for this interface */ +#define SIOCAUTOCONF_STOP _IOWR('i', 133, struct in6_ifreq) /* stop accepting rtadv for this interface */ #endif // -------------------------------------------------------------------------- @@ -69,234 +66,230 @@ struct prf_ra { // http://www.opensource.apple.com/source/Libinfo/Libinfo-406.17/gen.subproj/getifmaddrs.c?txt // It's here because OSX 10.6 does not have this convenience function. -#define SALIGN (sizeof(uint32_t) - 1) -#define SA_RLEN(sa) ((sa)->sa_len ? (((sa)->sa_len + SALIGN) & ~SALIGN) : \ -(SALIGN + 1)) -#define MAX_SYSCTL_TRY 5 -#define RTA_MASKS (RTA_GATEWAY | RTA_IFP | RTA_IFA) +#define SALIGN (sizeof(uint32_t) - 1) +#define SA_RLEN(sa) ((sa)->sa_len ? (((sa)->sa_len + SALIGN) & ~SALIGN) : (SALIGN + 1)) +#define MAX_SYSCTL_TRY 5 +#define RTA_MASKS (RTA_GATEWAY | RTA_IFP | RTA_IFA) /* FreeBSD uses NET_RT_IFMALIST and RTM_NEWMADDR from */ /* We can use NET_RT_IFLIST2 and RTM_NEWMADDR2 on Darwin */ -//#define DARWIN_COMPAT +// #define DARWIN_COMPAT -//#ifdef DARWIN_COMPAT +// #ifdef DARWIN_COMPAT #define GIM_SYSCTL_MIB NET_RT_IFLIST2 -#define GIM_RTM_ADDR RTM_NEWMADDR2 -//#else -//#define GIM_SYSCTL_MIB NET_RT_IFMALIST -//#define GIM_RTM_ADDR RTM_NEWMADDR -//#endif +#define GIM_RTM_ADDR RTM_NEWMADDR2 +// #else +// #define GIM_SYSCTL_MIB NET_RT_IFMALIST +// #define GIM_RTM_ADDR RTM_NEWMADDR +// #endif // Not in 10.6 includes so use our own struct _intl_ifmaddrs { - struct _intl_ifmaddrs *ifma_next; - struct sockaddr *ifma_name; - struct sockaddr *ifma_addr; - struct sockaddr *ifma_lladdr; + struct _intl_ifmaddrs* ifma_next; + struct sockaddr* ifma_name; + struct sockaddr* ifma_addr; + struct sockaddr* ifma_lladdr; }; -static inline int _intl_getifmaddrs(struct _intl_ifmaddrs **pif) +static inline int _intl_getifmaddrs(struct _intl_ifmaddrs** pif) { - int icnt = 1; - int dcnt = 0; - int ntry = 0; - size_t len; - size_t needed; - int mib[6]; - int i; - char *buf; - char *data; - char *next; - char *p; - struct ifma_msghdr2 *ifmam; - struct _intl_ifmaddrs *ifa, *ift; - struct rt_msghdr *rtm; - struct sockaddr *sa; + int icnt = 1; + int dcnt = 0; + int ntry = 0; + size_t len; + size_t needed; + int mib[6]; + int i; + char* buf; + char* data; + char* next; + char* p; + struct ifma_msghdr2* ifmam; + struct _intl_ifmaddrs *ifa, *ift; + struct rt_msghdr* rtm; + struct sockaddr* sa; - mib[0] = CTL_NET; - mib[1] = PF_ROUTE; - mib[2] = 0; /* protocol */ - mib[3] = 0; /* wildcard address family */ - mib[4] = GIM_SYSCTL_MIB; - mib[5] = 0; /* no flags */ - do { - if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) - return (-1); - if ((buf = (char *)malloc(needed)) == NULL) - return (-1); - if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) { - if (errno != ENOMEM || ++ntry >= MAX_SYSCTL_TRY) { - free(buf); - return (-1); - } - free(buf); - buf = NULL; - } - } while (buf == NULL); + mib[0] = CTL_NET; + mib[1] = PF_ROUTE; + mib[2] = 0; /* protocol */ + mib[3] = 0; /* wildcard address family */ + mib[4] = GIM_SYSCTL_MIB; + mib[5] = 0; /* no flags */ + do { + if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) + return (-1); + if ((buf = (char*)malloc(needed)) == NULL) + return (-1); + if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) { + if (errno != ENOMEM || ++ntry >= MAX_SYSCTL_TRY) { + free(buf); + return (-1); + } + free(buf); + buf = NULL; + } + } while (buf == NULL); - for (next = buf; next < buf + needed; next += rtm->rtm_msglen) { - rtm = (struct rt_msghdr *)(void *)next; - if (rtm->rtm_version != RTM_VERSION) - continue; - switch (rtm->rtm_type) { - case GIM_RTM_ADDR: - ifmam = (struct ifma_msghdr2 *)(void *)rtm; - if ((ifmam->ifmam_addrs & RTA_IFA) == 0) - break; - icnt++; - p = (char *)(ifmam + 1); - for (i = 0; i < RTAX_MAX; i++) { - if ((RTA_MASKS & ifmam->ifmam_addrs & - (1 << i)) == 0) - continue; - sa = (struct sockaddr *)(void *)p; - len = SA_RLEN(sa); - dcnt += len; - p += len; - } - break; - } - } + for (next = buf; next < buf + needed; next += rtm->rtm_msglen) { + rtm = (struct rt_msghdr*)(void*)next; + if (rtm->rtm_version != RTM_VERSION) + continue; + switch (rtm->rtm_type) { + case GIM_RTM_ADDR: + ifmam = (struct ifma_msghdr2*)(void*)rtm; + if ((ifmam->ifmam_addrs & RTA_IFA) == 0) + break; + icnt++; + p = (char*)(ifmam + 1); + for (i = 0; i < RTAX_MAX; i++) { + if ((RTA_MASKS & ifmam->ifmam_addrs & (1 << i)) == 0) + continue; + sa = (struct sockaddr*)(void*)p; + len = SA_RLEN(sa); + dcnt += len; + p += len; + } + break; + } + } - data = (char *)malloc(sizeof(struct _intl_ifmaddrs) * icnt + dcnt); - if (data == NULL) { - free(buf); - return (-1); - } + data = (char*)malloc(sizeof(struct _intl_ifmaddrs) * icnt + dcnt); + if (data == NULL) { + free(buf); + return (-1); + } - ifa = (struct _intl_ifmaddrs *)(void *)data; - data += sizeof(struct _intl_ifmaddrs) * icnt; + ifa = (struct _intl_ifmaddrs*)(void*)data; + data += sizeof(struct _intl_ifmaddrs) * icnt; - memset(ifa, 0, sizeof(struct _intl_ifmaddrs) * icnt); - ift = ifa; + memset(ifa, 0, sizeof(struct _intl_ifmaddrs) * icnt); + ift = ifa; - for (next = buf; next < buf + needed; next += rtm->rtm_msglen) { - rtm = (struct rt_msghdr *)(void *)next; - if (rtm->rtm_version != RTM_VERSION) - continue; + for (next = buf; next < buf + needed; next += rtm->rtm_msglen) { + rtm = (struct rt_msghdr*)(void*)next; + if (rtm->rtm_version != RTM_VERSION) + continue; - switch (rtm->rtm_type) { - case GIM_RTM_ADDR: - ifmam = (struct ifma_msghdr2 *)(void *)rtm; - if ((ifmam->ifmam_addrs & RTA_IFA) == 0) - break; + switch (rtm->rtm_type) { + case GIM_RTM_ADDR: + ifmam = (struct ifma_msghdr2*)(void*)rtm; + if ((ifmam->ifmam_addrs & RTA_IFA) == 0) + break; - p = (char *)(ifmam + 1); - for (i = 0; i < RTAX_MAX; i++) { - if ((RTA_MASKS & ifmam->ifmam_addrs & - (1 << i)) == 0) - continue; - sa = (struct sockaddr *)(void *)p; - len = SA_RLEN(sa); - switch (i) { - case RTAX_GATEWAY: - ift->ifma_lladdr = - (struct sockaddr *)(void *)data; - memcpy(data, p, len); - data += len; - break; + p = (char*)(ifmam + 1); + for (i = 0; i < RTAX_MAX; i++) { + if ((RTA_MASKS & ifmam->ifmam_addrs & (1 << i)) == 0) + continue; + sa = (struct sockaddr*)(void*)p; + len = SA_RLEN(sa); + switch (i) { + case RTAX_GATEWAY: + ift->ifma_lladdr = (struct sockaddr*)(void*)data; + memcpy(data, p, len); + data += len; + break; - case RTAX_IFP: - ift->ifma_name = - (struct sockaddr *)(void *)data; - memcpy(data, p, len); - data += len; - break; + case RTAX_IFP: + ift->ifma_name = (struct sockaddr*)(void*)data; + memcpy(data, p, len); + data += len; + break; - case RTAX_IFA: - ift->ifma_addr = - (struct sockaddr *)(void *)data; - memcpy(data, p, len); - data += len; - break; + case RTAX_IFA: + ift->ifma_addr = (struct sockaddr*)(void*)data; + memcpy(data, p, len); + data += len; + break; - default: - data += len; - break; - } - p += len; - } - ift->ifma_next = ift + 1; - ift = ift->ifma_next; - break; - } - } + default: + data += len; + break; + } + p += len; + } + ift->ifma_next = ift + 1; + ift = ift->ifma_next; + break; + } + } - free(buf); + free(buf); - if (ift > ifa) { - ift--; - ift->ifma_next = NULL; - *pif = ifa; - } else { - *pif = NULL; - free(ifa); - } - return (0); + if (ift > ifa) { + ift--; + ift->ifma_next = NULL; + *pif = ifa; + } + else { + *pif = NULL; + free(ifa); + } + return (0); } -static inline void _intl_freeifmaddrs(struct _intl_ifmaddrs *ifmp) +static inline void _intl_freeifmaddrs(struct _intl_ifmaddrs* ifmp) { - free(ifmp); + free(ifmp); } // -------------------------------------------------------------------------- // -------------------------------------------------------------------------- -#include -#include -#include -#include - #include "../node/Constants.hpp" -#include "../node/Utils.hpp" -#include "../node/Mutex.hpp" #include "../node/Dictionary.hpp" -#include "OSUtils.hpp" +#include "../node/Mutex.hpp" +#include "../node/Utils.hpp" #include "MacKextEthernetTap.hpp" +#include "OSUtils.hpp" + +#include +#include +#include +#include // ff:ff:ff:ff:ff:ff with no ADI -static const ZeroTier::MulticastGroup _blindWildcardMulticastGroup(ZeroTier::MAC(0xff),0); +static const ZeroTier::MulticastGroup _blindWildcardMulticastGroup(ZeroTier::MAC(0xff), 0); -static inline bool _setIpv6Stuff(const char *ifname,bool performNUD,bool acceptRouterAdverts) +static inline bool _setIpv6Stuff(const char* ifname, bool performNUD, bool acceptRouterAdverts) { - struct in6_ndireq nd; - struct in6_ifreq ifr; + struct in6_ndireq nd; + struct in6_ifreq ifr; - int s = socket(AF_INET6,SOCK_DGRAM,0); - if (s <= 0) - return false; + int s = socket(AF_INET6, SOCK_DGRAM, 0); + if (s <= 0) + return false; - memset(&nd,0,sizeof(nd)); - strncpy(nd.ifname,ifname,sizeof(nd.ifname)); + memset(&nd, 0, sizeof(nd)); + strncpy(nd.ifname, ifname, sizeof(nd.ifname)); - if (ioctl(s,SIOCGIFINFO_IN6,&nd)) { - close(s); - return false; - } + if (ioctl(s, SIOCGIFINFO_IN6, &nd)) { + close(s); + return false; + } - unsigned long oldFlags = (unsigned long)nd.ndi.flags; + unsigned long oldFlags = (unsigned long)nd.ndi.flags; - if (performNUD) - nd.ndi.flags |= ND6_IFF_PERFORMNUD; - else nd.ndi.flags &= ~ND6_IFF_PERFORMNUD; + if (performNUD) + nd.ndi.flags |= ND6_IFF_PERFORMNUD; + else + nd.ndi.flags &= ~ND6_IFF_PERFORMNUD; - if (oldFlags != (unsigned long)nd.ndi.flags) { - if (ioctl(s,SIOCSIFINFO_FLAGS,&nd)) { - close(s); - return false; - } - } + if (oldFlags != (unsigned long)nd.ndi.flags) { + if (ioctl(s, SIOCSIFINFO_FLAGS, &nd)) { + close(s); + return false; + } + } - memset(&ifr,0,sizeof(ifr)); - strncpy(ifr.ifr_name,ifname,sizeof(ifr.ifr_name)); - if (ioctl(s,acceptRouterAdverts ? SIOCAUTOCONF_START : SIOCAUTOCONF_STOP,&ifr)) { - close(s); - return false; - } + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); + if (ioctl(s, acceptRouterAdverts ? SIOCAUTOCONF_START : SIOCAUTOCONF_STOP, &ifr)) { + close(s); + return false; + } - close(s); - return true; + close(s); + return true; } namespace ZeroTier { @@ -305,397 +298,407 @@ static long globalTapsRunning = 0; static Mutex globalTapCreateLock; MacKextEthernetTap::MacKextEthernetTap( - const char *homePath, - const MAC &mac, - unsigned int mtu, - unsigned int metric, - uint64_t nwid, - const char *friendlyName, - void (*handler)(void *,void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *data,unsigned int len), - void *arg) : - _handler(handler), - _arg(arg), - _nwid(nwid), - _homePath(homePath), - _mtu(mtu), - _metric(metric), - _fd(0), - _enabled(true) + const char* homePath, + const MAC& mac, + unsigned int mtu, + unsigned int metric, + uint64_t nwid, + const char* friendlyName, + void (*handler)(void*, void*, uint64_t, const MAC&, const MAC&, unsigned int, unsigned int, const void* data, unsigned int len), + void* arg) + : _handler(handler) + , _arg(arg) + , _nwid(nwid) + , _homePath(homePath) + , _mtu(mtu) + , _metric(metric) + , _fd(0) + , _enabled(true) { - char devpath[64],ethaddr[64],mtustr[32],metstr[32],nwids[32]; - struct stat stattmp; + char devpath[64], ethaddr[64], mtustr[32], metstr[32], nwids[32]; + struct stat stattmp; - OSUtils::ztsnprintf(nwids,sizeof(nwids),"%.16llx",nwid); + OSUtils::ztsnprintf(nwids, sizeof(nwids), "%.16llx", nwid); - Mutex::Lock _gl(globalTapCreateLock); + Mutex::Lock _gl(globalTapCreateLock); - if (::stat("/dev/zt0",&stattmp)) { - long kextpid = (long)fork(); - if (kextpid == 0) { - ::chdir(homePath); - OSUtils::redirectUnixOutputs("/dev/null",(const char *)0); - ::execl("/sbin/kextload","/sbin/kextload","-q","-repository",homePath,"tap.kext",(const char *)0); - ::_exit(-1); - } else if (kextpid > 0) { - int exitcode = -1; - ::waitpid(kextpid,&exitcode,0); - } - ::usleep(500); // give tap device driver time to start up and try again - if (::stat("/dev/zt0",&stattmp)) - throw std::runtime_error("/dev/zt# tap devices do not exist and cannot load tap.kext"); - } + if (::stat("/dev/zt0", &stattmp)) { + long kextpid = (long)fork(); + if (kextpid == 0) { + ::chdir(homePath); + OSUtils::redirectUnixOutputs("/dev/null", (const char*)0); + ::execl("/sbin/kextload", "/sbin/kextload", "-q", "-repository", homePath, "tap.kext", (const char*)0); + ::_exit(-1); + } + else if (kextpid > 0) { + int exitcode = -1; + ::waitpid(kextpid, &exitcode, 0); + } + ::usleep(500); // give tap device driver time to start up and try again + if (::stat("/dev/zt0", &stattmp)) + throw std::runtime_error("/dev/zt# tap devices do not exist and cannot load tap.kext"); + } - // Try to reopen the last device we had, if we had one and it's still unused. - std::map globalDeviceMap; - FILE *devmapf = fopen((_homePath + ZT_PATH_SEPARATOR_S + "devicemap").c_str(),"r"); - if (devmapf) { - char buf[256]; - while (fgets(buf,sizeof(buf),devmapf)) { - char *x = (char *)0; - char *y = (char *)0; - char *saveptr = (char *)0; - for(char *f=Utils::stok(buf,"\r\n=",&saveptr);(f);f=Utils::stok((char *)0,"\r\n=",&saveptr)) { - if (!x) x = f; - else if (!y) y = f; - else break; - } - if ((x)&&(y)&&(x[0])&&(y[0])) - globalDeviceMap[x] = y; - } - fclose(devmapf); - } - bool recalledDevice = false; - std::map::const_iterator gdmEntry = globalDeviceMap.find(nwids); - if (gdmEntry != globalDeviceMap.end()) { - std::string devpath("/dev/"); devpath.append(gdmEntry->second); - if (stat(devpath.c_str(),&stattmp) == 0) { - _fd = ::open(devpath.c_str(),O_RDWR); - if (_fd > 0) { - _dev = gdmEntry->second; - recalledDevice = true; - } - } - } + // Try to reopen the last device we had, if we had one and it's still unused. + std::map globalDeviceMap; + FILE* devmapf = fopen((_homePath + ZT_PATH_SEPARATOR_S + "devicemap").c_str(), "r"); + if (devmapf) { + char buf[256]; + while (fgets(buf, sizeof(buf), devmapf)) { + char* x = (char*)0; + char* y = (char*)0; + char* saveptr = (char*)0; + for (char* f = Utils::stok(buf, "\r\n=", &saveptr); (f); f = Utils::stok((char*)0, "\r\n=", &saveptr)) { + if (! x) + x = f; + else if (! y) + y = f; + else + break; + } + if ((x) && (y) && (x[0]) && (y[0])) + globalDeviceMap[x] = y; + } + fclose(devmapf); + } + bool recalledDevice = false; + std::map::const_iterator gdmEntry = globalDeviceMap.find(nwids); + if (gdmEntry != globalDeviceMap.end()) { + std::string devpath("/dev/"); + devpath.append(gdmEntry->second); + if (stat(devpath.c_str(), &stattmp) == 0) { + _fd = ::open(devpath.c_str(), O_RDWR); + if (_fd > 0) { + _dev = gdmEntry->second; + recalledDevice = true; + } + } + } - // Open the first unused tap device if we didn't recall a previous one. - if (!recalledDevice) { - for(int i=0;i<64;++i) { - OSUtils::ztsnprintf(devpath,sizeof(devpath),"/dev/zt%d",i); - if (stat(devpath,&stattmp)) - throw std::runtime_error("no more TAP devices available"); - _fd = ::open(devpath,O_RDWR); - if (_fd > 0) { - char foo[16]; - OSUtils::ztsnprintf(foo,sizeof(foo),"zt%d",i); - _dev = foo; - break; - } - } - } + // Open the first unused tap device if we didn't recall a previous one. + if (! recalledDevice) { + for (int i = 0; i < 64; ++i) { + OSUtils::ztsnprintf(devpath, sizeof(devpath), "/dev/zt%d", i); + if (stat(devpath, &stattmp)) + throw std::runtime_error("no more TAP devices available"); + _fd = ::open(devpath, O_RDWR); + if (_fd > 0) { + char foo[16]; + OSUtils::ztsnprintf(foo, sizeof(foo), "zt%d", i); + _dev = foo; + break; + } + } + } - if (_fd <= 0) - throw std::runtime_error("unable to open TAP device or no more devices available"); + if (_fd <= 0) + throw std::runtime_error("unable to open TAP device or no more devices available"); - if (fcntl(_fd,F_SETFL,fcntl(_fd,F_GETFL) & ~O_NONBLOCK) == -1) { - ::close(_fd); - throw std::runtime_error("unable to set flags on file descriptor for TAP device"); - } + if (fcntl(_fd, F_SETFL, fcntl(_fd, F_GETFL) & ~O_NONBLOCK) == -1) { + ::close(_fd); + throw std::runtime_error("unable to set flags on file descriptor for TAP device"); + } - // Configure MAC address and MTU, bring interface up - OSUtils::ztsnprintf(ethaddr,sizeof(ethaddr),"%.2x:%.2x:%.2x:%.2x:%.2x:%.2x",(int)mac[0],(int)mac[1],(int)mac[2],(int)mac[3],(int)mac[4],(int)mac[5]); - OSUtils::ztsnprintf(mtustr,sizeof(mtustr),"%u",_mtu); - OSUtils::ztsnprintf(metstr,sizeof(metstr),"%u",_metric); - long cpid = (long)fork(); - if (cpid == 0) { - ::execl("/sbin/ifconfig","/sbin/ifconfig",_dev.c_str(),"lladdr",ethaddr,"mtu",mtustr,"metric",metstr,"up",(const char *)0); - ::_exit(-1); - } else if (cpid > 0) { - int exitcode = -1; - ::waitpid(cpid,&exitcode,0); - if (exitcode) { - ::close(_fd); - throw std::runtime_error("ifconfig failure setting link-layer address and activating tap interface"); - } - } + // Configure MAC address and MTU, bring interface up + OSUtils::ztsnprintf(ethaddr, sizeof(ethaddr), "%.2x:%.2x:%.2x:%.2x:%.2x:%.2x", (int)mac[0], (int)mac[1], (int)mac[2], (int)mac[3], (int)mac[4], (int)mac[5]); + OSUtils::ztsnprintf(mtustr, sizeof(mtustr), "%u", _mtu); + OSUtils::ztsnprintf(metstr, sizeof(metstr), "%u", _metric); + long cpid = (long)fork(); + if (cpid == 0) { + ::execl("/sbin/ifconfig", "/sbin/ifconfig", _dev.c_str(), "lladdr", ethaddr, "mtu", mtustr, "metric", metstr, "up", (const char*)0); + ::_exit(-1); + } + else if (cpid > 0) { + int exitcode = -1; + ::waitpid(cpid, &exitcode, 0); + if (exitcode) { + ::close(_fd); + throw std::runtime_error("ifconfig failure setting link-layer address and activating tap interface"); + } + } - _setIpv6Stuff(_dev.c_str(),true,false); + _setIpv6Stuff(_dev.c_str(), true, false); - // Set close-on-exec so that devices cannot persist if we fork/exec for update - fcntl(_fd,F_SETFD,fcntl(_fd,F_GETFD) | FD_CLOEXEC); + // Set close-on-exec so that devices cannot persist if we fork/exec for update + fcntl(_fd, F_SETFD, fcntl(_fd, F_GETFD) | FD_CLOEXEC); - ::pipe(_shutdownSignalPipe); + ::pipe(_shutdownSignalPipe); - ++globalTapsRunning; + ++globalTapsRunning; - globalDeviceMap[nwids] = _dev; - devmapf = fopen((_homePath + ZT_PATH_SEPARATOR_S + "devicemap").c_str(),"w"); - if (devmapf) { - gdmEntry = globalDeviceMap.begin(); - while (gdmEntry != globalDeviceMap.end()) { - fprintf(devmapf,"%s=%s\n",gdmEntry->first.c_str(),gdmEntry->second.c_str()); - ++gdmEntry; - } - fclose(devmapf); - } + globalDeviceMap[nwids] = _dev; + devmapf = fopen((_homePath + ZT_PATH_SEPARATOR_S + "devicemap").c_str(), "w"); + if (devmapf) { + gdmEntry = globalDeviceMap.begin(); + while (gdmEntry != globalDeviceMap.end()) { + fprintf(devmapf, "%s=%s\n", gdmEntry->first.c_str(), gdmEntry->second.c_str()); + ++gdmEntry; + } + fclose(devmapf); + } - _thread = Thread::start(this); + _thread = Thread::start(this); } MacKextEthernetTap::~MacKextEthernetTap() { - MacDNSHelper::removeDNS(_nwid); + MacDNSHelper::removeDNS(_nwid); - ::write(_shutdownSignalPipe[1],"\0",1); // causes thread to exit - Thread::join(_thread); - for (std::thread &t : _rxThreads) { - t.join(); - } - ::close(_fd); - ::close(_shutdownSignalPipe[0]); - ::close(_shutdownSignalPipe[1]); + ::write(_shutdownSignalPipe[1], "\0", 1); // causes thread to exit + Thread::join(_thread); + for (std::thread& t : _rxThreads) { + t.join(); + } + ::close(_fd); + ::close(_shutdownSignalPipe[0]); + ::close(_shutdownSignalPipe[1]); - { - Mutex::Lock _gl(globalTapCreateLock); - if (--globalTapsRunning <= 0) { - globalTapsRunning = 0; // sanity check -- should not be possible + { + Mutex::Lock _gl(globalTapCreateLock); + if (--globalTapsRunning <= 0) { + globalTapsRunning = 0; // sanity check -- should not be possible - char tmp[16384]; - sprintf(tmp,"%s/%s",_homePath.c_str(),"tap.kext"); - long kextpid = (long)fork(); - if (kextpid == 0) { - OSUtils::redirectUnixOutputs("/dev/null",(const char *)0); - ::execl("/sbin/kextunload","/sbin/kextunload",tmp,(const char *)0); - ::_exit(-1); - } else if (kextpid > 0) { - int exitcode = -1; - ::waitpid(kextpid,&exitcode,0); - } - } - } + char tmp[16384]; + sprintf(tmp, "%s/%s", _homePath.c_str(), "tap.kext"); + long kextpid = (long)fork(); + if (kextpid == 0) { + OSUtils::redirectUnixOutputs("/dev/null", (const char*)0); + ::execl("/sbin/kextunload", "/sbin/kextunload", tmp, (const char*)0); + ::_exit(-1); + } + else if (kextpid > 0) { + int exitcode = -1; + ::waitpid(kextpid, &exitcode, 0); + } + } + } } void MacKextEthernetTap::setEnabled(bool en) { - _enabled = en; - // TODO: interface status change + _enabled = en; + // TODO: interface status change } bool MacKextEthernetTap::enabled() const { - return _enabled; + return _enabled; } -bool MacKextEthernetTap::addIp(const InetAddress &ip) +bool MacKextEthernetTap::addIp(const InetAddress& ip) { - if (!ip) - return false; + if (! ip) + return false; - long cpid = (long)fork(); - if (cpid == 0) { - char tmp[128]; - ::execl("/sbin/ifconfig","/sbin/ifconfig",_dev.c_str(),(ip.ss_family == AF_INET6) ? "inet6" : "inet",ip.toString(tmp),"alias",(const char *)0); - ::_exit(-1); - } else if (cpid > 0) { - int exitcode = -1; - ::waitpid(cpid,&exitcode,0); - return (exitcode == 0); - } // else return false... + long cpid = (long)fork(); + if (cpid == 0) { + char tmp[128]; + ::execl("/sbin/ifconfig", "/sbin/ifconfig", _dev.c_str(), (ip.ss_family == AF_INET6) ? "inet6" : "inet", ip.toString(tmp), "alias", (const char*)0); + ::_exit(-1); + } + else if (cpid > 0) { + int exitcode = -1; + ::waitpid(cpid, &exitcode, 0); + return (exitcode == 0); + } // else return false... - return false; + return false; } -bool MacKextEthernetTap::removeIp(const InetAddress &ip) +bool MacKextEthernetTap::removeIp(const InetAddress& ip) { - if (!ip) - return true; - std::vector allIps(ips()); - for(std::vector::iterator i(allIps.begin());i!=allIps.end();++i) { - if (*i == ip) { - long cpid = (long)fork(); - if (cpid == 0) { - char tmp[128]; - execl("/sbin/ifconfig","/sbin/ifconfig",_dev.c_str(),(ip.ss_family == AF_INET6) ? "inet6" : "inet",ip.toIpString(tmp),"-alias",(const char *)0); - _exit(-1); - } else if (cpid > 0) { - int exitcode = -1; - waitpid(cpid,&exitcode,0); - return (exitcode == 0); - } - } - } - return false; + if (! ip) + return true; + std::vector allIps(ips()); + for (std::vector::iterator i(allIps.begin()); i != allIps.end(); ++i) { + if (*i == ip) { + long cpid = (long)fork(); + if (cpid == 0) { + char tmp[128]; + execl("/sbin/ifconfig", "/sbin/ifconfig", _dev.c_str(), (ip.ss_family == AF_INET6) ? "inet6" : "inet", ip.toIpString(tmp), "-alias", (const char*)0); + _exit(-1); + } + else if (cpid > 0) { + int exitcode = -1; + waitpid(cpid, &exitcode, 0); + return (exitcode == 0); + } + } + } + return false; } std::vector MacKextEthernetTap::ips() const { - struct ifaddrs *ifa = (struct ifaddrs *)0; - if (getifaddrs(&ifa)) - return std::vector(); + struct ifaddrs* ifa = (struct ifaddrs*)0; + if (getifaddrs(&ifa)) + return std::vector(); - std::vector r; + std::vector r; - struct ifaddrs *p = ifa; - while (p) { - if ((!strcmp(p->ifa_name,_dev.c_str()))&&(p->ifa_addr)&&(p->ifa_netmask)&&(p->ifa_addr->sa_family == p->ifa_netmask->sa_family)) { - switch(p->ifa_addr->sa_family) { - case AF_INET: { - struct sockaddr_in *sin = (struct sockaddr_in *)p->ifa_addr; - struct sockaddr_in *nm = (struct sockaddr_in *)p->ifa_netmask; - r.push_back(InetAddress(&(sin->sin_addr.s_addr),4,Utils::countBits((uint32_t)nm->sin_addr.s_addr))); - } break; - case AF_INET6: { - struct sockaddr_in6 *sin = (struct sockaddr_in6 *)p->ifa_addr; - struct sockaddr_in6 *nm = (struct sockaddr_in6 *)p->ifa_netmask; - uint32_t b[4]; - memcpy(b,nm->sin6_addr.s6_addr,sizeof(b)); - r.push_back(InetAddress(sin->sin6_addr.s6_addr,16,Utils::countBits(b[0]) + Utils::countBits(b[1]) + Utils::countBits(b[2]) + Utils::countBits(b[3]))); - } break; - } - } - p = p->ifa_next; - } + struct ifaddrs* p = ifa; + while (p) { + if ((! strcmp(p->ifa_name, _dev.c_str())) && (p->ifa_addr) && (p->ifa_netmask) && (p->ifa_addr->sa_family == p->ifa_netmask->sa_family)) { + switch (p->ifa_addr->sa_family) { + case AF_INET: { + struct sockaddr_in* sin = (struct sockaddr_in*)p->ifa_addr; + struct sockaddr_in* nm = (struct sockaddr_in*)p->ifa_netmask; + r.push_back(InetAddress(&(sin->sin_addr.s_addr), 4, Utils::countBits((uint32_t)nm->sin_addr.s_addr))); + } break; + case AF_INET6: { + struct sockaddr_in6* sin = (struct sockaddr_in6*)p->ifa_addr; + struct sockaddr_in6* nm = (struct sockaddr_in6*)p->ifa_netmask; + uint32_t b[4]; + memcpy(b, nm->sin6_addr.s6_addr, sizeof(b)); + r.push_back(InetAddress(sin->sin6_addr.s6_addr, 16, Utils::countBits(b[0]) + Utils::countBits(b[1]) + Utils::countBits(b[2]) + Utils::countBits(b[3]))); + } break; + } + } + p = p->ifa_next; + } - if (ifa) - freeifaddrs(ifa); + if (ifa) + freeifaddrs(ifa); - std::sort(r.begin(),r.end()); - r.erase(std::unique(r.begin(),r.end()),r.end()); + std::sort(r.begin(), r.end()); + r.erase(std::unique(r.begin(), r.end()), r.end()); - return r; + return r; } -void MacKextEthernetTap::put(const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len) +void MacKextEthernetTap::put(const MAC& from, const MAC& to, unsigned int etherType, const void* data, unsigned int len) { - char putBuf[ZT_MAX_MTU + 64]; - if ((_fd > 0)&&(len <= _mtu)&&(_enabled)) { - to.copyTo(putBuf,6); - from.copyTo(putBuf + 6,6); - *((uint16_t *)(putBuf + 12)) = htons((uint16_t)etherType); - memcpy(putBuf + 14,data,len); - len += 14; - ::write(_fd,putBuf,len); - } + char putBuf[ZT_MAX_MTU + 64]; + if ((_fd > 0) && (len <= _mtu) && (_enabled)) { + to.copyTo(putBuf, 6); + from.copyTo(putBuf + 6, 6); + *((uint16_t*)(putBuf + 12)) = htons((uint16_t)etherType); + memcpy(putBuf + 14, data, len); + len += 14; + ::write(_fd, putBuf, len); + } } std::string MacKextEthernetTap::deviceName() const { - return _dev; + return _dev; } -void MacKextEthernetTap::setFriendlyName(const char *friendlyName) +void MacKextEthernetTap::setFriendlyName(const char* friendlyName) { } -void MacKextEthernetTap::scanMulticastGroups(std::vector &added,std::vector &removed) +void MacKextEthernetTap::scanMulticastGroups(std::vector& added, std::vector& removed) { - std::vector newGroups; + std::vector newGroups; - struct _intl_ifmaddrs *ifmap = (struct _intl_ifmaddrs *)0; - if (!_intl_getifmaddrs(&ifmap)) { - struct _intl_ifmaddrs *p = ifmap; - while (p) { - if (p->ifma_addr->sa_family == AF_LINK) { - struct sockaddr_dl *in = (struct sockaddr_dl *)p->ifma_name; - struct sockaddr_dl *la = (struct sockaddr_dl *)p->ifma_addr; - if ((la->sdl_alen == 6)&&(in->sdl_nlen <= _dev.length())&&(!memcmp(_dev.data(),in->sdl_data,in->sdl_nlen))) - newGroups.push_back(MulticastGroup(MAC(la->sdl_data + la->sdl_nlen,6),0)); - } - p = p->ifma_next; - } - _intl_freeifmaddrs(ifmap); - } + struct _intl_ifmaddrs* ifmap = (struct _intl_ifmaddrs*)0; + if (! _intl_getifmaddrs(&ifmap)) { + struct _intl_ifmaddrs* p = ifmap; + while (p) { + if (p->ifma_addr->sa_family == AF_LINK) { + struct sockaddr_dl* in = (struct sockaddr_dl*)p->ifma_name; + struct sockaddr_dl* la = (struct sockaddr_dl*)p->ifma_addr; + if ((la->sdl_alen == 6) && (in->sdl_nlen <= _dev.length()) && (! memcmp(_dev.data(), in->sdl_data, in->sdl_nlen))) + newGroups.push_back(MulticastGroup(MAC(la->sdl_data + la->sdl_nlen, 6), 0)); + } + p = p->ifma_next; + } + _intl_freeifmaddrs(ifmap); + } - std::vector allIps(ips()); - for(std::vector::iterator ip(allIps.begin());ip!=allIps.end();++ip) - newGroups.push_back(MulticastGroup::deriveMulticastGroupForAddressResolution(*ip)); + std::vector allIps(ips()); + for (std::vector::iterator ip(allIps.begin()); ip != allIps.end(); ++ip) + newGroups.push_back(MulticastGroup::deriveMulticastGroupForAddressResolution(*ip)); - std::sort(newGroups.begin(),newGroups.end()); - std::unique(newGroups.begin(),newGroups.end()); + std::sort(newGroups.begin(), newGroups.end()); + std::unique(newGroups.begin(), newGroups.end()); - for(std::vector::iterator m(newGroups.begin());m!=newGroups.end();++m) { - if (!std::binary_search(_multicastGroups.begin(),_multicastGroups.end(),*m)) - added.push_back(*m); - } - for(std::vector::iterator m(_multicastGroups.begin());m!=_multicastGroups.end();++m) { - if (!std::binary_search(newGroups.begin(),newGroups.end(),*m)) - removed.push_back(*m); - } + for (std::vector::iterator m(newGroups.begin()); m != newGroups.end(); ++m) { + if (! std::binary_search(_multicastGroups.begin(), _multicastGroups.end(), *m)) + added.push_back(*m); + } + for (std::vector::iterator m(_multicastGroups.begin()); m != _multicastGroups.end(); ++m) { + if (! std::binary_search(newGroups.begin(), newGroups.end(), *m)) + removed.push_back(*m); + } - _multicastGroups.swap(newGroups); + _multicastGroups.swap(newGroups); } void MacKextEthernetTap::setMtu(unsigned int mtu) { - if (mtu != _mtu) { - _mtu = mtu; - long cpid = (long)fork(); - if (cpid == 0) { - char tmp[64]; - OSUtils::ztsnprintf(tmp,sizeof(tmp),"%u",mtu); - execl("/sbin/ifconfig","/sbin/ifconfig",_dev.c_str(),"mtu",tmp,(const char *)0); - _exit(-1); - } else if (cpid > 0) { - int exitcode = -1; - waitpid(cpid,&exitcode,0); - } - } + if (mtu != _mtu) { + _mtu = mtu; + long cpid = (long)fork(); + if (cpid == 0) { + char tmp[64]; + OSUtils::ztsnprintf(tmp, sizeof(tmp), "%u", mtu); + execl("/sbin/ifconfig", "/sbin/ifconfig", _dev.c_str(), "mtu", tmp, (const char*)0); + _exit(-1); + } + else if (cpid > 0) { + int exitcode = -1; + waitpid(cpid, &exitcode, 0); + } + } } -void MacKextEthernetTap::threadMain() - throw() +void MacKextEthernetTap::threadMain() throw() { - fd_set readfds,nullfds; - MAC to,from; - int n,nfds,r; - char getBuf[ZT_MAX_MTU + 64]; + fd_set readfds, nullfds; + MAC to, from; + int n, nfds, r; + char getBuf[ZT_MAX_MTU + 64]; - Thread::sleep(500); + Thread::sleep(500); - FD_ZERO(&readfds); - FD_ZERO(&nullfds); - nfds = (int)std::max(_shutdownSignalPipe[0],_fd) + 1; + FD_ZERO(&readfds); + FD_ZERO(&nullfds); + nfds = (int)std::max(_shutdownSignalPipe[0], _fd) + 1; - r = 0; - for(;;) { - FD_SET(_shutdownSignalPipe[0],&readfds); - FD_SET(_fd,&readfds); - select(nfds,&readfds,&nullfds,&nullfds,(struct timeval *)0); + r = 0; + for (;;) { + FD_SET(_shutdownSignalPipe[0], &readfds); + FD_SET(_fd, &readfds); + select(nfds, &readfds, &nullfds, &nullfds, (struct timeval*)0); - if (FD_ISSET(_shutdownSignalPipe[0],&readfds)) // writes to shutdown pipe terminate thread - break; + if (FD_ISSET(_shutdownSignalPipe[0], &readfds)) // writes to shutdown pipe terminate thread + break; - if (FD_ISSET(_fd,&readfds)) { - n = (int)::read(_fd,getBuf + r,sizeof(getBuf) - r); - if (n < 0) { - if ((errno != EINTR)&&(errno != ETIMEDOUT)) - break; - } else { - // Some tap drivers like to send the ethernet frame and the - // payload in two chunks, so handle that by accumulating - // data until we have at least a frame. - r += n; - if (r > 14) { - if (r > ((int)_mtu + 14)) // sanity check for weird TAP behavior on some platforms - r = _mtu + 14; + if (FD_ISSET(_fd, &readfds)) { + n = (int)::read(_fd, getBuf + r, sizeof(getBuf) - r); + if (n < 0) { + if ((errno != EINTR) && (errno != ETIMEDOUT)) + break; + } + else { + // Some tap drivers like to send the ethernet frame and the + // payload in two chunks, so handle that by accumulating + // data until we have at least a frame. + r += n; + if (r > 14) { + if (r > ((int)_mtu + 14)) // sanity check for weird TAP behavior on some platforms + r = _mtu + 14; - if (_enabled) { - to.setTo(getBuf,6); - from.setTo(getBuf + 6,6); - unsigned int etherType = ntohs(((const uint16_t *)getBuf)[6]); - // TODO: VLAN support - _handler(_arg,(void *)0,_nwid,from,to,etherType,0,(const void *)(getBuf + 14),r - 14); - } + if (_enabled) { + to.setTo(getBuf, 6); + from.setTo(getBuf + 6, 6); + unsigned int etherType = ntohs(((const uint16_t*)getBuf)[6]); + // TODO: VLAN support + _handler(_arg, (void*)0, _nwid, from, to, etherType, 0, (const void*)(getBuf + 14), r - 14); + } - r = 0; - } - } - } - } + r = 0; + } + } + } + } } -void MacKextEthernetTap::setDns(const char *domain, const std::vector &servers) +void MacKextEthernetTap::setDns(const char* domain, const std::vector& servers) { - MacDNSHelper::setDNS(_nwid, domain, servers); + MacDNSHelper::setDNS(_nwid, domain, servers); } -} // namespace ZeroTier +} // namespace ZeroTier diff --git a/osdep/MacKextEthernetTap.hpp b/osdep/MacKextEthernetTap.hpp index aede9286..a96f6ef0 100644 --- a/osdep/MacKextEthernetTap.hpp +++ b/osdep/MacKextEthernetTap.hpp @@ -14,71 +14,66 @@ #ifndef ZT_MacKextEthernetTap_HPP #define ZT_MacKextEthernetTap_HPP -#include -#include +#include "../node/Constants.hpp" +#include "../node/InetAddress.hpp" +#include "../node/MAC.hpp" +#include "../node/MulticastGroup.hpp" +#include "EthernetTap.hpp" +#include "Thread.hpp" #include +#include +#include #include -#include #include - -#include "../node/Constants.hpp" -#include "../node/MAC.hpp" -#include "../node/InetAddress.hpp" -#include "../node/MulticastGroup.hpp" - -#include "Thread.hpp" -#include "EthernetTap.hpp" +#include namespace ZeroTier { -class MacKextEthernetTap : public EthernetTap -{ -public: - MacKextEthernetTap( - const char *homePath, - const MAC &mac, - unsigned int mtu, - unsigned int metric, - uint64_t nwid, - const char *friendlyName, - void (*handler)(void *,void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int), - void *arg); +class MacKextEthernetTap : public EthernetTap { + public: + MacKextEthernetTap( + const char* homePath, + const MAC& mac, + unsigned int mtu, + unsigned int metric, + uint64_t nwid, + const char* friendlyName, + void (*handler)(void*, void*, uint64_t, const MAC&, const MAC&, unsigned int, unsigned int, const void*, unsigned int), + void* arg); - virtual ~MacKextEthernetTap(); + virtual ~MacKextEthernetTap(); - virtual void setEnabled(bool en); - virtual bool enabled() const; - virtual bool addIp(const InetAddress &ip); - virtual bool removeIp(const InetAddress &ip); - virtual std::vector ips() const; - virtual void put(const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len); - virtual std::string deviceName() const; - virtual void setFriendlyName(const char *friendlyName); - virtual void scanMulticastGroups(std::vector &added,std::vector &removed); - virtual void setMtu(unsigned int mtu); - virtual void setDns(const char *domain, const std::vector &servers); + virtual void setEnabled(bool en); + virtual bool enabled() const; + virtual bool addIp(const InetAddress& ip); + virtual bool removeIp(const InetAddress& ip); + virtual std::vector ips() const; + virtual void put(const MAC& from, const MAC& to, unsigned int etherType, const void* data, unsigned int len); + virtual std::string deviceName() const; + virtual void setFriendlyName(const char* friendlyName); + virtual void scanMulticastGroups(std::vector& added, std::vector& removed); + virtual void setMtu(unsigned int mtu); + virtual void setDns(const char* domain, const std::vector& servers); + void threadMain() throw(); - void threadMain() - throw(); - -private: - void (*_handler)(void *,void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int); - void *_arg; - uint64_t _nwid; - Thread _thread; - std::string _homePath; - std::string _dev; - std::vector _multicastGroups; - unsigned int _mtu; - unsigned int _metric; - int _fd; - int _shutdownSignalPipe[2]; - volatile bool _enabled; - std::vector _rxThreads; + private: + void (*_handler)(void*, void*, uint64_t, const MAC&, const MAC&, unsigned int, unsigned int, const void*, unsigned int); + void* _arg; + uint64_t _nwid; + Thread _thread; + std::string _homePath; + std::string _dev; + std::vector _multicastGroups; + unsigned int _mtu; + unsigned int _metric; + int _fd; + int _shutdownSignalPipe[2]; + volatile bool _enabled; + std::vector _rxThreads; }; -} // namespace ZeroTier +} // namespace ZeroTier #endif diff --git a/osdep/ManagedRoute.cpp b/osdep/ManagedRoute.cpp index 9be2eda1..55cc1ba2 100644 --- a/osdep/ManagedRoute.cpp +++ b/osdep/ManagedRoute.cpp @@ -20,20 +20,20 @@ #include #ifdef __WINDOWS__ -#include -#include -#include #include +#include +#include +#include #endif #ifdef __UNIX_LIKE__ -#include +#include +#include #include #include #include #include -#include -#include +#include #ifndef ZT_SDK #include #endif @@ -45,11 +45,11 @@ #include #endif -#include +#include "ManagedRoute.hpp" + #include #include - -#include "ManagedRoute.hpp" +#include #ifdef __LINUX__ #include "LinuxNetLink.hpp" #endif @@ -62,365 +62,383 @@ namespace { // Fork a target into two more specific targets e.g. 0.0.0.0/0 -> 0.0.0.0/1, 128.0.0.0/1 // If the target is already maximally-specific, 'right' will be unchanged and 'left' will be 't' -static void _forkTarget(const InetAddress &t,InetAddress &left,InetAddress &right) +static void _forkTarget(const InetAddress& t, InetAddress& left, InetAddress& right) { - const unsigned int bits = t.netmaskBits() + 1; - left = t; - if (t.ss_family == AF_INET) { - if (bits <= 32) { - left.setPort(bits); - right = t; - reinterpret_cast(&right)->sin_addr.s_addr ^= Utils::hton((uint32_t)(1 << (32 - bits))); - right.setPort(bits); - } else { - right.zero(); - } - } else if (t.ss_family == AF_INET6) { - if (bits <= 128) { - left.setPort(bits); - right = t; - uint8_t *b = reinterpret_cast(reinterpret_cast(&right)->sin6_addr.s6_addr); - b[bits / 8] ^= 1 << (8 - (bits % 8)); - right.setPort(bits); - } else { - right.zero(); - } - } + const unsigned int bits = t.netmaskBits() + 1; + left = t; + if (t.ss_family == AF_INET) { + if (bits <= 32) { + left.setPort(bits); + right = t; + reinterpret_cast(&right)->sin_addr.s_addr ^= Utils::hton((uint32_t)(1 << (32 - bits))); + right.setPort(bits); + } + else { + right.zero(); + } + } + else if (t.ss_family == AF_INET6) { + if (bits <= 128) { + left.setPort(bits); + right = t; + uint8_t* b = reinterpret_cast(reinterpret_cast(&right)->sin6_addr.s6_addr); + b[bits / 8] ^= 1 << (8 - (bits % 8)); + right.setPort(bits); + } + else { + right.zero(); + } + } } -struct _RTE -{ - InetAddress target; - InetAddress via; - char device[128]; - int metric; - bool ifscope; - bool isDefault; +struct _RTE { + InetAddress target; + InetAddress via; + char device[128]; + int metric; + bool ifscope; + bool isDefault; }; -#ifdef __BSD__ // ------------------------------------------------------------ +#ifdef __BSD__ // ------------------------------------------------------------ #define ZT_ROUTING_SUPPORT_FOUND 1 #ifndef ZT_SDK -static std::vector<_RTE> _getRTEs(const InetAddress &target,bool contains) +static std::vector<_RTE> _getRTEs(const InetAddress& target, bool contains) { - std::vector<_RTE> rtes; - int mib[6]; - size_t needed; + std::vector<_RTE> rtes; + int mib[6]; + size_t needed; - mib[0] = CTL_NET; - mib[1] = PF_ROUTE; - mib[2] = 0; - mib[3] = 0; - mib[4] = NET_RT_DUMP; - mib[5] = 0; - if (!sysctl(mib,6,NULL,&needed,NULL,0)) { - if (needed <= 0) - return rtes; + mib[0] = CTL_NET; + mib[1] = PF_ROUTE; + mib[2] = 0; + mib[3] = 0; + mib[4] = NET_RT_DUMP; + mib[5] = 0; + if (! sysctl(mib, 6, NULL, &needed, NULL, 0)) { + if (needed <= 0) + return rtes; - char *buf = (char *)::malloc(needed); - if (buf) { - if (!sysctl(mib,6,buf,&needed,NULL,0)) { - struct rt_msghdr *rtm; - for(char *next=buf,*end=buf+needed;nextrtm_msglen; + char* buf = (char*)::malloc(needed); + if (buf) { + if (! sysctl(mib, 6, buf, &needed, NULL, 0)) { + struct rt_msghdr* rtm; + for (char *next = buf, *end = buf + needed; next < end;) { + rtm = (struct rt_msghdr*)next; + char* saptr = (char*)(rtm + 1); + char* saend = next + rtm->rtm_msglen; - InetAddress sa_t,sa_v; - int deviceIndex = -9999; - bool isDefault = false; + InetAddress sa_t, sa_v; + int deviceIndex = -9999; + bool isDefault = false; - if (((rtm->rtm_flags & RTF_LLINFO) == 0)&&((rtm->rtm_flags & RTF_HOST) == 0)&&((rtm->rtm_flags & RTF_UP) != 0)&&((rtm->rtm_flags & RTF_MULTICAST) == 0)) { - int which = 0; - while (saptr < saend) { - struct sockaddr *sa = (struct sockaddr *)saptr; - unsigned int salen = sa->sa_len; - if (!salen) - break; + if (((rtm->rtm_flags & RTF_LLINFO) == 0) && ((rtm->rtm_flags & RTF_HOST) == 0) && ((rtm->rtm_flags & RTF_UP) != 0) && ((rtm->rtm_flags & RTF_MULTICAST) == 0)) { + int which = 0; + while (saptr < saend) { + struct sockaddr* sa = (struct sockaddr*)saptr; + unsigned int salen = sa->sa_len; + if (! salen) + break; - // Skip missing fields in rtm_addrs bit field - while ((rtm->rtm_addrs & 1) == 0) { - rtm->rtm_addrs >>= 1; - ++which; - if (which > 6) - break; - } - if (which > 6) - break; + // Skip missing fields in rtm_addrs bit field + while ((rtm->rtm_addrs & 1) == 0) { + rtm->rtm_addrs >>= 1; + ++which; + if (which > 6) + break; + } + if (which > 6) + break; - rtm->rtm_addrs >>= 1; - switch(which++) { - case 0: - //printf("RTA_DST\n"); - if (sa->sa_family == AF_INET6) { - struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa; - if ((sin6->sin6_addr.s6_addr[0] == 0xfe)&&((sin6->sin6_addr.s6_addr[1] & 0xc0) == 0x80)) { - // BSD uses this fucking strange in-band signaling method to encode device scope IDs for IPv6 addresses... probably a holdover from very early versions of the spec. - unsigned int interfaceIndex = ((((unsigned int)sin6->sin6_addr.s6_addr[2]) << 8) & 0xff) | (((unsigned int)sin6->sin6_addr.s6_addr[3]) & 0xff); - sin6->sin6_addr.s6_addr[2] = 0; - sin6->sin6_addr.s6_addr[3] = 0; - if (!sin6->sin6_scope_id) - sin6->sin6_scope_id = interfaceIndex; - } + rtm->rtm_addrs >>= 1; + switch (which++) { + case 0: + // printf("RTA_DST\n"); + if (sa->sa_family == AF_INET6) { + struct sockaddr_in6* sin6 = (struct sockaddr_in6*)sa; + if ((sin6->sin6_addr.s6_addr[0] == 0xfe) && ((sin6->sin6_addr.s6_addr[1] & 0xc0) == 0x80)) { + // BSD uses this fucking strange in-band signaling method to encode device scope IDs for IPv6 addresses... probably a holdover from very early versions of the spec. + unsigned int interfaceIndex = ((((unsigned int)sin6->sin6_addr.s6_addr[2]) << 8) & 0xff) | (((unsigned int)sin6->sin6_addr.s6_addr[3]) & 0xff); + sin6->sin6_addr.s6_addr[2] = 0; + sin6->sin6_addr.s6_addr[3] = 0; + if (! sin6->sin6_scope_id) + sin6->sin6_scope_id = interfaceIndex; + } #ifdef __APPLE__ - isDefault = IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr) && !(rtm->rtm_flags & RTF_IFSCOPE); + isDefault = IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr) && ! (rtm->rtm_flags & RTF_IFSCOPE); #endif - } else { - struct sockaddr_in *sin4 = (struct sockaddr_in *)sa; - isDefault = sin4->sin_addr.s_addr == 0; - } - sa_t = *sa; - break; - case 1: - //printf("RTA_GATEWAY\n"); - switch(sa->sa_family) { - case AF_LINK: - // deviceIndex = (int)((const struct sockaddr_dl *)sa)->sdl_index; - case AF_INET: - case AF_INET6: - sa_v = *sa; - break; - } - break; - case 2: { - //printf("RTA_NETMASK\n"); - if (sa_t.ss_family == AF_INET6) { - salen = sizeof(struct sockaddr_in6); - unsigned int bits = 0; - for(int i=0;i<16;++i) { - unsigned char c = (unsigned char)((const struct sockaddr_in6 *)sa)->sin6_addr.s6_addr[i]; - if (c == 0xff) - bits += 8; - else break; - } - sa_t.setPort(bits); - } else if (sa_t.ss_family == AF_INET) { - salen = sizeof(struct sockaddr_in); - sa_t.setPort((unsigned int)Utils::countBits((uint32_t)((const struct sockaddr_in *)sa)->sin_addr.s_addr)); - } - } break; - /* - case 3: - //printf("RTA_GENMASK\n"); - break; - case 4: - //printf("RTA_IFP\n"); - break; - case 5: - //printf("RTA_IFA\n"); - break; - case 6: - //printf("RTA_AUTHOR\n"); - break; - */ - } + } + else { + struct sockaddr_in* sin4 = (struct sockaddr_in*)sa; + isDefault = sin4->sin_addr.s_addr == 0; + } + sa_t = *sa; + break; + case 1: + // printf("RTA_GATEWAY\n"); + switch (sa->sa_family) { + case AF_LINK: + // deviceIndex = (int)((const struct sockaddr_dl *)sa)->sdl_index; + case AF_INET: + case AF_INET6: + sa_v = *sa; + break; + } + break; + case 2: { + // printf("RTA_NETMASK\n"); + if (sa_t.ss_family == AF_INET6) { + salen = sizeof(struct sockaddr_in6); + unsigned int bits = 0; + for (int i = 0; i < 16; ++i) { + unsigned char c = (unsigned char)((const struct sockaddr_in6*)sa)->sin6_addr.s6_addr[i]; + if (c == 0xff) + bits += 8; + else + break; + } + sa_t.setPort(bits); + } + else if (sa_t.ss_family == AF_INET) { + salen = sizeof(struct sockaddr_in); + sa_t.setPort((unsigned int)Utils::countBits((uint32_t)((const struct sockaddr_in*)sa)->sin_addr.s_addr)); + } + } break; + /* + case 3: + //printf("RTA_GENMASK\n"); + break; + case 4: + //printf("RTA_IFP\n"); + break; + case 5: + //printf("RTA_IFA\n"); + break; + case 6: + //printf("RTA_AUTHOR\n"); + break; + */ + } - saptr += salen; - } + saptr += salen; + } + deviceIndex = rtm->rtm_index; - deviceIndex = rtm->rtm_index; + if (((contains) && (sa_t.containsAddress(target))) || (sa_t == target)) { + rtes.push_back(_RTE()); + rtes.back().target = sa_t; + rtes.back().via = sa_v; + rtes.back().isDefault = isDefault; + if (deviceIndex >= 0) { + if_indextoname(deviceIndex, rtes.back().device); + } + else { + rtes.back().device[0] = (char)0; + } + rtes.back().metric = ((int)rtm->rtm_rmx.rmx_hopcount < 0) ? 0 : (int)rtm->rtm_rmx.rmx_hopcount; + } + } + next = saend; + } + } - if (((contains)&&(sa_t.containsAddress(target)))||(sa_t == target)) { - rtes.push_back(_RTE()); - rtes.back().target = sa_t; - rtes.back().via = sa_v; - rtes.back().isDefault = isDefault; - if (deviceIndex >= 0) { - if_indextoname(deviceIndex,rtes.back().device); - } else { - rtes.back().device[0] = (char)0; - } - rtes.back().metric = ((int)rtm->rtm_rmx.rmx_hopcount < 0) ? 0 : (int)rtm->rtm_rmx.rmx_hopcount; - } - } + ::free(buf); + } + } - next = saend; - } - } - - ::free(buf); - } - } - - return rtes; + return rtes; } #endif -static void _routeCmd(const char *op,const InetAddress &target,const InetAddress &via,const char *ifscope,const char *localInterface) +static void _routeCmd(const char* op, const InetAddress& target, const InetAddress& via, const char* ifscope, const char* localInterface) { - // char f1[1024],f2[1024]; printf("cmd %s %s %s %s %s\n",op,target.toString(f1),via.toString(f2),ifscope,localInterface); - long p = (long)fork(); - if (p > 0) { - int exitcode = -1; - ::waitpid(p,&exitcode,0); - } else if (p == 0) { - ::close(STDOUT_FILENO); - ::close(STDERR_FILENO); - char ttmp[64]; - char iptmp[64]; - if (via) { - if ((ifscope)&&(ifscope[0])) { + // char f1[1024],f2[1024]; printf("cmd %s %s %s %s %s\n",op,target.toString(f1),via.toString(f2),ifscope,localInterface); + long p = (long)fork(); + if (p > 0) { + int exitcode = -1; + ::waitpid(p, &exitcode, 0); + } + else if (p == 0) { + ::close(STDOUT_FILENO); + ::close(STDERR_FILENO); + char ttmp[64]; + char iptmp[64]; + if (via) { + if ((ifscope) && (ifscope[0])) { #ifdef ZT_TRACE - fprintf(stderr, "DEBUG: route %s -ifscope %s %s %s" ZT_EOL_S, ifscope,((target.ss_family == AF_INET6) ? "-inet6" : "-inet"),target.toString(ttmp),via.toIpString(iptmp)); + fprintf(stderr, "DEBUG: route %s -ifscope %s %s %s" ZT_EOL_S, ifscope, ((target.ss_family == AF_INET6) ? "-inet6" : "-inet"), target.toString(ttmp), via.toIpString(iptmp)); #endif - ::execl(ZT_BSD_ROUTE_CMD,ZT_BSD_ROUTE_CMD,op,"-ifscope",ifscope,((target.ss_family == AF_INET6) ? "-inet6" : "-inet"),target.toString(ttmp),via.toIpString(iptmp),(const char *)0); - } else { + ::execl(ZT_BSD_ROUTE_CMD, ZT_BSD_ROUTE_CMD, op, "-ifscope", ifscope, ((target.ss_family == AF_INET6) ? "-inet6" : "-inet"), target.toString(ttmp), via.toIpString(iptmp), (const char*)0); + } + else { #ifdef ZT_TRACE - fprintf(stderr, "DEBUG: route %s %s %s %s" ZT_EOL_S, op,((target.ss_family == AF_INET6) ? "-inet6" : "-inet"),target.toString(ttmp),via.toIpString(iptmp)); + fprintf(stderr, "DEBUG: route %s %s %s %s" ZT_EOL_S, op, ((target.ss_family == AF_INET6) ? "-inet6" : "-inet"), target.toString(ttmp), via.toIpString(iptmp)); #endif - ::execl(ZT_BSD_ROUTE_CMD,ZT_BSD_ROUTE_CMD,op,((target.ss_family == AF_INET6) ? "-inet6" : "-inet"),target.toString(ttmp),via.toIpString(iptmp),(const char *)0); - } - } else if ((localInterface)&&(localInterface[0])) { - if ((ifscope)&&(ifscope[0])) { + ::execl(ZT_BSD_ROUTE_CMD, ZT_BSD_ROUTE_CMD, op, ((target.ss_family == AF_INET6) ? "-inet6" : "-inet"), target.toString(ttmp), via.toIpString(iptmp), (const char*)0); + } + } + else if ((localInterface) && (localInterface[0])) { + if ((ifscope) && (ifscope[0])) { #ifdef ZT_TRACE - fprintf(stderr, "DEBUG: route %s -ifscope %s %s %s -interface %s" ZT_EOL_S, op, ifscope,((target.ss_family == AF_INET6) ? "-inet6" : "-inet"),target.toString(ttmp),localInterface); + fprintf(stderr, "DEBUG: route %s -ifscope %s %s %s -interface %s" ZT_EOL_S, op, ifscope, ((target.ss_family == AF_INET6) ? "-inet6" : "-inet"), target.toString(ttmp), localInterface); #endif - ::execl(ZT_BSD_ROUTE_CMD,ZT_BSD_ROUTE_CMD,op,"-ifscope",ifscope,((target.ss_family == AF_INET6) ? "-inet6" : "-inet"),target.toString(ttmp),"-interface",localInterface,(const char *)0); - } else { + ::execl(ZT_BSD_ROUTE_CMD, ZT_BSD_ROUTE_CMD, op, "-ifscope", ifscope, ((target.ss_family == AF_INET6) ? "-inet6" : "-inet"), target.toString(ttmp), "-interface", localInterface, (const char*)0); + } + else { #ifdef ZT_TRACE - fprintf(stderr, "DEBUG: route %s %s %s -interface %s" ZT_EOL_S, op,((target.ss_family == AF_INET6) ? "-inet6" : "-inet"),target.toString(ttmp),localInterface); + fprintf(stderr, "DEBUG: route %s %s %s -interface %s" ZT_EOL_S, op, ((target.ss_family == AF_INET6) ? "-inet6" : "-inet"), target.toString(ttmp), localInterface); #endif - ::execl(ZT_BSD_ROUTE_CMD,ZT_BSD_ROUTE_CMD,op,((target.ss_family == AF_INET6) ? "-inet6" : "-inet"),target.toString(ttmp),"-interface",localInterface,(const char *)0); - } - } - ::_exit(-1); - } + ::execl(ZT_BSD_ROUTE_CMD, ZT_BSD_ROUTE_CMD, op, ((target.ss_family == AF_INET6) ? "-inet6" : "-inet"), target.toString(ttmp), "-interface", localInterface, (const char*)0); + } + } + ::_exit(-1); + } } -#endif // __BSD__ ------------------------------------------------------------ +#endif // __BSD__ ------------------------------------------------------------ -#ifdef __LINUX__ // ---------------------------------------------------------- +#ifdef __LINUX__ // ---------------------------------------------------------- #define ZT_ROUTING_SUPPORT_FOUND 1 // This has been replaced by LinuxNetLink -#endif // __LINUX__ ---------------------------------------------------------- +#endif // __LINUX__ ---------------------------------------------------------- -#ifdef __WINDOWS__ // -------------------------------------------------------- +#ifdef __WINDOWS__ // -------------------------------------------------------- #define ZT_ROUTING_SUPPORT_FOUND 1 -static bool _winRoute(bool del,const NET_LUID &interfaceLuid,const NET_IFINDEX &interfaceIndex,const InetAddress &target,const InetAddress &via) +static bool _winRoute(bool del, const NET_LUID& interfaceLuid, const NET_IFINDEX& interfaceIndex, const InetAddress& target, const InetAddress& via) { - MIB_IPFORWARD_ROW2 rtrow; - InitializeIpForwardEntry(&rtrow); - rtrow.InterfaceLuid.Value = interfaceLuid.Value; - rtrow.InterfaceIndex = interfaceIndex; - if (target.ss_family == AF_INET) { - rtrow.DestinationPrefix.Prefix.si_family = AF_INET; - rtrow.DestinationPrefix.Prefix.Ipv4.sin_family = AF_INET; - rtrow.DestinationPrefix.Prefix.Ipv4.sin_addr.S_un.S_addr = reinterpret_cast(&target)->sin_addr.S_un.S_addr; - if (via.ss_family == AF_INET) { - rtrow.NextHop.si_family = AF_INET; - rtrow.NextHop.Ipv4.sin_family = AF_INET; - rtrow.NextHop.Ipv4.sin_addr.S_un.S_addr = reinterpret_cast(&via)->sin_addr.S_un.S_addr; - } - } else if (target.ss_family == AF_INET6) { - rtrow.DestinationPrefix.Prefix.si_family = AF_INET6; - rtrow.DestinationPrefix.Prefix.Ipv6.sin6_family = AF_INET6; - memcpy(rtrow.DestinationPrefix.Prefix.Ipv6.sin6_addr.u.Byte,reinterpret_cast(&target)->sin6_addr.u.Byte,16); - if (via.ss_family == AF_INET6) { - rtrow.NextHop.si_family = AF_INET6; - rtrow.NextHop.Ipv6.sin6_family = AF_INET6; - memcpy(rtrow.NextHop.Ipv6.sin6_addr.u.Byte,reinterpret_cast(&via)->sin6_addr.u.Byte,16); - } - } else { - return false; - } - rtrow.DestinationPrefix.PrefixLength = target.netmaskBits(); - rtrow.SitePrefixLength = rtrow.DestinationPrefix.PrefixLength; - rtrow.ValidLifetime = 0xffffffff; - rtrow.PreferredLifetime = 0xffffffff; - rtrow.Metric = -1; - rtrow.Protocol = MIB_IPPROTO_NETMGMT; - rtrow.Loopback = FALSE; - rtrow.AutoconfigureAddress = FALSE; - rtrow.Publish = FALSE; - rtrow.Immortal = FALSE; - rtrow.Age = 0; - rtrow.Origin = NlroManual; - if (del) { - return (DeleteIpForwardEntry2(&rtrow) == NO_ERROR); - } else { - NTSTATUS r = CreateIpForwardEntry2(&rtrow); - if (r == NO_ERROR) { - return true; - } else if (r == ERROR_OBJECT_ALREADY_EXISTS) { - return (SetIpForwardEntry2(&rtrow) == NO_ERROR); - } else { - return false; - } - } + MIB_IPFORWARD_ROW2 rtrow; + InitializeIpForwardEntry(&rtrow); + rtrow.InterfaceLuid.Value = interfaceLuid.Value; + rtrow.InterfaceIndex = interfaceIndex; + if (target.ss_family == AF_INET) { + rtrow.DestinationPrefix.Prefix.si_family = AF_INET; + rtrow.DestinationPrefix.Prefix.Ipv4.sin_family = AF_INET; + rtrow.DestinationPrefix.Prefix.Ipv4.sin_addr.S_un.S_addr = reinterpret_cast(&target)->sin_addr.S_un.S_addr; + if (via.ss_family == AF_INET) { + rtrow.NextHop.si_family = AF_INET; + rtrow.NextHop.Ipv4.sin_family = AF_INET; + rtrow.NextHop.Ipv4.sin_addr.S_un.S_addr = reinterpret_cast(&via)->sin_addr.S_un.S_addr; + } + } + else if (target.ss_family == AF_INET6) { + rtrow.DestinationPrefix.Prefix.si_family = AF_INET6; + rtrow.DestinationPrefix.Prefix.Ipv6.sin6_family = AF_INET6; + memcpy(rtrow.DestinationPrefix.Prefix.Ipv6.sin6_addr.u.Byte, reinterpret_cast(&target)->sin6_addr.u.Byte, 16); + if (via.ss_family == AF_INET6) { + rtrow.NextHop.si_family = AF_INET6; + rtrow.NextHop.Ipv6.sin6_family = AF_INET6; + memcpy(rtrow.NextHop.Ipv6.sin6_addr.u.Byte, reinterpret_cast(&via)->sin6_addr.u.Byte, 16); + } + } + else { + return false; + } + rtrow.DestinationPrefix.PrefixLength = target.netmaskBits(); + rtrow.SitePrefixLength = rtrow.DestinationPrefix.PrefixLength; + rtrow.ValidLifetime = 0xffffffff; + rtrow.PreferredLifetime = 0xffffffff; + rtrow.Metric = -1; + rtrow.Protocol = MIB_IPPROTO_NETMGMT; + rtrow.Loopback = FALSE; + rtrow.AutoconfigureAddress = FALSE; + rtrow.Publish = FALSE; + rtrow.Immortal = FALSE; + rtrow.Age = 0; + rtrow.Origin = NlroManual; + if (del) { + return (DeleteIpForwardEntry2(&rtrow) == NO_ERROR); + } + else { + NTSTATUS r = CreateIpForwardEntry2(&rtrow); + if (r == NO_ERROR) { + return true; + } + else if (r == ERROR_OBJECT_ALREADY_EXISTS) { + return (SetIpForwardEntry2(&rtrow) == NO_ERROR); + } + else { + return false; + } + } } -static bool _winHasRoute(const NET_LUID &interfaceLuid, const NET_IFINDEX &interfaceIndex, const InetAddress &target, const InetAddress &via) +static bool _winHasRoute(const NET_LUID& interfaceLuid, const NET_IFINDEX& interfaceIndex, const InetAddress& target, const InetAddress& via) { - MIB_IPFORWARD_ROW2 rtrow; - InitializeIpForwardEntry(&rtrow); - rtrow.InterfaceLuid.Value = interfaceLuid.Value; - rtrow.InterfaceIndex = interfaceIndex; - if (target.ss_family == AF_INET) { - rtrow.DestinationPrefix.Prefix.si_family = AF_INET; - rtrow.DestinationPrefix.Prefix.Ipv4.sin_family = AF_INET; - rtrow.DestinationPrefix.Prefix.Ipv4.sin_addr.S_un.S_addr = reinterpret_cast(&target)->sin_addr.S_un.S_addr; - if (via.ss_family == AF_INET) { - rtrow.NextHop.si_family = AF_INET; - rtrow.NextHop.Ipv4.sin_family = AF_INET; - rtrow.NextHop.Ipv4.sin_addr.S_un.S_addr = reinterpret_cast(&via)->sin_addr.S_un.S_addr; - } - } else if (target.ss_family == AF_INET6) { - rtrow.DestinationPrefix.Prefix.si_family = AF_INET6; - rtrow.DestinationPrefix.Prefix.Ipv6.sin6_family = AF_INET6; - memcpy(rtrow.DestinationPrefix.Prefix.Ipv6.sin6_addr.u.Byte, reinterpret_cast(&target)->sin6_addr.u.Byte, 16); - if (via.ss_family == AF_INET6) { - rtrow.NextHop.si_family = AF_INET6; - rtrow.NextHop.Ipv6.sin6_family = AF_INET6; - memcpy(rtrow.NextHop.Ipv6.sin6_addr.u.Byte, reinterpret_cast(&via)->sin6_addr.u.Byte, 16); - } - } else { - return false; - } - rtrow.DestinationPrefix.PrefixLength = target.netmaskBits(); - rtrow.SitePrefixLength = rtrow.DestinationPrefix.PrefixLength; - return (GetIpForwardEntry2(&rtrow) == NO_ERROR); + MIB_IPFORWARD_ROW2 rtrow; + InitializeIpForwardEntry(&rtrow); + rtrow.InterfaceLuid.Value = interfaceLuid.Value; + rtrow.InterfaceIndex = interfaceIndex; + if (target.ss_family == AF_INET) { + rtrow.DestinationPrefix.Prefix.si_family = AF_INET; + rtrow.DestinationPrefix.Prefix.Ipv4.sin_family = AF_INET; + rtrow.DestinationPrefix.Prefix.Ipv4.sin_addr.S_un.S_addr = reinterpret_cast(&target)->sin_addr.S_un.S_addr; + if (via.ss_family == AF_INET) { + rtrow.NextHop.si_family = AF_INET; + rtrow.NextHop.Ipv4.sin_family = AF_INET; + rtrow.NextHop.Ipv4.sin_addr.S_un.S_addr = reinterpret_cast(&via)->sin_addr.S_un.S_addr; + } + } + else if (target.ss_family == AF_INET6) { + rtrow.DestinationPrefix.Prefix.si_family = AF_INET6; + rtrow.DestinationPrefix.Prefix.Ipv6.sin6_family = AF_INET6; + memcpy(rtrow.DestinationPrefix.Prefix.Ipv6.sin6_addr.u.Byte, reinterpret_cast(&target)->sin6_addr.u.Byte, 16); + if (via.ss_family == AF_INET6) { + rtrow.NextHop.si_family = AF_INET6; + rtrow.NextHop.Ipv6.sin6_family = AF_INET6; + memcpy(rtrow.NextHop.Ipv6.sin6_addr.u.Byte, reinterpret_cast(&via)->sin6_addr.u.Byte, 16); + } + } + else { + return false; + } + rtrow.DestinationPrefix.PrefixLength = target.netmaskBits(); + rtrow.SitePrefixLength = rtrow.DestinationPrefix.PrefixLength; + return (GetIpForwardEntry2(&rtrow) == NO_ERROR); } -#endif // __WINDOWS__ -------------------------------------------------------- +#endif // __WINDOWS__ -------------------------------------------------------- #ifndef ZT_ROUTING_SUPPORT_FOUND -#error "ManagedRoute.cpp has no support for managing routes on this platform! You'll need to check and see if one of the existing ones will work and make sure proper defines are set, or write one. Please do a GitHub pull request if you do this for a new OS." +#error \ + "ManagedRoute.cpp has no support for managing routes on this platform! You'll need to check and see if one of the existing ones will work and make sure proper defines are set, or write one. Please do a GitHub pull request if you do this for a new OS." #endif -} // anonymous namespace +} // anonymous namespace -ManagedRoute::ManagedRoute(const InetAddress &target,const InetAddress &via,const InetAddress &src,const char *device) +ManagedRoute::ManagedRoute(const InetAddress& target, const InetAddress& via, const InetAddress& src, const char* device) { - _target = target; - _via = via; - _src = src; + _target = target; + _via = via; + _src = src; - if (_via.ss_family == AF_INET) { - _via.setPort(32); - } else if (_via.ss_family == AF_INET6) { - _via.setPort(128); - } + if (_via.ss_family == AF_INET) { + _via.setPort(32); + } + else if (_via.ss_family == AF_INET6) { + _via.setPort(128); + } - if (_src.ss_family == AF_INET) { - _src.setPort(32); - } else if (_src.ss_family == AF_INET6) { - _src.setPort(128); - } + if (_src.ss_family == AF_INET) { + _src.setPort(32); + } + else if (_src.ss_family == AF_INET6) { + _src.setPort(128); + } - Utils::scopy(_device,sizeof(_device),device); - _systemDevice[0] = (char)0; + Utils::scopy(_device, sizeof(_device), device); + _systemDevice[0] = (char)0; } ManagedRoute::~ManagedRoute() { - this->remove(); + this->remove(); } /* Linux NOTE: for default route override, some Linux distributions will @@ -439,190 +457,192 @@ ManagedRoute::~ManagedRoute() bool ManagedRoute::sync() { #ifdef __WINDOWS__ - NET_LUID interfaceLuid; - interfaceLuid.Value = (ULONG64)Utils::hexStrToU64(_device); // on Windows we use the hex LUID as the "interface name" for ManagedRoute - NET_IFINDEX interfaceIndex = -1; - if (ConvertInterfaceLuidToIndex(&interfaceLuid,&interfaceIndex) != NO_ERROR) - return false; + NET_LUID interfaceLuid; + interfaceLuid.Value = (ULONG64)Utils::hexStrToU64(_device); // on Windows we use the hex LUID as the "interface name" for ManagedRoute + NET_IFINDEX interfaceIndex = -1; + if (ConvertInterfaceLuidToIndex(&interfaceLuid, &interfaceIndex) != NO_ERROR) + return false; #endif - InetAddress leftt,rightt; - if (_target.netmaskBits() == 0) // bifurcate only the default route - _forkTarget(_target,leftt,rightt); - else leftt = _target; + InetAddress leftt, rightt; + if (_target.netmaskBits() == 0) // bifurcate only the default route + _forkTarget(_target, leftt, rightt); + else + leftt = _target; -#ifdef __BSD__ // ------------------------------------------------------------ +#ifdef __BSD__ // ------------------------------------------------------------ - if (_device[0]) { - bool haveDevice = false; - struct ifaddrs *ifa = (struct ifaddrs *)0; - if (!getifaddrs(&ifa)) { - struct ifaddrs *p = ifa; - while (p) { - if ((p->ifa_name)&&(!strcmp(_device, p->ifa_name))) { - haveDevice = true; - break; - } - p = p->ifa_next; - } - freeifaddrs(ifa); - } - if (!haveDevice) - return false; - } + if (_device[0]) { + bool haveDevice = false; + struct ifaddrs* ifa = (struct ifaddrs*)0; + if (! getifaddrs(&ifa)) { + struct ifaddrs* p = ifa; + while (p) { + if ((p->ifa_name) && (! strcmp(_device, p->ifa_name))) { + haveDevice = true; + break; + } + p = p->ifa_next; + } + freeifaddrs(ifa); + } + if (! haveDevice) + return false; + } - std::vector<_RTE> rtes(_getRTEs(_target,false)); + std::vector<_RTE> rtes(_getRTEs(_target, false)); - bool hasRoute = false; - for(std::vector<_RTE>::iterator r(rtes.begin());r!=rtes.end();++r) { - hasRoute = _target == r->target && _via.ipOnly() == r->via.ipOnly() && (strcmp(r->device,_device) == 0); - if (hasRoute) { break; } - } + bool hasRoute = false; + for (std::vector<_RTE>::iterator r(rtes.begin()); r != rtes.end(); ++r) { + hasRoute = _target == r->target && _via.ipOnly() == r->via.ipOnly() && (strcmp(r->device, _device) == 0); + if (hasRoute) { + break; + } + } - // char buf[255]; - // fprintf(stderr, "hasRoute %d %s\n", !!hasRoute, _target.toString(buf)); + // char buf[255]; + // fprintf(stderr, "hasRoute %d %s\n", !!hasRoute, _target.toString(buf)); + if (! hasRoute) { + if (_target && _target.netmaskBits() == 0) { // Allow Default + InetAddress newSystemVia; + char newSystemDevice[128]; + newSystemDevice[0] = (char)0; - if (!hasRoute) { - if (_target && _target.netmaskBits() == 0) { // Allow Default - InetAddress newSystemVia; - char newSystemDevice[128]; - newSystemDevice[0] = (char)0; + // if our routes got deleted + // delete the systemd via that we had added with -ifscope + if (_systemVia && ! ! _systemDevice[0]) { + _routeCmd("delete", _target, _systemVia, _systemDevice, (const char*)0); + } - // if our routes got deleted - // delete the systemd via that we had added with -ifscope - if (_systemVia && !!_systemDevice[0]) { - _routeCmd("delete",_target,_systemVia,_systemDevice,(const char *)0); - } + _systemVia = newSystemVia; + Utils::scopy(_systemDevice, sizeof(_systemDevice), newSystemDevice); + // If macos has a network hiccup, it deletes what the route we set, and it's own physical routes. + // if !hasRoute (our 0.0.0.0 has been deleted), the OS has changed stuff + // So don't assume _systemX are valid anymore. Always get for _system{Via,Device} - _systemVia = newSystemVia; - Utils::scopy(_systemDevice,sizeof(_systemDevice),newSystemDevice); - // If macos has a network hiccup, it deletes what the route we set, and it's own physical routes. - // if !hasRoute (our 0.0.0.0 has been deleted), the OS has changed stuff - // So don't assume _systemX are valid anymore. Always get for _system{Via,Device} + // Find system default route that this route should override + // We need to put it back when default route is turned off + for (std::vector<_RTE>::iterator r(rtes.begin()); r != rtes.end(); ++r) { + if (r->via) { + if (r->isDefault == 1 && (strcmp(r->device, _device) != 0)) { + // char buf[255]; + // fprintf(stderr, "system device1 %s %s\n", r->via.toString(buf), r->device); - // Find system default route that this route should override - // We need to put it back when default route is turned off - for(std::vector<_RTE>::iterator r(rtes.begin());r!=rtes.end();++r) { - if (r->via) { - if ( r->isDefault == 1 && (strcmp(r->device,_device) != 0) ) { + newSystemVia = r->via; + Utils::scopy(newSystemDevice, sizeof(newSystemDevice), r->device); + break; + } + } + } - // char buf[255]; - // fprintf(stderr, "system device1 %s %s\n", r->via.toString(buf), r->device); + if (newSystemVia) { + _systemVia = newSystemVia; + } + if (newSystemDevice[0]) { + Utils::scopy(_systemDevice, sizeof(_systemDevice), newSystemDevice); + } - newSystemVia = r->via; - Utils::scopy(newSystemDevice,sizeof(newSystemDevice),r->device); - break; - } - } - } + // if there's no newSystemVia, the OS might not have + // ipv4 or ipv6 connectivity. + // we should still add our ZeroTier ipv4 or 6 routes though - if (newSystemVia) { _systemVia = newSystemVia; } - if (newSystemDevice[0]) { - Utils::scopy(_systemDevice,sizeof(_systemDevice),newSystemDevice); - } + if (! ! _systemVia && ! ! _systemDevice[0]) { + _routeCmd("delete", _target, _systemVia, (const char*)0, (const char*)0); + } - // if there's no newSystemVia, the OS might not have - // ipv4 or ipv6 connectivity. - // we should still add our ZeroTier ipv4 or 6 routes though + _routeCmd("add", _target, _via, (const char*)0, (const char*)0); - if (!!_systemVia && !!_systemDevice[0]) { - _routeCmd("delete",_target,_systemVia,(const char *)0,(const char *)0); - } + if (! ! _systemVia && ! ! _systemDevice[0]) { + _routeCmd("add", _target, _systemVia, _systemDevice, (const char*)0); + } - _routeCmd("add",_target,_via,(const char *)0,(const char *)0); + _applied[_target] = true; + } + else { + // Do Non-Default route commands + _applied[_target] = true; + _routeCmd("add", leftt, _via, (const char*)0, (_via) ? (const char*)0 : _device); + } + } - if (!!_systemVia && !!_systemDevice[0]) { - _routeCmd("add",_target,_systemVia,_systemDevice,(const char *)0); - } +#endif // __BSD__ ------------------------------------------------------------ - _applied[_target] = true; +#ifdef __LINUX__ // ---------------------------------------------------------- - } else { - // Do Non-Default route commands - _applied[_target] = true; - _routeCmd("add",leftt,_via,(const char *)0,(_via) ? (const char *)0 : _device); - } - } + if ((leftt) && (! LinuxNetLink::getInstance().routeIsSet(leftt, _via, _src, _device))) { + _applied[leftt] = false; // boolean unused + LinuxNetLink::getInstance().addRoute(leftt, _via, _src, _device); + } + if ((rightt) && (! LinuxNetLink::getInstance().routeIsSet(rightt, _via, _src, _device))) { + _applied[rightt] = false; // boolean unused + LinuxNetLink::getInstance().addRoute(rightt, _via, _src, _device); + } +#endif // __LINUX__ ---------------------------------------------------------- -#endif // __BSD__ ------------------------------------------------------------ +#ifdef __WINDOWS__ // -------------------------------------------------------- -#ifdef __LINUX__ // ---------------------------------------------------------- + if ((! _applied.count(leftt)) || (! _winHasRoute(interfaceLuid, interfaceIndex, leftt, _via))) { + _applied[leftt] = false; // boolean unused + _winRoute(false, interfaceLuid, interfaceIndex, leftt, _via); + } + if ((rightt) && ((! _applied.count(rightt)) || (! _winHasRoute(interfaceLuid, interfaceIndex, rightt, _via)))) { + _applied[rightt] = false; // boolean unused + _winRoute(false, interfaceLuid, interfaceIndex, rightt, _via); + } - if ((leftt)&&(!LinuxNetLink::getInstance().routeIsSet(leftt,_via,_src,_device))) { - _applied[leftt] = false; // boolean unused - LinuxNetLink::getInstance().addRoute(leftt, _via, _src, _device); - } - if ((rightt)&&(!LinuxNetLink::getInstance().routeIsSet(rightt,_via,_src,_device))) { - _applied[rightt] = false; // boolean unused - LinuxNetLink::getInstance().addRoute(rightt, _via, _src, _device); - } +#endif // __WINDOWS__ -------------------------------------------------------- -#endif // __LINUX__ ---------------------------------------------------------- - -#ifdef __WINDOWS__ // -------------------------------------------------------- - - if ( (!_applied.count(leftt)) || (!_winHasRoute(interfaceLuid,interfaceIndex,leftt,_via)) ) { - _applied[leftt] = false; // boolean unused - _winRoute(false,interfaceLuid,interfaceIndex,leftt,_via); - } - if ( (rightt) && ( (!_applied.count(rightt)) || (!_winHasRoute(interfaceLuid,interfaceIndex,rightt,_via)) ) ) { - _applied[rightt] = false; // boolean unused - _winRoute(false,interfaceLuid,interfaceIndex,rightt,_via); - } - -#endif // __WINDOWS__ -------------------------------------------------------- - - return true; + return true; } #endif void ManagedRoute::remove() { #ifdef __WINDOWS__ - NET_LUID interfaceLuid; - interfaceLuid.Value = (ULONG64)Utils::hexStrToU64(_device); // on Windows we use the hex LUID as the "interface name" for ManagedRoute - NET_IFINDEX interfaceIndex = -1; - if (ConvertInterfaceLuidToIndex(&interfaceLuid,&interfaceIndex) != NO_ERROR) - return; + NET_LUID interfaceLuid; + interfaceLuid.Value = (ULONG64)Utils::hexStrToU64(_device); // on Windows we use the hex LUID as the "interface name" for ManagedRoute + NET_IFINDEX interfaceIndex = -1; + if (ConvertInterfaceLuidToIndex(&interfaceLuid, &interfaceIndex) != NO_ERROR) + return; #endif #ifdef __BSD__ -#endif // __BSD__ ------------------------------------------------------------ +#endif // __BSD__ ------------------------------------------------------------ - for(std::map::iterator r(_applied.begin());r!=_applied.end();++r) { -#ifdef __BSD__ // ------------------------------------------------------------ - if (_target && _target.netmaskBits() == 0) { - _routeCmd("delete",_target,_via,(const char *)0,(const char *)0); - if (_systemVia && _systemDevice[0]) { - _routeCmd("delete",_target,_systemVia,_systemDevice,(const char *)0); + for (std::map::iterator r(_applied.begin()); r != _applied.end(); ++r) { +#ifdef __BSD__ // ------------------------------------------------------------ + if (_target && _target.netmaskBits() == 0) { + _routeCmd("delete", _target, _via, (const char*)0, (const char*)0); + if (_systemVia && _systemDevice[0]) { + _routeCmd("delete", _target, _systemVia, _systemDevice, (const char*)0); - _routeCmd("add",_target,_systemVia,(const char *)0,(const char *)0); + _routeCmd("add", _target, _systemVia, (const char*)0, (const char*)0); + } + } + else { + _routeCmd("delete", _target, _via, (const char*)0, _via ? (const char*)0 : _device); + } + break; +#endif // __BSD__ ------------------------------------------------------------ - } - } else { - _routeCmd("delete",_target,_via, (const char *)0, _via ? (const char *)0 : _device); - } - break; -#endif // __BSD__ ------------------------------------------------------------ +#ifdef __LINUX__ // ---------------------------------------------------------- + //_routeCmd("del",r->first,_via,(_via) ? (const char *)0 : _device); + LinuxNetLink::getInstance().delRoute(r->first, _via, _src, (_via) ? (const char*)0 : _device); +#endif // __LINUX__ ---------------------------------------------------------- -#ifdef __LINUX__ // ---------------------------------------------------------- - //_routeCmd("del",r->first,_via,(_via) ? (const char *)0 : _device); - LinuxNetLink::getInstance().delRoute(r->first,_via,_src,(_via) ? (const char *)0 : _device); -#endif // __LINUX__ ---------------------------------------------------------- +#ifdef __WINDOWS__ // -------------------------------------------------------- + _winRoute(true, interfaceLuid, interfaceIndex, r->first, _via); +#endif // __WINDOWS__ -------------------------------------------------------- + } -#ifdef __WINDOWS__ // -------------------------------------------------------- - _winRoute(true,interfaceLuid,interfaceIndex,r->first,_via); -#endif // __WINDOWS__ -------------------------------------------------------- - } - - _target.zero(); - _via.zero(); - _systemVia.zero(); - _device[0] = (char)0; - _systemDevice[0] = (char)0; - _applied.clear(); + _target.zero(); + _via.zero(); + _systemVia.zero(); + _device[0] = (char)0; + _systemDevice[0] = (char)0; + _applied.clear(); } -} // namespace ZeroTier +} // namespace ZeroTier diff --git a/osdep/ManagedRoute.hpp b/osdep/ManagedRoute.hpp index 4cadedaa..11fda77f 100644 --- a/osdep/ManagedRoute.hpp +++ b/osdep/ManagedRoute.hpp @@ -14,70 +14,85 @@ #ifndef ZT_MANAGEDROUTE_HPP #define ZT_MANAGEDROUTE_HPP +#include "../node/AtomicCounter.hpp" +#include "../node/InetAddress.hpp" +#include "../node/SharedPtr.hpp" +#include "../node/Utils.hpp" + +#include +#include #include #include - -#include "../node/InetAddress.hpp" -#include "../node/Utils.hpp" -#include "../node/SharedPtr.hpp" -#include "../node/AtomicCounter.hpp" - -#include #include -#include namespace ZeroTier { /** * A ZT-managed route that used C++ RAII semantics to automatically clean itself up on deallocate */ -class ManagedRoute -{ - friend class SharedPtr; +class ManagedRoute { + friend class SharedPtr; -public: - ManagedRoute(const InetAddress &target,const InetAddress &via,const InetAddress &src,const char *device); - ~ManagedRoute(); + public: + ManagedRoute(const InetAddress& target, const InetAddress& via, const InetAddress& src, const char* device); + ~ManagedRoute(); - /** - * Set or update currently set route - * - * This must be called periodically for routes that shadow others so that - * shadow routes can be updated. In some cases it has no effect - * - * @return True if route add/update was successful - */ - bool sync(); + /** + * Set or update currently set route + * + * This must be called periodically for routes that shadow others so that + * shadow routes can be updated. In some cases it has no effect + * + * @return True if route add/update was successful + */ + bool sync(); - /** - * Remove and clear this ManagedRoute - * - * This does nothing if this ManagedRoute is not set or has already been - * removed. If this is not explicitly called it is called automatically on - * destruct. - */ - void remove(); + /** + * Remove and clear this ManagedRoute + * + * This does nothing if this ManagedRoute is not set or has already been + * removed. If this is not explicitly called it is called automatically on + * destruct. + */ + void remove(); - inline const InetAddress &target() const { return _target; } - inline const InetAddress &via() const { return _via; } - inline const InetAddress &src() const { return _src; } - inline const char *device() const { return _device; } + inline const InetAddress& target() const + { + return _target; + } + inline const InetAddress& via() const + { + return _via; + } + inline const InetAddress& src() const + { + return _src; + } + inline const char* device() const + { + return _device; + } -private: - ManagedRoute(const ManagedRoute &) {} - inline ManagedRoute &operator=(const ManagedRoute &) { return *this; } + private: + ManagedRoute(const ManagedRoute&) + { + } + inline ManagedRoute& operator=(const ManagedRoute&) + { + return *this; + } - InetAddress _target; - InetAddress _via; - InetAddress _src; - InetAddress _systemVia; // for route overrides - std::map _applied; // routes currently applied - char _device[128]; - char _systemDevice[128]; // for route overrides + InetAddress _target; + InetAddress _via; + InetAddress _src; + InetAddress _systemVia; // for route overrides + std::map _applied; // routes currently applied + char _device[128]; + char _systemDevice[128]; // for route overrides - AtomicCounter __refCount; + AtomicCounter __refCount; }; -} // namespace ZeroTier +} // namespace ZeroTier #endif diff --git a/osdep/NeighborDiscovery.cpp b/osdep/NeighborDiscovery.cpp index 5e03282d..457e161f 100644 --- a/osdep/NeighborDiscovery.cpp +++ b/osdep/NeighborDiscovery.cpp @@ -12,15 +12,15 @@ /****/ #include "NeighborDiscovery.hpp" -#include "OSUtils.hpp" #include "../include/ZeroTierOne.h" +#include "OSUtils.hpp" #include namespace ZeroTier { -uint16_t calc_checksum (uint16_t *addr, int len) +uint16_t calc_checksum(uint16_t* addr, int len) { int count = len; uint32_t sum = 0; @@ -34,7 +34,7 @@ uint16_t calc_checksum (uint16_t *addr, int len) // Add left-over byte, if any. if (count > 0) { - sum += *(uint8_t *) addr; + sum += *(uint8_t*)addr; } // Fold 32-bit sum into 16 bits; we lose information by doing this, @@ -55,13 +55,11 @@ struct _pseudo_header { uint8_t targetAddr[16]; uint32_t length; uint8_t zeros[3]; - uint8_t next; // 58 + uint8_t next; // 58 }; struct _option { - _option(int optionType) - : type(optionType) - , length(8) + _option(int optionType) : type(optionType), length(8) { memset(mac, 0, sizeof(mac)); } @@ -72,21 +70,18 @@ struct _option { }; struct _neighbor_solicitation { - _neighbor_solicitation() - : type(135) - , code(0) - , checksum(0) - , option(1) + _neighbor_solicitation() : type(135), code(0), checksum(0), option(1) { memset(&reserved, 0, sizeof(reserved)); memset(target, 0, sizeof(target)); } - void calculateChecksum(const sockaddr_storage &sourceIp, const sockaddr_storage &destIp) { + void calculateChecksum(const sockaddr_storage& sourceIp, const sockaddr_storage& destIp) + { _pseudo_header ph; memset(&ph, 0, sizeof(_pseudo_header)); - const sockaddr_in6 *src = (const sockaddr_in6*)&sourceIp; - const sockaddr_in6 *dest = (const sockaddr_in6*)&destIp; + const sockaddr_in6* src = (const sockaddr_in6*)&sourceIp; + const sockaddr_in6* dest = (const sockaddr_in6*)&destIp; memcpy(ph.sourceAddr, &src->sin6_addr, sizeof(struct in6_addr)); memcpy(ph.targetAddr, &dest->sin6_addr, sizeof(struct in6_addr)); @@ -94,9 +89,9 @@ struct _neighbor_solicitation { ph.length = htonl(sizeof(_neighbor_solicitation)); size_t len = sizeof(_pseudo_header) + sizeof(_neighbor_solicitation); - uint8_t *tmp = (uint8_t*)malloc(len); + uint8_t* tmp = (uint8_t*)malloc(len); memcpy(tmp, &ph, sizeof(_pseudo_header)); - memcpy(tmp+sizeof(_pseudo_header), this, sizeof(_neighbor_solicitation)); + memcpy(tmp + sizeof(_pseudo_header), this, sizeof(_neighbor_solicitation)); checksum = calc_checksum((uint16_t*)tmp, (int)len); @@ -104,8 +99,8 @@ struct _neighbor_solicitation { tmp = NULL; } - uint8_t type; // 135 - uint8_t code; // 0 + uint8_t type; // 135 + uint8_t code; // 0 uint16_t checksum; uint32_t reserved; uint8_t target[16]; @@ -113,22 +108,18 @@ struct _neighbor_solicitation { }; struct _neighbor_advertisement { - _neighbor_advertisement() - : type(136) - , code(0) - , checksum(0) - , rso(0x40) - , option(2) + _neighbor_advertisement() : type(136), code(0), checksum(0), rso(0x40), option(2) { memset(padding, 0, sizeof(padding)); memset(target, 0, sizeof(target)); } - void calculateChecksum(const sockaddr_storage &sourceIp, const sockaddr_storage &destIp) { + void calculateChecksum(const sockaddr_storage& sourceIp, const sockaddr_storage& destIp) + { _pseudo_header ph; memset(&ph, 0, sizeof(_pseudo_header)); - const sockaddr_in6 *src = (const sockaddr_in6*)&sourceIp; - const sockaddr_in6 *dest = (const sockaddr_in6*)&destIp; + const sockaddr_in6* src = (const sockaddr_in6*)&sourceIp; + const sockaddr_in6* dest = (const sockaddr_in6*)&destIp; memcpy(ph.sourceAddr, &src->sin6_addr, sizeof(struct in6_addr)); memcpy(ph.targetAddr, &dest->sin6_addr, sizeof(struct in6_addr)); @@ -136,9 +127,9 @@ struct _neighbor_advertisement { ph.length = htonl(sizeof(_neighbor_advertisement)); size_t len = sizeof(_pseudo_header) + sizeof(_neighbor_advertisement); - uint8_t *tmp = (uint8_t*)malloc(len); + uint8_t* tmp = (uint8_t*)malloc(len); memcpy(tmp, &ph, sizeof(_pseudo_header)); - memcpy(tmp+sizeof(_pseudo_header), this, sizeof(_neighbor_advertisement)); + memcpy(tmp + sizeof(_pseudo_header), this, sizeof(_neighbor_advertisement)); checksum = calc_checksum((uint16_t*)tmp, (int)len); @@ -146,8 +137,8 @@ struct _neighbor_advertisement { tmp = NULL; } - uint8_t type; // 136 - uint8_t code; // 0 + uint8_t type; // 136 + uint8_t code; // 0 uint16_t checksum; uint8_t rso; uint8_t padding[3]; @@ -155,39 +146,38 @@ struct _neighbor_advertisement { _option option; }; -NeighborDiscovery::NeighborDiscovery() - : _cache(256) - , _lastCleaned(OSUtils::now()) -{} - -void NeighborDiscovery::addLocal(const sockaddr_storage &address, const MAC &mac) +NeighborDiscovery::NeighborDiscovery() : _cache(256), _lastCleaned(OSUtils::now()) { - _NDEntry &e = _cache[InetAddress(address)]; +} + +void NeighborDiscovery::addLocal(const sockaddr_storage& address, const MAC& mac) +{ + _NDEntry& e = _cache[InetAddress(address)]; e.lastQuerySent = 0; e.lastResponseReceived = 0; e.mac = mac; e.local = true; } -void NeighborDiscovery::remove(const sockaddr_storage &address) +void NeighborDiscovery::remove(const sockaddr_storage& address) { _cache.erase(InetAddress(address)); } -sockaddr_storage NeighborDiscovery::processIncomingND(const uint8_t *nd, unsigned int len, const sockaddr_storage &localIp, uint8_t *response, unsigned int &responseLen, MAC &responseDest) +sockaddr_storage NeighborDiscovery::processIncomingND(const uint8_t* nd, unsigned int len, const sockaddr_storage& localIp, uint8_t* response, unsigned int& responseLen, MAC& responseDest) { assert(sizeof(_neighbor_solicitation) == 28); assert(sizeof(_neighbor_advertisement) == 32); const uint64_t now = OSUtils::now(); - sockaddr_storage ip = {0}; + sockaddr_storage ip = { 0 }; if (len >= sizeof(_neighbor_solicitation) && nd[0] == 0x87) { // respond to Neighbor Solicitation request for local address _neighbor_solicitation solicitation; memcpy(&solicitation, nd, len); InetAddress targetAddress(solicitation.target, 16, 0); - _NDEntry *targetEntry = _cache.get(targetAddress); + _NDEntry* targetEntry = _cache.get(targetAddress); if (targetEntry && targetEntry->local) { _neighbor_advertisement adv; targetEntry->mac.copyTo(adv.option.mac, 6); @@ -197,12 +187,13 @@ sockaddr_storage NeighborDiscovery::processIncomingND(const uint8_t *nd, unsigne responseLen = sizeof(_neighbor_advertisement); responseDest.setTo(solicitation.option.mac, 6); } - } else if (len >= sizeof(_neighbor_advertisement) && nd[0] == 0x88) { + } + else if (len >= sizeof(_neighbor_advertisement) && nd[0] == 0x88) { _neighbor_advertisement adv; memcpy(&adv, nd, len); InetAddress responseAddress(adv.target, 16, 0); - _NDEntry *queryEntry = _cache.get(responseAddress); - if(queryEntry && !queryEntry->local && (now - queryEntry->lastQuerySent <= ZT_ND_QUERY_MAX_TTL)) { + _NDEntry* queryEntry = _cache.get(responseAddress); + if (queryEntry && ! queryEntry->local && (now - queryEntry->lastQuerySent <= ZT_ND_QUERY_MAX_TTL)) { queryEntry->lastResponseReceived = now; queryEntry->mac.setTo(adv.option.mac, 6); ip = responseAddress; @@ -212,10 +203,10 @@ sockaddr_storage NeighborDiscovery::processIncomingND(const uint8_t *nd, unsigne if ((now - _lastCleaned) >= ZT_ND_EXPIRE) { _lastCleaned = now; Hashtable::Iterator i(_cache); - InetAddress *k = NULL; - _NDEntry *v = NULL; + InetAddress* k = NULL; + _NDEntry* v = NULL; while (i.next(k, v)) { - if(!v->local && (now - v->lastResponseReceived) >= ZT_ND_EXPIRE) { + if (! v->local && (now - v->lastResponseReceived) >= ZT_ND_EXPIRE) { _cache.erase(*k); } } @@ -224,7 +215,7 @@ sockaddr_storage NeighborDiscovery::processIncomingND(const uint8_t *nd, unsigne return ip; } -MAC NeighborDiscovery::query(const MAC &localMac, const sockaddr_storage &localIp, const sockaddr_storage &targetIp, uint8_t *query, unsigned int &queryLen, MAC &queryDest) +MAC NeighborDiscovery::query(const MAC& localMac, const sockaddr_storage& localIp, const sockaddr_storage& targetIp, uint8_t* query, unsigned int& queryLen, MAC& queryDest) { const uint64_t now = OSUtils::now(); @@ -233,10 +224,9 @@ MAC NeighborDiscovery::query(const MAC &localMac, const sockaddr_storage &localI InetAddress targetAddress(targetIp); targetAddress.setPort(0); - _NDEntry &e = _cache[targetAddress]; + _NDEntry& e = _cache[targetAddress]; - if ( (e.mac && ((now - e.lastResponseReceived) >= (ZT_ND_EXPIRE / 3))) || - (!e.mac && ((now - e.lastQuerySent) >= ZT_ND_QUERY_INTERVAL))) { + if ((e.mac && ((now - e.lastResponseReceived) >= (ZT_ND_EXPIRE / 3))) || (! e.mac && ((now - e.lastQuerySent) >= ZT_ND_QUERY_INTERVAL))) { e.lastQuerySent = now; _neighbor_solicitation ns; @@ -245,10 +235,12 @@ MAC NeighborDiscovery::query(const MAC &localMac, const sockaddr_storage &localI ns.calculateChecksum(localIp, targetIp); if (e.mac) { queryDest = e.mac; - } else { + } + else { queryDest = (uint64_t)0xffffffffffffULL; } - } else { + } + else { queryLen = 0; queryDest.zero(); } @@ -256,4 +248,4 @@ MAC NeighborDiscovery::query(const MAC &localMac, const sockaddr_storage &localI return e.mac; } -} +} // namespace ZeroTier diff --git a/osdep/NeighborDiscovery.hpp b/osdep/NeighborDiscovery.hpp index b25dafb9..0d92b817 100644 --- a/osdep/NeighborDiscovery.hpp +++ b/osdep/NeighborDiscovery.hpp @@ -15,9 +15,8 @@ #define ZT_NEIGHBORDISCOVERY_HPP #include "../node/Hashtable.hpp" -#include "../node/MAC.hpp" #include "../node/InetAddress.hpp" - +#include "../node/MAC.hpp" #define ZT_ND_QUERY_INTERVAL 2000 @@ -25,12 +24,10 @@ #define ZT_ND_EXPIRE 600000 - namespace ZeroTier { -class NeighborDiscovery -{ -public: +class NeighborDiscovery { + public: NeighborDiscovery(); /** @@ -39,23 +36,24 @@ public: * @param mac Our local MAC address * @param ip Our IPv6 address */ - void addLocal(const sockaddr_storage &address, const MAC &mac); + void addLocal(const sockaddr_storage& address, const MAC& mac); /** * Delete a local IP entry or cached Neighbor entry * * @param address IPv6 address to remove */ - void remove(const sockaddr_storage &address); + void remove(const sockaddr_storage& address); - sockaddr_storage processIncomingND(const uint8_t *nd, unsigned int len, const sockaddr_storage &localIp, uint8_t *response, unsigned int &responseLen, MAC &responseDest); + sockaddr_storage processIncomingND(const uint8_t* nd, unsigned int len, const sockaddr_storage& localIp, uint8_t* response, unsigned int& responseLen, MAC& responseDest); - MAC query(const MAC &localMac, const sockaddr_storage &localIp, const sockaddr_storage &targetIp, uint8_t *query, unsigned int &queryLen, MAC &queryDest); + MAC query(const MAC& localMac, const sockaddr_storage& localIp, const sockaddr_storage& targetIp, uint8_t* query, unsigned int& queryLen, MAC& queryDest); -private: - struct _NDEntry - { - _NDEntry() : lastQuerySent(0), lastResponseReceived(0), mac(), local(false) {} + private: + struct _NDEntry { + _NDEntry() : lastQuerySent(0), lastResponseReceived(0), mac(), local(false) + { + } uint64_t lastQuerySent; uint64_t lastResponseReceived; MAC mac; @@ -66,6 +64,6 @@ private: uint64_t _lastCleaned; }; -} // namespace ZeroTier +} // namespace ZeroTier #endif diff --git a/osdep/NetBSDEthernetTap.cpp b/osdep/NetBSDEthernetTap.cpp index 5627f5f1..7362db68 100644 --- a/osdep/NetBSDEthernetTap.cpp +++ b/osdep/NetBSDEthernetTap.cpp @@ -11,469 +11,477 @@ */ /****/ -#include -#include -#include -#include -#include +#include "NetBSDEthernetTap.hpp" -#include -#include +#include "../node/Constants.hpp" +#include "../node/Mutex.hpp" +#include "../node/Utils.hpp" +#include "OSUtils.hpp" +#include "freebsd_getifmaddrs.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include #include -#include +#include +#include #include +#include +#include +#include #include #include #include #include - -#include - -#include "freebsd_getifmaddrs.h" - -#include -#include +#include #include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include - -#include "../node/Constants.hpp" -#include "../node/Utils.hpp" -#include "../node/Mutex.hpp" -#include "OSUtils.hpp" -#include "NetBSDEthernetTap.hpp" - -#include using namespace std; #define ZT_BASE32_CHARS "0123456789abcdefghijklmnopqrstuv" // ff:ff:ff:ff:ff:ff with no ADI -static const ZeroTier::MulticastGroup _blindWildcardMulticastGroup(ZeroTier::MAC(0xff),0); +static const ZeroTier::MulticastGroup _blindWildcardMulticastGroup(ZeroTier::MAC(0xff), 0); namespace ZeroTier { NetBSDEthernetTap::NetBSDEthernetTap( - const char *homePath, - const MAC &mac, - unsigned int mtu, - unsigned int metric, - uint64_t nwid, - const char *friendlyName, - void (*handler)(void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int), - void *arg) : - _handler(handler), - _arg(arg), - _nwid(nwid), - _mtu(mtu), - _metric(metric), - _fd(0), - _enabled(true) + const char* homePath, + const MAC& mac, + unsigned int mtu, + unsigned int metric, + uint64_t nwid, + const char* friendlyName, + void (*handler)(void*, uint64_t, const MAC&, const MAC&, unsigned int, unsigned int, const void*, unsigned int), + void* arg) + : _handler(handler) + , _arg(arg) + , _nwid(nwid) + , _mtu(mtu) + , _metric(metric) + , _fd(0) + , _enabled(true) { - static Mutex globalTapCreateLock; - char devpath[64],ethaddr[64],mtustr[32],metstr[32],tmpdevname[32]; - struct stat stattmp; + static Mutex globalTapCreateLock; + char devpath[64], ethaddr[64], mtustr[32], metstr[32], tmpdevname[32]; + struct stat stattmp; - Mutex::Lock _gl(globalTapCreateLock); + Mutex::Lock _gl(globalTapCreateLock); - if (mtu > 2800) - throw std::runtime_error("max tap MTU is 2800"); + if (mtu > 2800) + throw std::runtime_error("max tap MTU is 2800"); - // we can create /dev/tap* - std::vector devFiles(OSUtils::listDirectory("/dev")); - for(int i=9993;i<(9993+128);++i) { - Utils::snprintf(tmpdevname,sizeof(tmpdevname),"tap%d",i); - Utils::snprintf(devpath,sizeof(devpath),"/dev/%s",tmpdevname); - if (std::find(devFiles.begin(),devFiles.end(),std::string(tmpdevname)) == devFiles.end()) { - long cpid = (long)vfork(); - if (cpid == 0) { - ::execl("/sbin/ifconfig","/sbin/ifconfig",tmpdevname,"create",(const char *)0); - ::_exit(-1); - } else if (cpid > 0) { - int exitcode = -1; - ::waitpid(cpid,&exitcode,0); - } else throw std::runtime_error("fork() failed"); + // we can create /dev/tap* + std::vector devFiles(OSUtils::listDirectory("/dev")); + for (int i = 9993; i < (9993 + 128); ++i) { + Utils::snprintf(tmpdevname, sizeof(tmpdevname), "tap%d", i); + Utils::snprintf(devpath, sizeof(devpath), "/dev/%s", tmpdevname); + if (std::find(devFiles.begin(), devFiles.end(), std::string(tmpdevname)) == devFiles.end()) { + long cpid = (long)vfork(); + if (cpid == 0) { + ::execl("/sbin/ifconfig", "/sbin/ifconfig", tmpdevname, "create", (const char*)0); + ::_exit(-1); + } + else if (cpid > 0) { + int exitcode = -1; + ::waitpid(cpid, &exitcode, 0); + } + else + throw std::runtime_error("fork() failed"); - cpid = (long)vfork(); - if (cpid == 0) { - string tmp; - sprintf((char*)tmp.c_str(), "%d", i); - string minor = tmp.c_str(); - ::execl("/sbin/mknod","/sbin/mknod",devpath,"c","169",minor.c_str(),(const char *)0); - // http://ftp.netbsd.org/pub/NetBSD/NetBSD-current/src/sys/conf/majors - // major 169 => tap - ::_exit(-1); - } else if (cpid > 0) { - int exitcode = -1; - ::waitpid(cpid,&exitcode,0); - } else throw std::runtime_error("fork() failed"); + cpid = (long)vfork(); + if (cpid == 0) { + string tmp; + sprintf((char*)tmp.c_str(), "%d", i); + string minor = tmp.c_str(); + ::execl("/sbin/mknod", "/sbin/mknod", devpath, "c", "169", minor.c_str(), (const char*)0); + // http://ftp.netbsd.org/pub/NetBSD/NetBSD-current/src/sys/conf/majors + // major 169 => tap + ::_exit(-1); + } + else if (cpid > 0) { + int exitcode = -1; + ::waitpid(cpid, &exitcode, 0); + } + else + throw std::runtime_error("fork() failed"); - cerr<<"created device "< 0) - break; - else - throw std::runtime_error("unable to open created tap device "); - } else { - throw std::runtime_error("cannot find /dev node for newly created tap device"); - } - } - } + _dev = tmpdevname; + _fd = ::open(devpath, O_RDWR); + if (! stat(devpath, &stattmp)) { + if (_fd > 0) + break; + else + throw std::runtime_error("unable to open created tap device "); + } + else { + throw std::runtime_error("cannot find /dev node for newly created tap device"); + } + } + } - if (_fd <= 0) - throw std::runtime_error("unable to open TAP device or no more devices available"); + if (_fd <= 0) + throw std::runtime_error("unable to open TAP device or no more devices available"); - if (fcntl(_fd,F_SETFL,fcntl(_fd,F_GETFL) & ~O_NONBLOCK) == -1) { - ::close(_fd); - throw std::runtime_error("unable to set flags on file descriptor for TAP device"); - } + if (fcntl(_fd, F_SETFL, fcntl(_fd, F_GETFL) & ~O_NONBLOCK) == -1) { + ::close(_fd); + throw std::runtime_error("unable to set flags on file descriptor for TAP device"); + } - // Configure MAC address and MTU, bring interface up - Utils::snprintf(ethaddr,sizeof(ethaddr),"%.2x:%.2x:%.2x:%.2x:%.2x:%.2x",(int)mac[0],(int)mac[1],(int)mac[2],(int)mac[3],(int)mac[4],(int)mac[5]); - Utils::snprintf(mtustr,sizeof(mtustr),"%u",_mtu); - Utils::snprintf(metstr,sizeof(metstr),"%u",_metric); - long cpid = (long)vfork(); - if (cpid == 0) { - ::execl("/sbin/ifconfig","/sbin/ifconfig",_dev.c_str(),"link",ethaddr,"mtu",mtustr,"metric",metstr,"up",(const char *)0); - ::_exit(-1); - } else if (cpid > 0) { - int exitcode = -1; - ::waitpid(cpid,&exitcode,0); - if (exitcode) { - ::close(_fd); - throw std::runtime_error("ifconfig failure setting link-layer address and activating tap interface"); - } - } + // Configure MAC address and MTU, bring interface up + Utils::snprintf(ethaddr, sizeof(ethaddr), "%.2x:%.2x:%.2x:%.2x:%.2x:%.2x", (int)mac[0], (int)mac[1], (int)mac[2], (int)mac[3], (int)mac[4], (int)mac[5]); + Utils::snprintf(mtustr, sizeof(mtustr), "%u", _mtu); + Utils::snprintf(metstr, sizeof(metstr), "%u", _metric); + long cpid = (long)vfork(); + if (cpid == 0) { + ::execl("/sbin/ifconfig", "/sbin/ifconfig", _dev.c_str(), "link", ethaddr, "mtu", mtustr, "metric", metstr, "up", (const char*)0); + ::_exit(-1); + } + else if (cpid > 0) { + int exitcode = -1; + ::waitpid(cpid, &exitcode, 0); + if (exitcode) { + ::close(_fd); + throw std::runtime_error("ifconfig failure setting link-layer address and activating tap interface"); + } + } - // ifconfig link seems to be different from address - // https://wiki.netbsd.org/tutorials/faking_a_mac_address/ - cpid = (long)vfork(); - if (cpid == 0) { - string cmdline = "net.link.tap."+string(_dev); - cmdline += "="+string(ethaddr); - ::execl("/sbin/sysctl","/sbin/sysctl","-w",cmdline.c_str(),(const char *)0); - ::_exit(-1); - } else if (cpid > 0) { - int exitcode = -1; - ::waitpid(cpid,&exitcode,0); - if (exitcode) { - ::close(_fd); - throw std::runtime_error("sysctl failure setting link-layer address and activating tap interface"); - } - } + // ifconfig link seems to be different from address + // https://wiki.netbsd.org/tutorials/faking_a_mac_address/ + cpid = (long)vfork(); + if (cpid == 0) { + string cmdline = "net.link.tap." + string(_dev); + cmdline += "=" + string(ethaddr); + ::execl("/sbin/sysctl", "/sbin/sysctl", "-w", cmdline.c_str(), (const char*)0); + ::_exit(-1); + } + else if (cpid > 0) { + int exitcode = -1; + ::waitpid(cpid, &exitcode, 0); + if (exitcode) { + ::close(_fd); + throw std::runtime_error("sysctl failure setting link-layer address and activating tap interface"); + } + } - // Set close-on-exec so that devices cannot persist if we fork/exec for update - fcntl(_fd,F_SETFD,fcntl(_fd,F_GETFD) | FD_CLOEXEC); + // Set close-on-exec so that devices cannot persist if we fork/exec for update + fcntl(_fd, F_SETFD, fcntl(_fd, F_GETFD) | FD_CLOEXEC); - ::pipe(_shutdownSignalPipe); - - _thread = Thread::start(this); + ::pipe(_shutdownSignalPipe); + _thread = Thread::start(this); } NetBSDEthernetTap::~NetBSDEthernetTap() { - ::write(_shutdownSignalPipe[1],"\0",1); // causes thread to exit - Thread::join(_thread); - ::close(_fd); - ::close(_shutdownSignalPipe[0]); - ::close(_shutdownSignalPipe[1]); + ::write(_shutdownSignalPipe[1], "\0", 1); // causes thread to exit + Thread::join(_thread); + ::close(_fd); + ::close(_shutdownSignalPipe[0]); + ::close(_shutdownSignalPipe[1]); - long cpid = (long)vfork(); - if (cpid == 0) { - ::execl("/sbin/ifconfig","/sbin/ifconfig",_dev.c_str(),"destroy",(const char *)0); - ::_exit(-1); - } else if (cpid > 0) { - int exitcode = -1; - ::waitpid(cpid,&exitcode,0); - } + long cpid = (long)vfork(); + if (cpid == 0) { + ::execl("/sbin/ifconfig", "/sbin/ifconfig", _dev.c_str(), "destroy", (const char*)0); + ::_exit(-1); + } + else if (cpid > 0) { + int exitcode = -1; + ::waitpid(cpid, &exitcode, 0); + } - cpid = (long)vfork(); - if (cpid == 0) { - string tmp="/dev/"; - tmp+=_dev.c_str(); - ::execl("/bin/rm","/bin/rm",tmp.c_str(),(const char *)0); - ::_exit(-1); - } else if (cpid > 0) { - int exitcode = -1; - ::waitpid(cpid,&exitcode,0); - } else throw std::runtime_error("fork() failed"); + cpid = (long)vfork(); + if (cpid == 0) { + string tmp = "/dev/"; + tmp += _dev.c_str(); + ::execl("/bin/rm", "/bin/rm", tmp.c_str(), (const char*)0); + ::_exit(-1); + } + else if (cpid > 0) { + int exitcode = -1; + ::waitpid(cpid, &exitcode, 0); + } + else + throw std::runtime_error("fork() failed"); } void NetBSDEthernetTap::setEnabled(bool en) { - _enabled = en; + _enabled = en; } bool NetBSDEthernetTap::enabled() const { - return _enabled; + return _enabled; } -static bool ___removeIp(const std::string &_dev,const InetAddress &ip) +static bool ___removeIp(const std::string& _dev, const InetAddress& ip) { - long cpid = (long)vfork(); - if (cpid == 0) { - execl("/sbin/ifconfig","/sbin/ifconfig",_dev.c_str(),"inet",ip.toIpString().c_str(),"-alias",(const char *)0); - _exit(-1); - } else if (cpid > 0) { - int exitcode = -1; - waitpid(cpid,&exitcode,0); - return (exitcode == 0); - } - return false; // never reached, make compiler shut up about return value + long cpid = (long)vfork(); + if (cpid == 0) { + execl("/sbin/ifconfig", "/sbin/ifconfig", _dev.c_str(), "inet", ip.toIpString().c_str(), "-alias", (const char*)0); + _exit(-1); + } + else if (cpid > 0) { + int exitcode = -1; + waitpid(cpid, &exitcode, 0); + return (exitcode == 0); + } + return false; // never reached, make compiler shut up about return value } -bool NetBSDEthernetTap::addIp(const InetAddress &ip) +bool NetBSDEthernetTap::addIp(const InetAddress& ip) { - if (!ip) - return false; + if (! ip) + return false; - std::vector allIps(ips()); - if (std::find(allIps.begin(),allIps.end(),ip) != allIps.end()) - return true; // IP/netmask already assigned + std::vector allIps(ips()); + if (std::find(allIps.begin(), allIps.end(), ip) != allIps.end()) + return true; // IP/netmask already assigned - // Remove and reconfigure if address is the same but netmask is different - for(std::vector::iterator i(allIps.begin());i!=allIps.end();++i) { - if ((i->ipsEqual(ip))&&(i->netmaskBits() != ip.netmaskBits())) { - if (___removeIp(_dev,*i)) - break; - } - } + // Remove and reconfigure if address is the same but netmask is different + for (std::vector::iterator i(allIps.begin()); i != allIps.end(); ++i) { + if ((i->ipsEqual(ip)) && (i->netmaskBits() != ip.netmaskBits())) { + if (___removeIp(_dev, *i)) + break; + } + } - long cpid = (long)vfork(); - if (cpid == 0) { - ::execl("/sbin/ifconfig","/sbin/ifconfig",_dev.c_str(),ip.isV4() ? "inet" : "inet6",ip.toString().c_str(),"alias",(const char *)0); - ::_exit(-1); - } else if (cpid > 0) { - int exitcode = -1; - ::waitpid(cpid,&exitcode,0); - return (exitcode == 0); - } - return false; + long cpid = (long)vfork(); + if (cpid == 0) { + ::execl("/sbin/ifconfig", "/sbin/ifconfig", _dev.c_str(), ip.isV4() ? "inet" : "inet6", ip.toString().c_str(), "alias", (const char*)0); + ::_exit(-1); + } + else if (cpid > 0) { + int exitcode = -1; + ::waitpid(cpid, &exitcode, 0); + return (exitcode == 0); + } + return false; } -bool NetBSDEthernetTap::removeIp(const InetAddress &ip) +bool NetBSDEthernetTap::removeIp(const InetAddress& ip) { - if (!ip) - return false; - std::vector allIps(ips()); - if (std::find(allIps.begin(),allIps.end(),ip) != allIps.end()) { - if (___removeIp(_dev,ip)) - return true; - } - return false; + if (! ip) + return false; + std::vector allIps(ips()); + if (std::find(allIps.begin(), allIps.end(), ip) != allIps.end()) { + if (___removeIp(_dev, ip)) + return true; + } + return false; } std::vector NetBSDEthernetTap::ips() const { - struct ifaddrs *ifa = (struct ifaddrs *)0; - if (getifaddrs(&ifa)) - return std::vector(); + struct ifaddrs* ifa = (struct ifaddrs*)0; + if (getifaddrs(&ifa)) + return std::vector(); - std::vector r; + std::vector r; - struct ifaddrs *p = ifa; - while (p) { - if ((!strcmp(p->ifa_name,_dev.c_str()))&&(p->ifa_addr)&&(p->ifa_netmask)&&(p->ifa_addr->sa_family == p->ifa_netmask->sa_family)) { - switch(p->ifa_addr->sa_family) { - case AF_INET: { - struct sockaddr_in *sin = (struct sockaddr_in *)p->ifa_addr; - struct sockaddr_in *nm = (struct sockaddr_in *)p->ifa_netmask; - r.push_back(InetAddress(&(sin->sin_addr.s_addr),4,Utils::countBits((uint32_t)nm->sin_addr.s_addr))); - } break; - case AF_INET6: { - struct sockaddr_in6 *sin = (struct sockaddr_in6 *)p->ifa_addr; - struct sockaddr_in6 *nm = (struct sockaddr_in6 *)p->ifa_netmask; - uint32_t b[4]; - memcpy(b,nm->sin6_addr.s6_addr,sizeof(b)); - r.push_back(InetAddress(sin->sin6_addr.s6_addr,16,Utils::countBits(b[0]) + Utils::countBits(b[1]) + Utils::countBits(b[2]) + Utils::countBits(b[3]))); - } break; - } - } - p = p->ifa_next; - } + struct ifaddrs* p = ifa; + while (p) { + if ((! strcmp(p->ifa_name, _dev.c_str())) && (p->ifa_addr) && (p->ifa_netmask) && (p->ifa_addr->sa_family == p->ifa_netmask->sa_family)) { + switch (p->ifa_addr->sa_family) { + case AF_INET: { + struct sockaddr_in* sin = (struct sockaddr_in*)p->ifa_addr; + struct sockaddr_in* nm = (struct sockaddr_in*)p->ifa_netmask; + r.push_back(InetAddress(&(sin->sin_addr.s_addr), 4, Utils::countBits((uint32_t)nm->sin_addr.s_addr))); + } break; + case AF_INET6: { + struct sockaddr_in6* sin = (struct sockaddr_in6*)p->ifa_addr; + struct sockaddr_in6* nm = (struct sockaddr_in6*)p->ifa_netmask; + uint32_t b[4]; + memcpy(b, nm->sin6_addr.s6_addr, sizeof(b)); + r.push_back(InetAddress(sin->sin6_addr.s6_addr, 16, Utils::countBits(b[0]) + Utils::countBits(b[1]) + Utils::countBits(b[2]) + Utils::countBits(b[3]))); + } break; + } + } + p = p->ifa_next; + } - if (ifa) - freeifaddrs(ifa); + if (ifa) + freeifaddrs(ifa); - std::sort(r.begin(),r.end()); - std::unique(r.begin(),r.end()); + std::sort(r.begin(), r.end()); + std::unique(r.begin(), r.end()); - return r; + return r; } -void NetBSDEthernetTap::put(const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len) +void NetBSDEthernetTap::put(const MAC& from, const MAC& to, unsigned int etherType, const void* data, unsigned int len) { - char putBuf[4096]; - if ((_fd > 0)&&(len <= _mtu)&&(_enabled)) { - to.copyTo(putBuf,6); - from.copyTo(putBuf + 6,6); - *((uint16_t *)(putBuf + 12)) = htons((uint16_t)etherType); - memcpy(putBuf + 14,data,len); - len += 14; - ::write(_fd,putBuf,len); - } + char putBuf[4096]; + if ((_fd > 0) && (len <= _mtu) && (_enabled)) { + to.copyTo(putBuf, 6); + from.copyTo(putBuf + 6, 6); + *((uint16_t*)(putBuf + 12)) = htons((uint16_t)etherType); + memcpy(putBuf + 14, data, len); + len += 14; + ::write(_fd, putBuf, len); + } } std::string NetBSDEthernetTap::deviceName() const { - return _dev; + return _dev; } -void NetBSDEthernetTap::setFriendlyName(const char *friendlyName) +void NetBSDEthernetTap::setFriendlyName(const char* friendlyName) { } -void NetBSDEthernetTap::scanMulticastGroups(std::vector &added,std::vector &removed) +void NetBSDEthernetTap::scanMulticastGroups(std::vector& added, std::vector& removed) { - std::vector newGroups; + std::vector newGroups; - struct ifmaddrs *ifmap = (struct ifmaddrs *)0; - if (!getifmaddrs(&ifmap)) { - struct ifmaddrs *p = ifmap; - while (p) { - if (p->ifma_addr->sa_family == AF_LINK) { - struct sockaddr_dl *in = (struct sockaddr_dl *)p->ifma_name; - struct sockaddr_dl *la = (struct sockaddr_dl *)p->ifma_addr; - if ((la->sdl_alen == 6)&&(in->sdl_nlen <= _dev.length())&&(!memcmp(_dev.data(),in->sdl_data,in->sdl_nlen))) - newGroups.push_back(MulticastGroup(MAC(la->sdl_data + la->sdl_nlen,6),0)); - } - p = p->ifma_next; - } - freeifmaddrs(ifmap); - } + struct ifmaddrs* ifmap = (struct ifmaddrs*)0; + if (! getifmaddrs(&ifmap)) { + struct ifmaddrs* p = ifmap; + while (p) { + if (p->ifma_addr->sa_family == AF_LINK) { + struct sockaddr_dl* in = (struct sockaddr_dl*)p->ifma_name; + struct sockaddr_dl* la = (struct sockaddr_dl*)p->ifma_addr; + if ((la->sdl_alen == 6) && (in->sdl_nlen <= _dev.length()) && (! memcmp(_dev.data(), in->sdl_data, in->sdl_nlen))) + newGroups.push_back(MulticastGroup(MAC(la->sdl_data + la->sdl_nlen, 6), 0)); + } + p = p->ifma_next; + } + freeifmaddrs(ifmap); + } - std::vector allIps(ips()); - for(std::vector::iterator ip(allIps.begin());ip!=allIps.end();++ip) - newGroups.push_back(MulticastGroup::deriveMulticastGroupForAddressResolution(*ip)); + std::vector allIps(ips()); + for (std::vector::iterator ip(allIps.begin()); ip != allIps.end(); ++ip) + newGroups.push_back(MulticastGroup::deriveMulticastGroupForAddressResolution(*ip)); - std::sort(newGroups.begin(),newGroups.end()); - std::unique(newGroups.begin(),newGroups.end()); + std::sort(newGroups.begin(), newGroups.end()); + std::unique(newGroups.begin(), newGroups.end()); - for(std::vector::iterator m(newGroups.begin());m!=newGroups.end();++m) { - if (!std::binary_search(_multicastGroups.begin(),_multicastGroups.end(),*m)) - added.push_back(*m); - } - for(std::vector::iterator m(_multicastGroups.begin());m!=_multicastGroups.end();++m) { - if (!std::binary_search(newGroups.begin(),newGroups.end(),*m)) - removed.push_back(*m); - } + for (std::vector::iterator m(newGroups.begin()); m != newGroups.end(); ++m) { + if (! std::binary_search(_multicastGroups.begin(), _multicastGroups.end(), *m)) + added.push_back(*m); + } + for (std::vector::iterator m(_multicastGroups.begin()); m != _multicastGroups.end(); ++m) { + if (! std::binary_search(newGroups.begin(), newGroups.end(), *m)) + removed.push_back(*m); + } - _multicastGroups.swap(newGroups); + _multicastGroups.swap(newGroups); } /* bool NetBSDEthernetTap::updateMulticastGroups(std::set &groups) { - std::set newGroups; - struct ifmaddrs *ifmap = (struct ifmaddrs *)0; - if (!getifmaddrs(&ifmap)) { - struct ifmaddrs *p = ifmap; - while (p) { - if (p->ifma_addr->sa_family == AF_LINK) { - struct sockaddr_dl *in = (struct sockaddr_dl *)p->ifma_name; - struct sockaddr_dl *la = (struct sockaddr_dl *)p->ifma_addr; - if ((la->sdl_alen == 6)&&(in->sdl_nlen <= _dev.length())&&(!memcmp(_dev.data(),in->sdl_data,in->sdl_nlen))) - newGroups.insert(MulticastGroup(MAC(la->sdl_data + la->sdl_nlen,6),0)); - } - p = p->ifma_next; - } - freeifmaddrs(ifmap); - } + std::set newGroups; + struct ifmaddrs *ifmap = (struct ifmaddrs *)0; + if (!getifmaddrs(&ifmap)) { + struct ifmaddrs *p = ifmap; + while (p) { + if (p->ifma_addr->sa_family == AF_LINK) { + struct sockaddr_dl *in = (struct sockaddr_dl *)p->ifma_name; + struct sockaddr_dl *la = (struct sockaddr_dl *)p->ifma_addr; + if ((la->sdl_alen == 6)&&(in->sdl_nlen <= _dev.length())&&(!memcmp(_dev.data(),in->sdl_data,in->sdl_nlen))) + newGroups.insert(MulticastGroup(MAC(la->sdl_data + la->sdl_nlen,6),0)); + } + p = p->ifma_next; + } + freeifmaddrs(ifmap); + } - { - std::set allIps(ips()); - for(std::set::const_iterator i(allIps.begin());i!=allIps.end();++i) - newGroups.insert(MulticastGroup::deriveMulticastGroupForAddressResolution(*i)); - } + { + std::set allIps(ips()); + for(std::set::const_iterator i(allIps.begin());i!=allIps.end();++i) + newGroups.insert(MulticastGroup::deriveMulticastGroupForAddressResolution(*i)); + } - bool changed = false; + bool changed = false; - for(std::set::iterator mg(newGroups.begin());mg!=newGroups.end();++mg) { - if (!groups.count(*mg)) { - groups.insert(*mg); - changed = true; - } - } - for(std::set::iterator mg(groups.begin());mg!=groups.end();) { - if ((!newGroups.count(*mg))&&(*mg != _blindWildcardMulticastGroup)) { - groups.erase(mg++); - changed = true; - } else ++mg; - } + for(std::set::iterator mg(newGroups.begin());mg!=newGroups.end();++mg) { + if (!groups.count(*mg)) { + groups.insert(*mg); + changed = true; + } + } + for(std::set::iterator mg(groups.begin());mg!=groups.end();) { + if ((!newGroups.count(*mg))&&(*mg != _blindWildcardMulticastGroup)) { + groups.erase(mg++); + changed = true; + } else ++mg; + } - return changed; + return changed; } */ -void NetBSDEthernetTap::threadMain() - throw() +void NetBSDEthernetTap::threadMain() throw() { - fd_set readfds,nullfds; - MAC to,from; - int n,nfds,r; - char getBuf[8194]; + fd_set readfds, nullfds; + MAC to, from; + int n, nfds, r; + char getBuf[8194]; - // Wait for a moment after startup -- wait for Network to finish - // constructing itself. - Thread::sleep(500); + // Wait for a moment after startup -- wait for Network to finish + // constructing itself. + Thread::sleep(500); - FD_ZERO(&readfds); - FD_ZERO(&nullfds); - nfds = (int)std::max(_shutdownSignalPipe[0],_fd) + 1; + FD_ZERO(&readfds); + FD_ZERO(&nullfds); + nfds = (int)std::max(_shutdownSignalPipe[0], _fd) + 1; - r = 0; - for(;;) { - FD_SET(_shutdownSignalPipe[0],&readfds); - FD_SET(_fd,&readfds); - select(nfds,&readfds,&nullfds,&nullfds,(struct timeval *)0); + r = 0; + for (;;) { + FD_SET(_shutdownSignalPipe[0], &readfds); + FD_SET(_fd, &readfds); + select(nfds, &readfds, &nullfds, &nullfds, (struct timeval*)0); - if (FD_ISSET(_shutdownSignalPipe[0],&readfds)) // writes to shutdown pipe terminate thread - break; + if (FD_ISSET(_shutdownSignalPipe[0], &readfds)) // writes to shutdown pipe terminate thread + break; - if (FD_ISSET(_fd,&readfds)) { - n = (int)::read(_fd,getBuf + r,sizeof(getBuf) - r); - if (n < 0) { - if ((errno != EINTR)&&(errno != ETIMEDOUT)) - break; - } else { - // Some tap drivers like to send the ethernet frame and the - // payload in two chunks, so handle that by accumulating - // data until we have at least a frame. - r += n; - if (r > 14) { - if (r > ((int)_mtu + 14)) // sanity check for weird TAP behavior on some platforms - r = _mtu + 14; + if (FD_ISSET(_fd, &readfds)) { + n = (int)::read(_fd, getBuf + r, sizeof(getBuf) - r); + if (n < 0) { + if ((errno != EINTR) && (errno != ETIMEDOUT)) + break; + } + else { + // Some tap drivers like to send the ethernet frame and the + // payload in two chunks, so handle that by accumulating + // data until we have at least a frame. + r += n; + if (r > 14) { + if (r > ((int)_mtu + 14)) // sanity check for weird TAP behavior on some platforms + r = _mtu + 14; - if (_enabled) { - to.setTo(getBuf,6); - from.setTo(getBuf + 6,6); - unsigned int etherType = ntohs(((const uint16_t *)getBuf)[6]); - // TODO: VLAN support - _handler(_arg,_nwid,from,to,etherType,0,(const void *)(getBuf + 14),r - 14); - } + if (_enabled) { + to.setTo(getBuf, 6); + from.setTo(getBuf + 6, 6); + unsigned int etherType = ntohs(((const uint16_t*)getBuf)[6]); + // TODO: VLAN support + _handler(_arg, _nwid, from, to, etherType, 0, (const void*)(getBuf + 14), r - 14); + } - r = 0; - } - } - } - } + r = 0; + } + } + } + } } -} // namespace ZeroTier +} // namespace ZeroTier diff --git a/osdep/NetBSDEthernetTap.hpp b/osdep/NetBSDEthernetTap.hpp index 1809d1f6..22c31801 100644 --- a/osdep/NetBSDEthernetTap.hpp +++ b/osdep/NetBSDEthernetTap.hpp @@ -14,64 +14,63 @@ #ifndef ZT_NetBSDEthernetTap_HPP #define ZT_NetBSDEthernetTap_HPP +#include "../node/Constants.hpp" +#include "../node/MAC.hpp" +#include "../node/MulticastGroup.hpp" +#include "EthernetTap.hpp" +#include "Thread.hpp" + +#include #include #include - #include #include -#include - -#include "../node/Constants.hpp" -#include "../node/MulticastGroup.hpp" -#include "../node/MAC.hpp" -#include "Thread.hpp" -#include "EthernetTap.hpp" namespace ZeroTier { -class NetBSDEthernetTap : public EthernetTap -{ -public: - NetBSDEthernetTap( - const char *homePath, - const MAC &mac, - unsigned int mtu, - unsigned int metric, - uint64_t nwid, - const char *friendlyName, - void (*handler)(void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int), - void *arg); +class NetBSDEthernetTap : public EthernetTap { + public: + NetBSDEthernetTap( + const char* homePath, + const MAC& mac, + unsigned int mtu, + unsigned int metric, + uint64_t nwid, + const char* friendlyName, + void (*handler)(void*, uint64_t, const MAC&, const MAC&, unsigned int, unsigned int, const void*, unsigned int), + void* arg); - virtual ~NetBSDEthernetTap(); + virtual ~NetBSDEthernetTap(); - virtual void setEnabled(bool en); - virtual bool enabled() const; - virtual bool addIp(const InetAddress &ip); - virtual bool removeIp(const InetAddress &ip); - virtual std::vector ips() const; - virtual void put(const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len); - virtual std::string deviceName() const; - virtual void setFriendlyName(const char *friendlyName); - virtual void scanMulticastGroups(std::vector &added,std::vector &removed); - virtual void setDns(const char *domain, const std::vector &servers) {} + virtual void setEnabled(bool en); + virtual bool enabled() const; + virtual bool addIp(const InetAddress& ip); + virtual bool removeIp(const InetAddress& ip); + virtual std::vector ips() const; + virtual void put(const MAC& from, const MAC& to, unsigned int etherType, const void* data, unsigned int len); + virtual std::string deviceName() const; + virtual void setFriendlyName(const char* friendlyName); + virtual void scanMulticastGroups(std::vector& added, std::vector& removed); + virtual void setDns(const char* domain, const std::vector& servers) + { + } - void threadMain() - throw(); + void threadMain() throw(); -private: - void (*_handler)(void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int); - void *_arg; - uint64_t _nwid; - Thread _thread; - std::string _dev; - std::vector _multicastGroups; - unsigned int _mtu; - unsigned int _metric; - int _fd; - int _shutdownSignalPipe[2]; - volatile bool _enabled; + private: + void (*_handler)(void*, uint64_t, const MAC&, const MAC&, unsigned int, unsigned int, const void*, unsigned int); + void* _arg; + uint64_t _nwid; + Thread _thread; + std::string _dev; + std::vector _multicastGroups; + unsigned int _mtu; + unsigned int _metric; + int _fd; + int _shutdownSignalPipe[2]; + volatile bool _enabled; }; -} // namespace ZeroTier +} // namespace ZeroTier #endif diff --git a/osdep/OSUtils.cpp b/osdep/OSUtils.cpp index e98a2c70..cede6537 100644 --- a/osdep/OSUtils.cpp +++ b/osdep/OSUtils.cpp @@ -11,35 +11,34 @@ */ /****/ -#include -#include -#include -#include -#include -#include -#include - #include "../node/Constants.hpp" #include "../node/Utils.hpp" +#include +#include +#include +#include +#include +#include + #ifdef __UNIX_LIKE__ -#include +#include #include #include -#include +#include #include #include +#include #include -#include -#include +#include #endif #ifdef __WINDOWS__ -#include -#include -#include -#include #include +#include +#include +#include +#include #endif #include "OSUtils.hpp" @@ -50,361 +49,377 @@ namespace ZeroTier { -unsigned int OSUtils::ztsnprintf(char *buf,unsigned int len,const char *fmt,...) +unsigned int OSUtils::ztsnprintf(char* buf, unsigned int len, const char* fmt, ...) { - va_list ap; + va_list ap; - va_start(ap,fmt); - int n = (int)vsnprintf(buf,len,fmt,ap); - va_end(ap); + va_start(ap, fmt); + int n = (int)vsnprintf(buf, len, fmt, ap); + va_end(ap); - if ((n >= (int)len)||(n < 0)) { - if (len) - buf[len - 1] = (char)0; - throw std::length_error("buf[] overflow"); - } + if ((n >= (int)len) || (n < 0)) { + if (len) + buf[len - 1] = (char)0; + throw std::length_error("buf[] overflow"); + } - return (unsigned int)n; + return (unsigned int)n; } -std::string OSUtils::networkIDStr(const uint64_t nwid) { - char tmp[32] = {}; - ztsnprintf(tmp, sizeof(tmp), "%.16" PRIx64, nwid); - return std::string(tmp); +std::string OSUtils::networkIDStr(const uint64_t nwid) +{ + char tmp[32] = {}; + ztsnprintf(tmp, sizeof(tmp), "%.16" PRIx64, nwid); + return std::string(tmp); } -std::string OSUtils::nodeIDStr(const uint64_t nid) { - char tmp[32] = {}; - ztsnprintf(tmp, sizeof(tmp), "%.10" PRIx64, nid); - return std::string(tmp); +std::string OSUtils::nodeIDStr(const uint64_t nid) +{ + char tmp[32] = {}; + ztsnprintf(tmp, sizeof(tmp), "%.10" PRIx64, nid); + return std::string(tmp); } #ifdef __UNIX_LIKE__ -bool OSUtils::redirectUnixOutputs(const char *stdoutPath,const char *stderrPath) - throw() +bool OSUtils::redirectUnixOutputs(const char* stdoutPath, const char* stderrPath) throw() { - int fdout = ::open(stdoutPath,O_WRONLY|O_CREAT,0600); - if (fdout > 0) { - int fderr; - if (stderrPath) { - fderr = ::open(stderrPath,O_WRONLY|O_CREAT,0600); - if (fderr <= 0) { - ::close(fdout); - return false; - } - } else fderr = fdout; - ::close(STDOUT_FILENO); - ::close(STDERR_FILENO); - ::dup2(fdout,STDOUT_FILENO); - ::dup2(fderr,STDERR_FILENO); - return true; - } - return false; + int fdout = ::open(stdoutPath, O_WRONLY | O_CREAT, 0600); + if (fdout > 0) { + int fderr; + if (stderrPath) { + fderr = ::open(stderrPath, O_WRONLY | O_CREAT, 0600); + if (fderr <= 0) { + ::close(fdout); + return false; + } + } + else + fderr = fdout; + ::close(STDOUT_FILENO); + ::close(STDERR_FILENO); + ::dup2(fdout, STDOUT_FILENO); + ::dup2(fderr, STDERR_FILENO); + return true; + } + return false; } -#endif // __UNIX_LIKE__ +#endif // __UNIX_LIKE__ -std::vector OSUtils::listDirectory(const char *path,bool includeDirectories) +std::vector OSUtils::listDirectory(const char* path, bool includeDirectories) { - std::vector r; + std::vector r; #ifdef __WINDOWS__ - HANDLE hFind; - WIN32_FIND_DATAA ffd; - if ((hFind = FindFirstFileA((std::string(path) + "\\*").c_str(),&ffd)) != INVALID_HANDLE_VALUE) { - do { - if ( (strcmp(ffd.cFileName,".")) && (strcmp(ffd.cFileName,"..")) && (((ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0)||(((ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0)&&(includeDirectories))) ) - r.push_back(std::string(ffd.cFileName)); - } while (FindNextFileA(hFind,&ffd)); - FindClose(hFind); - } + HANDLE hFind; + WIN32_FIND_DATAA ffd; + if ((hFind = FindFirstFileA((std::string(path) + "\\*").c_str(), &ffd)) != INVALID_HANDLE_VALUE) { + do { + if ((strcmp(ffd.cFileName, ".")) && (strcmp(ffd.cFileName, "..")) && (((ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0) || (((ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0) && (includeDirectories)))) + r.push_back(std::string(ffd.cFileName)); + } while (FindNextFileA(hFind, &ffd)); + FindClose(hFind); + } #else - struct dirent de; - struct dirent *dptr; - DIR *d = opendir(path); - if (!d) - return r; - dptr = (struct dirent *)0; - for(;;) { - if (readdir_r(d,&de,&dptr)) - break; - if (dptr) { - if ((strcmp(dptr->d_name,"."))&&(strcmp(dptr->d_name,".."))&&((dptr->d_type != DT_DIR)||(includeDirectories))) - r.push_back(std::string(dptr->d_name)); - } else break; - } - closedir(d); + struct dirent de; + struct dirent* dptr; + DIR* d = opendir(path); + if (! d) + return r; + dptr = (struct dirent*)0; + for (;;) { + if (readdir_r(d, &de, &dptr)) + break; + if (dptr) { + if ((strcmp(dptr->d_name, ".")) && (strcmp(dptr->d_name, "..")) && ((dptr->d_type != DT_DIR) || (includeDirectories))) + r.push_back(std::string(dptr->d_name)); + } + else + break; + } + closedir(d); #endif - return r; + return r; } -long OSUtils::cleanDirectory(const char *path,const int64_t olderThan) +long OSUtils::cleanDirectory(const char* path, const int64_t olderThan) { - long cleaned = 0; + long cleaned = 0; #ifdef __WINDOWS__ - HANDLE hFind; - WIN32_FIND_DATAA ffd; - LARGE_INTEGER date,adjust; - adjust.QuadPart = 11644473600000 * 10000; - char tmp[4096]; - if ((hFind = FindFirstFileA((std::string(path) + "\\*").c_str(),&ffd)) != INVALID_HANDLE_VALUE) { - do { - if ((strcmp(ffd.cFileName,"."))&&(strcmp(ffd.cFileName,".."))&&((ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0)) { - date.HighPart = ffd.ftLastWriteTime.dwHighDateTime; - date.LowPart = ffd.ftLastWriteTime.dwLowDateTime; - if (date.QuadPart > 0) { - date.QuadPart -= adjust.QuadPart; - if ((int64_t)((date.QuadPart / 10000000) * 1000) < olderThan) { - ztsnprintf(tmp, sizeof(tmp), "%s\\%s", path, ffd.cFileName); - if (DeleteFileA(tmp)) - ++cleaned; - } - } - } - } while (FindNextFileA(hFind,&ffd)); - FindClose(hFind); - } + HANDLE hFind; + WIN32_FIND_DATAA ffd; + LARGE_INTEGER date, adjust; + adjust.QuadPart = 11644473600000 * 10000; + char tmp[4096]; + if ((hFind = FindFirstFileA((std::string(path) + "\\*").c_str(), &ffd)) != INVALID_HANDLE_VALUE) { + do { + if ((strcmp(ffd.cFileName, ".")) && (strcmp(ffd.cFileName, "..")) && ((ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0)) { + date.HighPart = ffd.ftLastWriteTime.dwHighDateTime; + date.LowPart = ffd.ftLastWriteTime.dwLowDateTime; + if (date.QuadPart > 0) { + date.QuadPart -= adjust.QuadPart; + if ((int64_t)((date.QuadPart / 10000000) * 1000) < olderThan) { + ztsnprintf(tmp, sizeof(tmp), "%s\\%s", path, ffd.cFileName); + if (DeleteFileA(tmp)) + ++cleaned; + } + } + } + } while (FindNextFileA(hFind, &ffd)); + FindClose(hFind); + } #else - struct dirent de; - struct dirent *dptr; - struct stat st; - char tmp[4096]; - DIR *d = opendir(path); - if (!d) - return -1; - dptr = (struct dirent *)0; - for(;;) { - if (readdir_r(d,&de,&dptr)) - break; - if (dptr) { - if ((strcmp(dptr->d_name,"."))&&(strcmp(dptr->d_name,".."))&&(dptr->d_type == DT_REG)) { - ztsnprintf(tmp,sizeof(tmp),"%s/%s",path,dptr->d_name); - if (stat(tmp,&st) == 0) { - int64_t mt = (int64_t)(st.st_mtime); - if ((mt > 0)&&((mt * 1000) < olderThan)) { - if (unlink(tmp) == 0) - ++cleaned; - } - } - } - } else break; - } - closedir(d); + struct dirent de; + struct dirent* dptr; + struct stat st; + char tmp[4096]; + DIR* d = opendir(path); + if (! d) + return -1; + dptr = (struct dirent*)0; + for (;;) { + if (readdir_r(d, &de, &dptr)) + break; + if (dptr) { + if ((strcmp(dptr->d_name, ".")) && (strcmp(dptr->d_name, "..")) && (dptr->d_type == DT_REG)) { + ztsnprintf(tmp, sizeof(tmp), "%s/%s", path, dptr->d_name); + if (stat(tmp, &st) == 0) { + int64_t mt = (int64_t)(st.st_mtime); + if ((mt > 0) && ((mt * 1000) < olderThan)) { + if (unlink(tmp) == 0) + ++cleaned; + } + } + } + } + else + break; + } + closedir(d); #endif - return cleaned; + return cleaned; } -bool OSUtils::rmDashRf(const char *path) +bool OSUtils::rmDashRf(const char* path) { #ifdef __WINDOWS__ - HANDLE hFind; - WIN32_FIND_DATAA ffd; - if ((hFind = FindFirstFileA((std::string(path) + "\\*").c_str(),&ffd)) != INVALID_HANDLE_VALUE) { - do { - if ((strcmp(ffd.cFileName,".") != 0)&&(strcmp(ffd.cFileName,"..") != 0)) { - if ((ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0) { - if (DeleteFileA((std::string(path) + ZT_PATH_SEPARATOR_S + ffd.cFileName).c_str()) == FALSE) - return false; - } else { - if (!rmDashRf((std::string(path) + ZT_PATH_SEPARATOR_S + ffd.cFileName).c_str())) - return false; - } - } - } while (FindNextFileA(hFind,&ffd)); - FindClose(hFind); - } - return (RemoveDirectoryA(path) != FALSE); + HANDLE hFind; + WIN32_FIND_DATAA ffd; + if ((hFind = FindFirstFileA((std::string(path) + "\\*").c_str(), &ffd)) != INVALID_HANDLE_VALUE) { + do { + if ((strcmp(ffd.cFileName, ".") != 0) && (strcmp(ffd.cFileName, "..") != 0)) { + if ((ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0) { + if (DeleteFileA((std::string(path) + ZT_PATH_SEPARATOR_S + ffd.cFileName).c_str()) == FALSE) + return false; + } + else { + if (! rmDashRf((std::string(path) + ZT_PATH_SEPARATOR_S + ffd.cFileName).c_str())) + return false; + } + } + } while (FindNextFileA(hFind, &ffd)); + FindClose(hFind); + } + return (RemoveDirectoryA(path) != FALSE); #else - struct dirent de; - struct dirent *dptr; - DIR *d = opendir(path); - if (!d) - return true; - dptr = (struct dirent *)0; - for(;;) { - if (readdir_r(d,&de,&dptr) != 0) - break; - if (!dptr) - break; - if ((strcmp(dptr->d_name,".") != 0)&&(strcmp(dptr->d_name,"..") != 0)&&(strlen(dptr->d_name) > 0)) { - std::string p(path); - p.push_back(ZT_PATH_SEPARATOR); - p.append(dptr->d_name); - if (unlink(p.c_str()) != 0) { // unlink first will remove symlinks instead of recursing them - if (!rmDashRf(p.c_str())) - return false; - } - } - } - closedir(d); - return (rmdir(path) == 0); + struct dirent de; + struct dirent* dptr; + DIR* d = opendir(path); + if (! d) + return true; + dptr = (struct dirent*)0; + for (;;) { + if (readdir_r(d, &de, &dptr) != 0) + break; + if (! dptr) + break; + if ((strcmp(dptr->d_name, ".") != 0) && (strcmp(dptr->d_name, "..") != 0) && (strlen(dptr->d_name) > 0)) { + std::string p(path); + p.push_back(ZT_PATH_SEPARATOR); + p.append(dptr->d_name); + if (unlink(p.c_str()) != 0) { // unlink first will remove symlinks instead of recursing them + if (! rmDashRf(p.c_str())) + return false; + } + } + } + closedir(d); + return (rmdir(path) == 0); #endif } -void OSUtils::lockDownFile(const char *path,bool isDir) +void OSUtils::lockDownFile(const char* path, bool isDir) { #ifdef __UNIX_LIKE__ - chmod(path,isDir ? 0700 : 0600); + chmod(path, isDir ? 0700 : 0600); #else #ifdef __WINDOWS__ - { - STARTUPINFOA startupInfo; - PROCESS_INFORMATION processInfo; + { + STARTUPINFOA startupInfo; + PROCESS_INFORMATION processInfo; - startupInfo.cb = sizeof(startupInfo); - memset(&startupInfo,0,sizeof(STARTUPINFOA)); - memset(&processInfo,0,sizeof(PROCESS_INFORMATION)); - if (CreateProcessA(NULL,(LPSTR)(std::string("C:\\Windows\\System32\\icacls.exe \"") + path + "\" /inheritance:d /Q").c_str(),NULL,NULL,FALSE,CREATE_NO_WINDOW,NULL,NULL,&startupInfo,&processInfo)) { - WaitForSingleObject(processInfo.hProcess,INFINITE); - CloseHandle(processInfo.hProcess); - CloseHandle(processInfo.hThread); - } + startupInfo.cb = sizeof(startupInfo); + memset(&startupInfo, 0, sizeof(STARTUPINFOA)); + memset(&processInfo, 0, sizeof(PROCESS_INFORMATION)); + if (CreateProcessA(NULL, (LPSTR)(std::string("C:\\Windows\\System32\\icacls.exe \"") + path + "\" /inheritance:d /Q").c_str(), NULL, NULL, FALSE, CREATE_NO_WINDOW, NULL, NULL, &startupInfo, &processInfo)) { + WaitForSingleObject(processInfo.hProcess, INFINITE); + CloseHandle(processInfo.hProcess); + CloseHandle(processInfo.hThread); + } - startupInfo.cb = sizeof(startupInfo); - memset(&startupInfo,0,sizeof(STARTUPINFOA)); - memset(&processInfo,0,sizeof(PROCESS_INFORMATION)); - if (CreateProcessA(NULL,(LPSTR)(std::string("C:\\Windows\\System32\\icacls.exe \"") + path + "\" /remove *S-1-5-32-545 /Q").c_str(),NULL,NULL,FALSE,CREATE_NO_WINDOW,NULL,NULL,&startupInfo,&processInfo)) { - WaitForSingleObject(processInfo.hProcess,INFINITE); - CloseHandle(processInfo.hProcess); - CloseHandle(processInfo.hThread); - } + startupInfo.cb = sizeof(startupInfo); + memset(&startupInfo, 0, sizeof(STARTUPINFOA)); + memset(&processInfo, 0, sizeof(PROCESS_INFORMATION)); + if (CreateProcessA(NULL, (LPSTR)(std::string("C:\\Windows\\System32\\icacls.exe \"") + path + "\" /remove *S-1-5-32-545 /Q").c_str(), NULL, NULL, FALSE, CREATE_NO_WINDOW, NULL, NULL, &startupInfo, &processInfo)) { + WaitForSingleObject(processInfo.hProcess, INFINITE); + CloseHandle(processInfo.hProcess); + CloseHandle(processInfo.hThread); + } - // Remove 'Everyone' group from R/RX access - startupInfo.cb = sizeof(startupInfo); - memset(&startupInfo, 0, sizeof(STARTUPINFOA)); - memset(&processInfo, 0, sizeof(PROCESS_INFORMATION)); - if (CreateProcessA(NULL, (LPSTR)(std::string("C:\\Windows\\System32\\icacls.exe \"") + path + "\" /remove:g Everyone /t /c /Q").c_str(), NULL, NULL, FALSE, CREATE_NO_WINDOW, NULL, NULL, &startupInfo, &processInfo)) { - WaitForSingleObject(processInfo.hProcess, INFINITE); - CloseHandle(processInfo.hProcess); - CloseHandle(processInfo.hThread); - } - } + // Remove 'Everyone' group from R/RX access + startupInfo.cb = sizeof(startupInfo); + memset(&startupInfo, 0, sizeof(STARTUPINFOA)); + memset(&processInfo, 0, sizeof(PROCESS_INFORMATION)); + if (CreateProcessA(NULL, (LPSTR)(std::string("C:\\Windows\\System32\\icacls.exe \"") + path + "\" /remove:g Everyone /t /c /Q").c_str(), NULL, NULL, FALSE, CREATE_NO_WINDOW, NULL, NULL, &startupInfo, &processInfo)) { + WaitForSingleObject(processInfo.hProcess, INFINITE); + CloseHandle(processInfo.hProcess); + CloseHandle(processInfo.hThread); + } + } #endif #endif } -uint64_t OSUtils::getLastModified(const char *path) +uint64_t OSUtils::getLastModified(const char* path) { - struct stat s; - if (stat(path,&s)) - return 0; - return (((uint64_t)s.st_mtime) * 1000ULL); + struct stat s; + if (stat(path, &s)) + return 0; + return (((uint64_t)s.st_mtime) * 1000ULL); } -bool OSUtils::fileExists(const char *path,bool followLinks) +bool OSUtils::fileExists(const char* path, bool followLinks) { - struct stat s; + struct stat s; #ifdef __UNIX_LIKE__ - if (!followLinks) - return (lstat(path,&s) == 0); + if (! followLinks) + return (lstat(path, &s) == 0); #endif - return (stat(path,&s) == 0); + return (stat(path, &s) == 0); } -int64_t OSUtils::getFileSize(const char *path) +int64_t OSUtils::getFileSize(const char* path) { - struct stat s; - if (stat(path,&s)) - return -1; + struct stat s; + if (stat(path, &s)) + return -1; #ifdef __WINDOWS__ - return s.st_size; + return s.st_size; #else - if (S_ISREG(s.st_mode)) - return s.st_size; + if (S_ISREG(s.st_mode)) + return s.st_size; #endif - return -1; + return -1; } -bool OSUtils::readFile(const char *path,std::string &buf) +bool OSUtils::readFile(const char* path, std::string& buf) { - char tmp[16384]; - FILE *f = fopen(path,"rb"); - if (f) { - for(;;) { - long n = (long)fread(tmp,1,sizeof(tmp),f); - if (n > 0) - buf.append(tmp,n); - else break; - } - fclose(f); - return true; - } - return false; + char tmp[16384]; + FILE* f = fopen(path, "rb"); + if (f) { + for (;;) { + long n = (long)fread(tmp, 1, sizeof(tmp), f); + if (n > 0) + buf.append(tmp, n); + else + break; + } + fclose(f); + return true; + } + return false; } -bool OSUtils::writeFile(const char *path,const void *buf,unsigned int len) +bool OSUtils::writeFile(const char* path, const void* buf, unsigned int len) { - FILE *f = fopen(path,"wb"); - if (f) { - if ((long)fwrite(buf,1,len,f) != (long)len) { - fclose(f); - return false; - } else { - fclose(f); - return true; - } - } - return false; + FILE* f = fopen(path, "wb"); + if (f) { + if ((long)fwrite(buf, 1, len, f) != (long)len) { + fclose(f); + return false; + } + else { + fclose(f); + return true; + } + } + return false; } -std::vector OSUtils::split(const char *s,const char *const sep,const char *esc,const char *quot) +std::vector OSUtils::split(const char* s, const char* const sep, const char* esc, const char* quot) { - std::vector fields; - std::string buf; + std::vector fields; + std::string buf; - if (!esc) - esc = ""; - if (!quot) - quot = ""; + if (! esc) + esc = ""; + if (! quot) + quot = ""; - bool escapeState = false; - char quoteState = 0; - while (*s) { - if (escapeState) { - escapeState = false; - buf.push_back(*s); - } else if (quoteState) { - if (*s == quoteState) { - quoteState = 0; - fields.push_back(buf); - buf.clear(); - } else buf.push_back(*s); - } else { - const char *quotTmp; - if (strchr(esc,*s)) - escapeState = true; - else if ((buf.size() <= 0)&&((quotTmp = strchr(quot,*s)))) - quoteState = *quotTmp; - else if (strchr(sep,*s)) { - if (!buf.empty()) { - fields.push_back(buf); - buf.clear(); - } // else skip runs of separators - } else buf.push_back(*s); - } - ++s; - } + bool escapeState = false; + char quoteState = 0; + while (*s) { + if (escapeState) { + escapeState = false; + buf.push_back(*s); + } + else if (quoteState) { + if (*s == quoteState) { + quoteState = 0; + fields.push_back(buf); + buf.clear(); + } + else + buf.push_back(*s); + } + else { + const char* quotTmp; + if (strchr(esc, *s)) + escapeState = true; + else if ((buf.size() <= 0) && ((quotTmp = strchr(quot, *s)))) + quoteState = *quotTmp; + else if (strchr(sep, *s)) { + if (! buf.empty()) { + fields.push_back(buf); + buf.clear(); + } // else skip runs of separators + } + else + buf.push_back(*s); + } + ++s; + } - if (buf.size()) - fields.push_back(buf); + if (buf.size()) + fields.push_back(buf); - return fields; + return fields; } std::string OSUtils::platformDefaultHomePath() { #ifdef __QNAP__ - char *cmd = "/sbin/getcfg zerotier Install_Path -f /etc/config/qpkg.conf"; + char* cmd = "/sbin/getcfg zerotier Install_Path -f /etc/config/qpkg.conf"; char buf[128]; - FILE *fp; + FILE* fp; if ((fp = popen(cmd, "r")) == NULL) { printf("Error opening pipe!\n"); return NULL; } - while (fgets(buf, 128, fp) != NULL) { } - if(pclose(fp)) { + while (fgets(buf, 128, fp) != NULL) {} + if (pclose(fp)) { printf("Command not found or exited with error status\n"); return NULL; } @@ -413,170 +428,205 @@ std::string OSUtils::platformDefaultHomePath() return homeDir; #endif #ifdef __UBIQUITI__ - // Only persistent location after firmware upgrades - return std::string("/config/zerotier-one"); + // Only persistent location after firmware upgrades + return std::string("/config/zerotier-one"); #endif // Check for user-defined environment variable before using defaults #ifdef __WINDOWS__ - DWORD bufferSize = 65535; - std::string userDefinedPath; - bufferSize = GetEnvironmentVariable("ZEROTIER_HOME", &userDefinedPath[0], bufferSize); - if (bufferSize) { - return userDefinedPath; - } + DWORD bufferSize = 65535; + std::string userDefinedPath; + bufferSize = GetEnvironmentVariable("ZEROTIER_HOME", &userDefinedPath[0], bufferSize); + if (bufferSize) { + return userDefinedPath; + } #else - if(const char* userDefinedPath = getenv("ZEROTIER_HOME")) { - return std::string(userDefinedPath); - } + if (const char* userDefinedPath = getenv("ZEROTIER_HOME")) { + return std::string(userDefinedPath); + } #endif - // Finally, resort to using default paths if no user-defined path was provided + // Finally, resort to using default paths if no user-defined path was provided #ifdef __UNIX_LIKE__ #ifdef __APPLE__ - // /Library/... on Apple - return std::string("/Library/Application Support/ZeroTier/One"); + // /Library/... on Apple + return std::string("/Library/Application Support/ZeroTier/One"); #else #ifdef __BSD__ - // BSD likes /var/db instead of /var/lib - return std::string("/var/db/zerotier-one"); + // BSD likes /var/db instead of /var/lib + return std::string("/var/db/zerotier-one"); #else - // Use /var/lib for Linux and other *nix - return std::string("/var/lib/zerotier-one"); + // Use /var/lib for Linux and other *nix + return std::string("/var/lib/zerotier-one"); #endif #endif -#else // not __UNIX_LIKE__ +#else // not __UNIX_LIKE__ #ifdef __WINDOWS__ - // Look up app data folder on Windows, e.g. C:\ProgramData\... - char buf[16384]; - if (SUCCEEDED(SHGetFolderPathA(NULL,CSIDL_COMMON_APPDATA,NULL,0,buf))) - return (std::string(buf) + "\\ZeroTier\\One"); - else return std::string("C:\\ZeroTier\\One"); + // Look up app data folder on Windows, e.g. C:\ProgramData\... + char buf[16384]; + if (SUCCEEDED(SHGetFolderPathA(NULL, CSIDL_COMMON_APPDATA, NULL, 0, buf))) + return (std::string(buf) + "\\ZeroTier\\One"); + else + return std::string("C:\\ZeroTier\\One"); #else - return (std::string(ZT_PATH_SEPARATOR_S) + "ZeroTier" + ZT_PATH_SEPARATOR_S + "One"); // UNKNOWN PLATFORM + return (std::string(ZT_PATH_SEPARATOR_S) + "ZeroTier" + ZT_PATH_SEPARATOR_S + "One"); // UNKNOWN PLATFORM #endif -#endif // __UNIX_LIKE__ or not... +#endif // __UNIX_LIKE__ or not... } #ifndef OMIT_JSON_SUPPORT // Inline these massive JSON operations in one place only to reduce binary footprint and compile time -nlohmann::json OSUtils::jsonParse(const std::string &buf) { return nlohmann::json::parse(buf.c_str()); } -std::string OSUtils::jsonDump(const nlohmann::json &j,int indentation) { return j.dump(indentation); } - -uint64_t OSUtils::jsonInt(const nlohmann::json &jv,const uint64_t dfl) +nlohmann::json OSUtils::jsonParse(const std::string& buf) { - try { - if (jv.is_number()) { - return (uint64_t)jv; - } else if (jv.is_string()) { - std::string s = jv; - return Utils::strToU64(s.c_str()); - } else if (jv.is_boolean()) { - return ((bool)jv ? 1ULL : 0ULL); - } - } catch ( ... ) {} - return dfl; + return nlohmann::json::parse(buf.c_str()); +} +std::string OSUtils::jsonDump(const nlohmann::json& j, int indentation) +{ + return j.dump(indentation); } -double OSUtils::jsonDouble(const nlohmann::json &jv,const double dfl) +uint64_t OSUtils::jsonInt(const nlohmann::json& jv, const uint64_t dfl) { - try { - if (jv.is_number()) { - return (double)jv; - } - else if (jv.is_string()) { - std::string s = jv; - return Utils::strToDouble(s.c_str()); - } else if (jv.is_boolean()) { - return (double)jv; - } - } catch ( ... ) {} - return dfl; + try { + if (jv.is_number()) { + return (uint64_t)jv; + } + else if (jv.is_string()) { + std::string s = jv; + return Utils::strToU64(s.c_str()); + } + else if (jv.is_boolean()) { + return ((bool)jv ? 1ULL : 0ULL); + } + } + catch (...) { + } + return dfl; } -uint64_t OSUtils::jsonIntHex(const nlohmann::json &jv,const uint64_t dfl) +double OSUtils::jsonDouble(const nlohmann::json& jv, const double dfl) { - try { - if (jv.is_number()) { - return (uint64_t)jv; - } else if (jv.is_string()) { - std::string s = jv; - return Utils::hexStrToU64(s.c_str()); - } else if (jv.is_boolean()) { - return ((bool)jv ? 1ULL : 0ULL); - } - } catch ( ... ) {} - return dfl; + try { + if (jv.is_number()) { + return (double)jv; + } + else if (jv.is_string()) { + std::string s = jv; + return Utils::strToDouble(s.c_str()); + } + else if (jv.is_boolean()) { + return (double)jv; + } + } + catch (...) { + } + return dfl; } -bool OSUtils::jsonBool(const nlohmann::json &jv,const bool dfl) +uint64_t OSUtils::jsonIntHex(const nlohmann::json& jv, const uint64_t dfl) { - try { - if (jv.is_boolean()) { - return (bool)jv; - } else if (jv.is_number()) { - return ((uint64_t)jv > 0ULL); - } else if (jv.is_string()) { - std::string s = jv; - if (s.length() > 0) { - switch(s[0]) { - case 't': - case 'T': - case '1': - return true; - } - } - return false; - } - } catch ( ... ) {} - return dfl; + try { + if (jv.is_number()) { + return (uint64_t)jv; + } + else if (jv.is_string()) { + std::string s = jv; + return Utils::hexStrToU64(s.c_str()); + } + else if (jv.is_boolean()) { + return ((bool)jv ? 1ULL : 0ULL); + } + } + catch (...) { + } + return dfl; } -std::string OSUtils::jsonString(const nlohmann::json &jv,const char *dfl) +bool OSUtils::jsonBool(const nlohmann::json& jv, const bool dfl) { - try { - if (jv.is_string()) { - return jv; - } else if (jv.is_number()) { - char tmp[64]; - ztsnprintf(tmp,sizeof(tmp),"%llu",(uint64_t)jv); - return tmp; - } else if (jv.is_boolean()) { - return ((bool)jv ? std::string("1") : std::string("0")); - } - } catch ( ... ) {} - return std::string((dfl) ? dfl : ""); + try { + if (jv.is_boolean()) { + return (bool)jv; + } + else if (jv.is_number()) { + return ((uint64_t)jv > 0ULL); + } + else if (jv.is_string()) { + std::string s = jv; + if (s.length() > 0) { + switch (s[0]) { + case 't': + case 'T': + case '1': + return true; + } + } + return false; + } + } + catch (...) { + } + return dfl; } -std::string OSUtils::jsonBinFromHex(const nlohmann::json &jv) +std::string OSUtils::jsonString(const nlohmann::json& jv, const char* dfl) { - std::string s(jsonString(jv,"")); - if (s.length() > 0) { - unsigned int buflen = (unsigned int)((s.length() / 2) + 1); - char *buf = new char[buflen]; - try { - unsigned int l = Utils::unhex(s.c_str(),buf,buflen); - std::string b(buf,l); - delete [] buf; - return b; - } catch ( ... ) { - delete [] buf; - } - } - return std::string(); + try { + if (jv.is_string()) { + return jv; + } + else if (jv.is_number()) { + char tmp[64]; + ztsnprintf(tmp, sizeof(tmp), "%llu", (uint64_t)jv); + return tmp; + } + else if (jv.is_boolean()) { + return ((bool)jv ? std::string("1") : std::string("0")); + } + } + catch (...) { + } + return std::string((dfl) ? dfl : ""); } -#endif // OMIT_JSON_SUPPORT +std::string OSUtils::jsonBinFromHex(const nlohmann::json& jv) +{ + std::string s(jsonString(jv, "")); + if (s.length() > 0) { + unsigned int buflen = (unsigned int)((s.length() / 2) + 1); + char* buf = new char[buflen]; + try { + unsigned int l = Utils::unhex(s.c_str(), buf, buflen); + std::string b(buf, l); + delete[] buf; + return b; + } + catch (...) { + delete[] buf; + } + } + return std::string(); +} + +#endif // OMIT_JSON_SUPPORT // Used to convert HTTP header names to ASCII lower case -const unsigned char OSUtils::TOLOWER_TABLE[256] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, ' ', '!', '"', '#', '$', '%', '&', 0x27, '(', ')', '*', '+', ',', '-', '.', '/', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=', '>', '?', '@', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '{', '|', '}', '~', '_', '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '{', '|', '}', '~', 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff }; +const unsigned char OSUtils::TOLOWER_TABLE[256] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, + 0x1d, 0x1e, 0x1f, ' ', '!', '"', '#', '$', '%', '&', 0x27, '(', ')', '*', '+', ',', '-', '.', '/', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + ':', ';', '<', '=', '>', '?', '@', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', + 'w', 'x', 'y', 'z', '{', '|', '}', '~', '_', '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', + 't', 'u', 'v', 'w', 'x', 'y', 'z', '{', '|', '}', '~', 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x90, + 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, + 0xae, 0xaf, 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, + 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, + 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff }; -} // namespace ZeroTier +} // namespace ZeroTier diff --git a/osdep/OSUtils.hpp b/osdep/OSUtils.hpp index f8214efa..0c135b33 100644 --- a/osdep/OSUtils.hpp +++ b/osdep/OSUtils.hpp @@ -14,29 +14,28 @@ #ifndef ZT_OSUTILS_HPP #define ZT_OSUTILS_HPP -#include -#include -#include -#include -#include - -#include -#include -#include - #include "../node/Constants.hpp" #include "../node/InetAddress.hpp" +#include +#include +#include +#include +#include +#include +#include +#include + #ifdef __WINDOWS__ -#include -#include #include +#include +#include #else -#include -#include -#include -#include #include +#include +#include +#include +#include #ifdef __LINUX__ #include #endif @@ -51,255 +50,265 @@ namespace ZeroTier { /** * Miscellaneous utility functions and global constants */ -class OSUtils -{ -public: - /** - * Variant of snprintf that is portable and throws an exception - * - * This just wraps the local implementation whatever it's called, while - * performing a few other checks and adding exceptions for overflow. - * - * @param buf Buffer to write to - * @param len Length of buffer in bytes - * @param fmt Format string - * @param ... Format arguments - * @throws std::length_error buf[] too short (buf[] will still be left null-terminated) - */ - static unsigned int ztsnprintf(char *buf,unsigned int len,const char *fmt,...); +class OSUtils { + public: + /** + * Variant of snprintf that is portable and throws an exception + * + * This just wraps the local implementation whatever it's called, while + * performing a few other checks and adding exceptions for overflow. + * + * @param buf Buffer to write to + * @param len Length of buffer in bytes + * @param fmt Format string + * @param ... Format arguments + * @throws std::length_error buf[] too short (buf[] will still be left null-terminated) + */ + static unsigned int ztsnprintf(char* buf, unsigned int len, const char* fmt, ...); - /** - * Converts a uint64_t network ID into a string - * - * @param nwid network ID - * @throws std::length_error buf[] too short (buf[] will still be left null-terminated) - */ - static std::string networkIDStr(const uint64_t nwid); + /** + * Converts a uint64_t network ID into a string + * + * @param nwid network ID + * @throws std::length_error buf[] too short (buf[] will still be left null-terminated) + */ + static std::string networkIDStr(const uint64_t nwid); - /** - * Converts a uint64_t node ID into a string - * - * @param nid node ID - * @throws std::length_error buf[] too short (buf[] will still be left null-terminated) - */ - static std::string nodeIDStr(const uint64_t nid); + /** + * Converts a uint64_t node ID into a string + * + * @param nid node ID + * @throws std::length_error buf[] too short (buf[] will still be left null-terminated) + */ + static std::string nodeIDStr(const uint64_t nid); #ifdef __UNIX_LIKE__ - /** - * Close STDOUT_FILENO and STDERR_FILENO and replace them with output to given path - * - * This can be called after fork() and prior to exec() to suppress output - * from a subprocess, such as auto-update. - * - * @param stdoutPath Path to file to use for stdout - * @param stderrPath Path to file to use for stderr, or NULL for same as stdout (default) - * @return True on success - */ - static bool redirectUnixOutputs(const char *stdoutPath,const char *stderrPath = (const char *)0) - throw(); -#endif // __UNIX_LIKE__ + /** + * Close STDOUT_FILENO and STDERR_FILENO and replace them with output to given path + * + * This can be called after fork() and prior to exec() to suppress output + * from a subprocess, such as auto-update. + * + * @param stdoutPath Path to file to use for stdout + * @param stderrPath Path to file to use for stderr, or NULL for same as stdout (default) + * @return True on success + */ + static bool redirectUnixOutputs(const char* stdoutPath, const char* stderrPath = (const char*)0) throw(); +#endif // __UNIX_LIKE__ - /** - * Delete a file - * - * @param path Path to delete - * @return True if delete was successful - */ - static inline bool rm(const char *path) - { + /** + * Delete a file + * + * @param path Path to delete + * @return True if delete was successful + */ + static inline bool rm(const char* path) + { #ifdef __WINDOWS__ - return (DeleteFileA(path) != FALSE); + return (DeleteFileA(path) != FALSE); #else - return (unlink(path) == 0); + return (unlink(path) == 0); #endif - } - static inline bool rm(const std::string &path) { return rm(path.c_str()); } + } + static inline bool rm(const std::string& path) + { + return rm(path.c_str()); + } - static inline bool mkdir(const char *path) - { + static inline bool mkdir(const char* path) + { #ifdef __WINDOWS__ - if (::PathIsDirectoryA(path)) - return true; - return (::CreateDirectoryA(path,NULL) == TRUE); + if (::PathIsDirectoryA(path)) + return true; + return (::CreateDirectoryA(path, NULL) == TRUE); #else - if (::mkdir(path,0755) != 0) - return (errno == EEXIST); - return true; + if (::mkdir(path, 0755) != 0) + return (errno == EEXIST); + return true; #endif - } - static inline bool mkdir(const std::string &path) { return OSUtils::mkdir(path.c_str()); } + } + static inline bool mkdir(const std::string& path) + { + return OSUtils::mkdir(path.c_str()); + } - static inline bool rename(const char *o,const char *n) - { + static inline bool rename(const char* o, const char* n) + { #ifdef __WINDOWS__ - DeleteFileA(n); - return (::rename(o,n) == 0); + DeleteFileA(n); + return (::rename(o, n) == 0); #else - return (::rename(o,n) == 0); + return (::rename(o, n) == 0); #endif - } + } - /** - * List a directory's contents - * - * @param path Path to list - * @param includeDirectories If true, include directories as well as files - * @return Names of files in directory (without path prepended) - */ - static std::vector listDirectory(const char *path,bool includeDirectories = false); + /** + * List a directory's contents + * + * @param path Path to list + * @param includeDirectories If true, include directories as well as files + * @return Names of files in directory (without path prepended) + */ + static std::vector listDirectory(const char* path, bool includeDirectories = false); - /** - * Clean a directory of files whose last modified time is older than this - * - * This ignores directories, symbolic links, and other special files. - * - * @param olderThan Last modified older than timestamp (ms since epoch) - * @return Number of cleaned files or negative on fatal error - */ - static long cleanDirectory(const char *path,const int64_t olderThan); + /** + * Clean a directory of files whose last modified time is older than this + * + * This ignores directories, symbolic links, and other special files. + * + * @param olderThan Last modified older than timestamp (ms since epoch) + * @return Number of cleaned files or negative on fatal error + */ + static long cleanDirectory(const char* path, const int64_t olderThan); - /** - * Delete a directory and all its files and subdirectories recursively - * - * @param path Path to delete - * @return True on success - */ - static bool rmDashRf(const char *path); + /** + * Delete a directory and all its files and subdirectories recursively + * + * @param path Path to delete + * @return True on success + */ + static bool rmDashRf(const char* path); - /** - * Set modes on a file to something secure - * - * This locks a file so that only the owner can access it. What it actually - * does varies by platform. - * - * @param path Path to lock - * @param isDir True if this is a directory - */ - static void lockDownFile(const char *path,bool isDir); + /** + * Set modes on a file to something secure + * + * This locks a file so that only the owner can access it. What it actually + * does varies by platform. + * + * @param path Path to lock + * @param isDir True if this is a directory + */ + static void lockDownFile(const char* path, bool isDir); - /** - * Get file last modification time - * - * Resolution is often only second, not millisecond, but the return is - * always in ms for comparison against now(). - * - * @param path Path to file to get time - * @return Last modification time in ms since epoch or 0 if not found - */ - static uint64_t getLastModified(const char *path); + /** + * Get file last modification time + * + * Resolution is often only second, not millisecond, but the return is + * always in ms for comparison against now(). + * + * @param path Path to file to get time + * @return Last modification time in ms since epoch or 0 if not found + */ + static uint64_t getLastModified(const char* path); - /** - * @param path Path to check - * @param followLinks Follow links (on platforms with that concept) - * @return True if file or directory exists at path location - */ - static bool fileExists(const char *path,bool followLinks = true); + /** + * @param path Path to check + * @param followLinks Follow links (on platforms with that concept) + * @return True if file or directory exists at path location + */ + static bool fileExists(const char* path, bool followLinks = true); - /** - * @param path Path to file - * @return File size or -1 if nonexistent or other failure - */ - static int64_t getFileSize(const char *path); + /** + * @param path Path to file + * @return File size or -1 if nonexistent or other failure + */ + static int64_t getFileSize(const char* path); - /** - * Get IP (v4 and/or v6) addresses for a given host - * - * This is a blocking resolver. - * - * @param name Host name - * @return IP addresses in InetAddress sort order or empty vector if not found - */ - static std::vector resolve(const char *name); + /** + * Get IP (v4 and/or v6) addresses for a given host + * + * This is a blocking resolver. + * + * @param name Host name + * @return IP addresses in InetAddress sort order or empty vector if not found + */ + static std::vector resolve(const char* name); - /** - * @return Current time in milliseconds since epoch - */ - static inline int64_t now() - { + /** + * @return Current time in milliseconds since epoch + */ + static inline int64_t now() + { #ifdef __WINDOWS__ - FILETIME ft; - SYSTEMTIME st; - ULARGE_INTEGER tmp; - GetSystemTime(&st); - SystemTimeToFileTime(&st,&ft); - tmp.LowPart = ft.dwLowDateTime; - tmp.HighPart = ft.dwHighDateTime; - return (int64_t)( ((tmp.QuadPart - 116444736000000000LL) / 10000L) + st.wMilliseconds ); + FILETIME ft; + SYSTEMTIME st; + ULARGE_INTEGER tmp; + GetSystemTime(&st); + SystemTimeToFileTime(&st, &ft); + tmp.LowPart = ft.dwLowDateTime; + tmp.HighPart = ft.dwHighDateTime; + return (int64_t)(((tmp.QuadPart - 116444736000000000LL) / 10000L) + st.wMilliseconds); #else - struct timeval tv; - gettimeofday(&tv,(struct timezone *)0); - return ( (1000LL * (int64_t)tv.tv_sec) + (int64_t)(tv.tv_usec / 1000) ); + struct timeval tv; + gettimeofday(&tv, (struct timezone*)0); + return ((1000LL * (int64_t)tv.tv_sec) + (int64_t)(tv.tv_usec / 1000)); #endif - }; + }; - /** - * Read the full contents of a file into a string buffer - * - * The buffer isn't cleared, so if it already contains data the file's data will - * be appended. - * - * @param path Path of file to read - * @param buf Buffer to fill - * @return True if open and read successful - */ - static bool readFile(const char *path,std::string &buf); + /** + * Read the full contents of a file into a string buffer + * + * The buffer isn't cleared, so if it already contains data the file's data will + * be appended. + * + * @param path Path of file to read + * @param buf Buffer to fill + * @return True if open and read successful + */ + static bool readFile(const char* path, std::string& buf); - /** - * Write a block of data to disk, replacing any current file contents - * - * @param path Path to write - * @param buf Buffer containing data - * @param len Length of buffer - * @return True if entire file was successfully written - */ - static bool writeFile(const char *path,const void *buf,unsigned int len); + /** + * Write a block of data to disk, replacing any current file contents + * + * @param path Path to write + * @param buf Buffer containing data + * @param len Length of buffer + * @return True if entire file was successfully written + */ + static bool writeFile(const char* path, const void* buf, unsigned int len); - /** - * Split a string by delimiter, with optional escape and quote characters - * - * @param s String to split - * @param sep One or more separators - * @param esc Zero or more escape characters - * @param quot Zero or more quote characters - * @return Vector of tokens - */ - static std::vector split(const char *s,const char *const sep,const char *esc,const char *quot); + /** + * Split a string by delimiter, with optional escape and quote characters + * + * @param s String to split + * @param sep One or more separators + * @param esc Zero or more escape characters + * @param quot Zero or more quote characters + * @return Vector of tokens + */ + static std::vector split(const char* s, const char* const sep, const char* esc, const char* quot); - /** - * Write a block of data to disk, replacing any current file contents - * - * @param path Path to write - * @param s Data to write - * @return True if entire file was successfully written - */ - static inline bool writeFile(const char *path,const std::string &s) { return writeFile(path,s.data(),(unsigned int)s.length()); } + /** + * Write a block of data to disk, replacing any current file contents + * + * @param path Path to write + * @param s Data to write + * @return True if entire file was successfully written + */ + static inline bool writeFile(const char* path, const std::string& s) + { + return writeFile(path, s.data(), (unsigned int)s.length()); + } - /** - * @param c ASCII character to convert - * @return Lower case ASCII character or unchanged if not a letter - */ - static inline char toLower(char c) throw() { return (char)OSUtils::TOLOWER_TABLE[(unsigned long)c]; } + /** + * @param c ASCII character to convert + * @return Lower case ASCII character or unchanged if not a letter + */ + static inline char toLower(char c) throw() + { + return (char)OSUtils::TOLOWER_TABLE[(unsigned long)c]; + } - /** - * @return Platform default ZeroTier One home path - */ - static std::string platformDefaultHomePath(); + /** + * @return Platform default ZeroTier One home path + */ + static std::string platformDefaultHomePath(); #ifndef OMIT_JSON_SUPPORT - static nlohmann::json jsonParse(const std::string &buf); - static std::string jsonDump(const nlohmann::json &j,int indentation = 1); - static uint64_t jsonInt(const nlohmann::json &jv,const uint64_t dfl); - static double jsonDouble(const nlohmann::json &jv,const double dfl); - static uint64_t jsonIntHex(const nlohmann::json &jv,const uint64_t dfl); - static bool jsonBool(const nlohmann::json &jv,const bool dfl); - static std::string jsonString(const nlohmann::json &jv,const char *dfl); - static std::string jsonBinFromHex(const nlohmann::json &jv); -#endif // OMIT_JSON_SUPPORT + static nlohmann::json jsonParse(const std::string& buf); + static std::string jsonDump(const nlohmann::json& j, int indentation = 1); + static uint64_t jsonInt(const nlohmann::json& jv, const uint64_t dfl); + static double jsonDouble(const nlohmann::json& jv, const double dfl); + static uint64_t jsonIntHex(const nlohmann::json& jv, const uint64_t dfl); + static bool jsonBool(const nlohmann::json& jv, const bool dfl); + static std::string jsonString(const nlohmann::json& jv, const char* dfl); + static std::string jsonBinFromHex(const nlohmann::json& jv); +#endif // OMIT_JSON_SUPPORT -private: - static const unsigned char TOLOWER_TABLE[256]; + private: + static const unsigned char TOLOWER_TABLE[256]; }; -} // namespace ZeroTier +} // namespace ZeroTier #endif diff --git a/osdep/Phy.hpp b/osdep/Phy.hpp index 14cf92ca..7af0f4cf 100644 --- a/osdep/Phy.hpp +++ b/osdep/Phy.hpp @@ -14,59 +14,58 @@ #ifndef ZT_PHY_HPP #define ZT_PHY_HPP +#include +#include #include #include #include -#include -#include - #if defined(_WIN32) || defined(_WIN64) +#include #include #include -#include -#define ZT_PHY_SOCKFD_TYPE SOCKET -#define ZT_PHY_SOCKFD_NULL (INVALID_SOCKET) -#define ZT_PHY_SOCKFD_VALID(s) ((s) != INVALID_SOCKET) -#define ZT_PHY_CLOSE_SOCKET(s) ::closesocket(s) -#define ZT_PHY_MAX_SOCKETS (FD_SETSIZE) -#define ZT_PHY_MAX_INTERCEPTS ZT_PHY_MAX_SOCKETS +#define ZT_PHY_SOCKFD_TYPE SOCKET +#define ZT_PHY_SOCKFD_NULL (INVALID_SOCKET) +#define ZT_PHY_SOCKFD_VALID(s) ((s) != INVALID_SOCKET) +#define ZT_PHY_CLOSE_SOCKET(s) ::closesocket(s) +#define ZT_PHY_MAX_SOCKETS (FD_SETSIZE) +#define ZT_PHY_MAX_INTERCEPTS ZT_PHY_MAX_SOCKETS #define ZT_PHY_SOCKADDR_STORAGE_TYPE struct sockaddr_storage -#else // not Windows - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#else // not Windows #include "../node/Metrics.hpp" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + #if defined(__linux__) || defined(linux) || defined(__LINUX__) || defined(__linux) #ifndef IPV6_DONTFRAG #define IPV6_DONTFRAG 62 #endif #endif -#define ZT_PHY_SOCKFD_TYPE int -#define ZT_PHY_SOCKFD_NULL (-1) -#define ZT_PHY_SOCKFD_VALID(s) ((s) > -1) -#define ZT_PHY_CLOSE_SOCKET(s) ::close(s) -#define ZT_PHY_MAX_SOCKETS (FD_SETSIZE) -#define ZT_PHY_MAX_INTERCEPTS ZT_PHY_MAX_SOCKETS +#define ZT_PHY_SOCKFD_TYPE int +#define ZT_PHY_SOCKFD_NULL (-1) +#define ZT_PHY_SOCKFD_VALID(s) ((s) > -1) +#define ZT_PHY_CLOSE_SOCKET(s) ::close(s) +#define ZT_PHY_MAX_SOCKETS (FD_SETSIZE) +#define ZT_PHY_MAX_INTERCEPTS ZT_PHY_MAX_SOCKETS #define ZT_PHY_SOCKADDR_STORAGE_TYPE struct sockaddr_storage -#endif // Windows or not +#endif // Windows or not namespace ZeroTier { @@ -122,1087 +121,1146 @@ typedef void PhySocket; * This isn't thread-safe with the exception of whack(), which is safe to * call from another thread to abort poll(). */ -template -class Phy -{ -private: - HANDLER_PTR_TYPE _handler; +template class Phy { + private: + HANDLER_PTR_TYPE _handler; - enum PhySocketType - { - ZT_PHY_SOCKET_CLOSED = 0x00, // socket is closed, will be removed on next poll() - ZT_PHY_SOCKET_TCP_OUT_PENDING = 0x01, - ZT_PHY_SOCKET_TCP_OUT_CONNECTED = 0x02, - ZT_PHY_SOCKET_TCP_IN = 0x03, - ZT_PHY_SOCKET_TCP_LISTEN = 0x04, - ZT_PHY_SOCKET_UDP = 0x05, - ZT_PHY_SOCKET_FD = 0x06, - ZT_PHY_SOCKET_UNIX_IN = 0x07, - ZT_PHY_SOCKET_UNIX_LISTEN = 0x08 - }; + enum PhySocketType { + ZT_PHY_SOCKET_CLOSED = 0x00, // socket is closed, will be removed on next poll() + ZT_PHY_SOCKET_TCP_OUT_PENDING = 0x01, + ZT_PHY_SOCKET_TCP_OUT_CONNECTED = 0x02, + ZT_PHY_SOCKET_TCP_IN = 0x03, + ZT_PHY_SOCKET_TCP_LISTEN = 0x04, + ZT_PHY_SOCKET_UDP = 0x05, + ZT_PHY_SOCKET_FD = 0x06, + ZT_PHY_SOCKET_UNIX_IN = 0x07, + ZT_PHY_SOCKET_UNIX_LISTEN = 0x08 + }; - struct PhySocketImpl { - PhySocketImpl() {} - PhySocketType type; - ZT_PHY_SOCKFD_TYPE sock; - void *uptr; // user-settable pointer - uint16_t localPort; - ZT_PHY_SOCKADDR_STORAGE_TYPE saddr; // remote for TCP_OUT and TCP_IN, local for TCP_LISTEN, RAW, and UDP - }; + struct PhySocketImpl { + PhySocketImpl() + { + } + PhySocketType type; + ZT_PHY_SOCKFD_TYPE sock; + void* uptr; // user-settable pointer + uint16_t localPort; + ZT_PHY_SOCKADDR_STORAGE_TYPE saddr; // remote for TCP_OUT and TCP_IN, local for TCP_LISTEN, RAW, and UDP + }; - std::list _socks; - fd_set _readfds; - fd_set _writefds; + std::list _socks; + fd_set _readfds; + fd_set _writefds; #if defined(_WIN32) || defined(_WIN64) - fd_set _exceptfds; + fd_set _exceptfds; #endif - long _nfds; + long _nfds; - ZT_PHY_SOCKFD_TYPE _whackReceiveSocket; - ZT_PHY_SOCKFD_TYPE _whackSendSocket; + ZT_PHY_SOCKFD_TYPE _whackReceiveSocket; + ZT_PHY_SOCKFD_TYPE _whackSendSocket; - bool _noDelay; - bool _noCheck; + bool _noDelay; + bool _noCheck; -public: - /** - * @param handler Pointer of type HANDLER_PTR_TYPE to handler - * @param noDelay If true, disable TCP NAGLE algorithm on TCP sockets - * @param noCheck If true, attempt to set UDP SO_NO_CHECK option to disable sending checksums - */ - Phy(HANDLER_PTR_TYPE handler,bool noDelay,bool noCheck) : - _handler(handler) - { - FD_ZERO(&_readfds); - FD_ZERO(&_writefds); + public: + /** + * @param handler Pointer of type HANDLER_PTR_TYPE to handler + * @param noDelay If true, disable TCP NAGLE algorithm on TCP sockets + * @param noCheck If true, attempt to set UDP SO_NO_CHECK option to disable sending checksums + */ + Phy(HANDLER_PTR_TYPE handler, bool noDelay, bool noCheck) : _handler(handler) + { + FD_ZERO(&_readfds); + FD_ZERO(&_writefds); #if defined(_WIN32) || defined(_WIN64) - FD_ZERO(&_exceptfds); + FD_ZERO(&_exceptfds); - SOCKET pipes[2]; - { // hack copied from StackOverflow, behaves a bit like pipe() on *nix systems - struct sockaddr_in inaddr; - struct sockaddr addr; - SOCKET lst=::socket(AF_INET, SOCK_STREAM,IPPROTO_TCP); - if (lst == INVALID_SOCKET) - throw std::runtime_error("unable to create pipes for select() abort"); - memset(&inaddr, 0, sizeof(inaddr)); - memset(&addr, 0, sizeof(addr)); - inaddr.sin_family = AF_INET; - inaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); - inaddr.sin_port = 0; - int yes=1; - setsockopt(lst,SOL_SOCKET,SO_REUSEADDR,(char*)&yes,sizeof(yes)); - bind(lst,(struct sockaddr *)&inaddr,sizeof(inaddr)); - listen(lst,1); - int len=sizeof(inaddr); - getsockname(lst, &addr,&len); - pipes[0]=::socket(AF_INET, SOCK_STREAM,0); - if (pipes[0] == INVALID_SOCKET) - throw std::runtime_error("unable to create pipes for select() abort"); - connect(pipes[0],&addr,len); - pipes[1]=accept(lst,0,0); - closesocket(lst); - } -#else // not Windows - int pipes[2]; - if (::pipe(pipes)) - throw std::runtime_error("unable to create pipes for select() abort"); -#endif // Windows or not + SOCKET pipes[2]; + { // hack copied from StackOverflow, behaves a bit like pipe() on *nix systems + struct sockaddr_in inaddr; + struct sockaddr addr; + SOCKET lst = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + if (lst == INVALID_SOCKET) + throw std::runtime_error("unable to create pipes for select() abort"); + memset(&inaddr, 0, sizeof(inaddr)); + memset(&addr, 0, sizeof(addr)); + inaddr.sin_family = AF_INET; + inaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + inaddr.sin_port = 0; + int yes = 1; + setsockopt(lst, SOL_SOCKET, SO_REUSEADDR, (char*)&yes, sizeof(yes)); + bind(lst, (struct sockaddr*)&inaddr, sizeof(inaddr)); + listen(lst, 1); + int len = sizeof(inaddr); + getsockname(lst, &addr, &len); + pipes[0] = ::socket(AF_INET, SOCK_STREAM, 0); + if (pipes[0] == INVALID_SOCKET) + throw std::runtime_error("unable to create pipes for select() abort"); + connect(pipes[0], &addr, len); + pipes[1] = accept(lst, 0, 0); + closesocket(lst); + } +#else // not Windows + int pipes[2]; + if (::pipe(pipes)) + throw std::runtime_error("unable to create pipes for select() abort"); +#endif // Windows or not - _nfds = (pipes[0] > pipes[1]) ? (long)pipes[0] : (long)pipes[1]; - _whackReceiveSocket = pipes[0]; - _whackSendSocket = pipes[1]; - _noDelay = noDelay; - _noCheck = noCheck; - } + _nfds = (pipes[0] > pipes[1]) ? (long)pipes[0] : (long)pipes[1]; + _whackReceiveSocket = pipes[0]; + _whackSendSocket = pipes[1]; + _noDelay = noDelay; + _noCheck = noCheck; + } - ~Phy() - { - for(typename std::list::const_iterator s(_socks.begin());s!=_socks.end();++s) { - if (s->type != ZT_PHY_SOCKET_CLOSED) - this->close((PhySocket *)&(*s),true); - } - ZT_PHY_CLOSE_SOCKET(_whackReceiveSocket); - ZT_PHY_CLOSE_SOCKET(_whackSendSocket); - } + ~Phy() + { + for (typename std::list::const_iterator s(_socks.begin()); s != _socks.end(); ++s) { + if (s->type != ZT_PHY_SOCKET_CLOSED) + this->close((PhySocket*)&(*s), true); + } + ZT_PHY_CLOSE_SOCKET(_whackReceiveSocket); + ZT_PHY_CLOSE_SOCKET(_whackSendSocket); + } - /** - * @param s Socket object - * @return Underlying OS-type (usually int or long) file descriptor associated with object - */ - static inline ZT_PHY_SOCKFD_TYPE getDescriptor(PhySocket* s) throw() - { - return reinterpret_cast(s)->sock; - } + /** + * @param s Socket object + * @return Underlying OS-type (usually int or long) file descriptor associated with object + */ + static inline ZT_PHY_SOCKFD_TYPE getDescriptor(PhySocket* s) throw() + { + return reinterpret_cast(s)->sock; + } - /** - * @param s Socket object - * @return Pointer to user object - */ - static inline void** getuptr(PhySocket* s) throw() - { - return &(reinterpret_cast(s)->uptr); - } + /** + * @param s Socket object + * @return Pointer to user object + */ + static inline void** getuptr(PhySocket* s) throw() + { + return &(reinterpret_cast(s)->uptr); + } - /** - * Return the local port corresponding to this PhySocket - * - * @param s Socket object - * - * @return Local port corresponding to this PhySocket - */ - static inline uint16_t getLocalPort(PhySocket* s) throw() - { - return reinterpret_cast(s)->localPort; - } + /** + * Return the local port corresponding to this PhySocket + * + * @param s Socket object + * + * @return Local port corresponding to this PhySocket + */ + static inline uint16_t getLocalPort(PhySocket* s) throw() + { + return reinterpret_cast(s)->localPort; + } - /** - * Cause poll() to stop waiting immediately - * - * This can be used to reset the polling loop after changes that require - * attention, or to shut down a background thread that is waiting, etc. - */ - inline void whack() - { + /** + * Cause poll() to stop waiting immediately + * + * This can be used to reset the polling loop after changes that require + * attention, or to shut down a background thread that is waiting, etc. + */ + inline void whack() + { #if defined(_WIN32) || defined(_WIN64) - ::send(_whackSendSocket, (const char*)this, 1, 0); + ::send(_whackSendSocket, (const char*)this, 1, 0); #else - (void)(::write(_whackSendSocket, (PhySocket*)this, 1)); + (void)(::write(_whackSendSocket, (PhySocket*)this, 1)); #endif - } + } - /** - * @return Number of open sockets - */ - inline unsigned long count() const throw() - { - return _socks.size(); - } + /** + * @return Number of open sockets + */ + inline unsigned long count() const throw() + { + return _socks.size(); + } - /** - * @return Maximum number of sockets allowed - */ - inline unsigned long maxCount() const throw() - { - return ZT_PHY_MAX_SOCKETS; - } + /** + * @return Maximum number of sockets allowed + */ + inline unsigned long maxCount() const throw() + { + return ZT_PHY_MAX_SOCKETS; + } - /** - * Wrap a raw file descriptor in a PhySocket structure - * - * This can be used to select/poll on a raw file descriptor as part of this - * class's I/O loop. By default the fd is set for read notification but - * this can be controlled with setNotifyReadable(). When any detected - * condition is present, the phyOnFileDescriptorActivity() callback is - * called with one or both of its arguments 'true'. - * - * The Phy<>::close() method *must* be called when you're done with this - * file descriptor to remove it from the select/poll set, but unlike other - * types of sockets Phy<> does not actually close the underlying fd or - * otherwise manage its life cycle. There is also no close notification - * callback for this fd, since Phy<> doesn't actually perform reading or - * writing or detect error conditions. This is only useful for adding a - * file descriptor to Phy<> to select/poll on it. - * - * @param fd Raw file descriptor - * @param uptr User pointer to supply to callbacks - * @return PhySocket wrapping fd or NULL on failure (out of memory or too many sockets) - */ - inline PhySocket *wrapSocket(ZT_PHY_SOCKFD_TYPE fd,void *uptr = (void *)0) - { - if (_socks.size() >= ZT_PHY_MAX_SOCKETS) - return (PhySocket *)0; - try { - _socks.push_back(PhySocketImpl()); - } catch ( ... ) { - return (PhySocket *)0; - } - PhySocketImpl &sws = _socks.back(); - if ((long)fd > _nfds) - _nfds = (long)fd; - FD_SET(fd,&_readfds); - sws.type = ZT_PHY_SOCKET_UNIX_IN; /* TODO: Type was changed to allow for CBs with new RPC model */ - sws.sock = fd; - sws.uptr = uptr; - memset(&(sws.saddr),0,sizeof(struct sockaddr_storage)); - // no sockaddr for this socket type, leave saddr null - return (PhySocket *)&sws; - } + /** + * Wrap a raw file descriptor in a PhySocket structure + * + * This can be used to select/poll on a raw file descriptor as part of this + * class's I/O loop. By default the fd is set for read notification but + * this can be controlled with setNotifyReadable(). When any detected + * condition is present, the phyOnFileDescriptorActivity() callback is + * called with one or both of its arguments 'true'. + * + * The Phy<>::close() method *must* be called when you're done with this + * file descriptor to remove it from the select/poll set, but unlike other + * types of sockets Phy<> does not actually close the underlying fd or + * otherwise manage its life cycle. There is also no close notification + * callback for this fd, since Phy<> doesn't actually perform reading or + * writing or detect error conditions. This is only useful for adding a + * file descriptor to Phy<> to select/poll on it. + * + * @param fd Raw file descriptor + * @param uptr User pointer to supply to callbacks + * @return PhySocket wrapping fd or NULL on failure (out of memory or too many sockets) + */ + inline PhySocket* wrapSocket(ZT_PHY_SOCKFD_TYPE fd, void* uptr = (void*)0) + { + if (_socks.size() >= ZT_PHY_MAX_SOCKETS) + return (PhySocket*)0; + try { + _socks.push_back(PhySocketImpl()); + } + catch (...) { + return (PhySocket*)0; + } + PhySocketImpl& sws = _socks.back(); + if ((long)fd > _nfds) + _nfds = (long)fd; + FD_SET(fd, &_readfds); + sws.type = ZT_PHY_SOCKET_UNIX_IN; /* TODO: Type was changed to allow for CBs with new RPC model */ + sws.sock = fd; + sws.uptr = uptr; + memset(&(sws.saddr), 0, sizeof(struct sockaddr_storage)); + // no sockaddr for this socket type, leave saddr null + return (PhySocket*)&sws; + } - /** - * Bind a UDP socket - * - * @param localAddress Local endpoint address and port - * @param uptr Initial value of user pointer associated with this socket (default: NULL) - * @param bufferSize Desired socket receive/send buffer size -- will set as close to this as possible (default: 0, leave alone) - * @return Socket or NULL on failure to bind - */ - inline PhySocket *udpBind(const struct sockaddr *localAddress,void *uptr = (void *)0,int bufferSize = 0) - { - if (_socks.size() >= ZT_PHY_MAX_SOCKETS) - return (PhySocket *)0; + /** + * Bind a UDP socket + * + * @param localAddress Local endpoint address and port + * @param uptr Initial value of user pointer associated with this socket (default: NULL) + * @param bufferSize Desired socket receive/send buffer size -- will set as close to this as possible (default: 0, leave alone) + * @return Socket or NULL on failure to bind + */ + inline PhySocket* udpBind(const struct sockaddr* localAddress, void* uptr = (void*)0, int bufferSize = 0) + { + if (_socks.size() >= ZT_PHY_MAX_SOCKETS) + return (PhySocket*)0; - ZT_PHY_SOCKFD_TYPE s = ::socket(localAddress->sa_family,SOCK_DGRAM,0); - if (!ZT_PHY_SOCKFD_VALID(s)) - return (PhySocket *)0; + ZT_PHY_SOCKFD_TYPE s = ::socket(localAddress->sa_family, SOCK_DGRAM, 0); + if (! ZT_PHY_SOCKFD_VALID(s)) + return (PhySocket*)0; - if (bufferSize > 0) { - int bs = bufferSize; - while (bs >= 65536) { - int tmpbs = bs; - if (setsockopt(s,SOL_SOCKET,SO_RCVBUF,(const char *)&tmpbs,sizeof(tmpbs)) == 0) - break; - bs -= 4096; - } - bs = bufferSize; - while (bs >= 65536) { - int tmpbs = bs; - if (setsockopt(s,SOL_SOCKET,SO_SNDBUF,(const char *)&tmpbs,sizeof(tmpbs)) == 0) - break; - bs -= 4096; - } - } + if (bufferSize > 0) { + int bs = bufferSize; + while (bs >= 65536) { + int tmpbs = bs; + if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, (const char*)&tmpbs, sizeof(tmpbs)) == 0) + break; + bs -= 4096; + } + bs = bufferSize; + while (bs >= 65536) { + int tmpbs = bs; + if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, (const char*)&tmpbs, sizeof(tmpbs)) == 0) + break; + bs -= 4096; + } + } #if defined(_WIN32) || defined(_WIN64) - { - BOOL f; - if (localAddress->sa_family == AF_INET6) { - f = TRUE; setsockopt(s,IPPROTO_IPV6,IPV6_V6ONLY,(const char *)&f,sizeof(f)); - f = FALSE; setsockopt(s,IPPROTO_IPV6,IPV6_DONTFRAG,(const char *)&f,sizeof(f)); - } - f = FALSE; setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(const char *)&f,sizeof(f)); - f = TRUE; setsockopt(s,SOL_SOCKET,SO_BROADCAST,(const char *)&f,sizeof(f)); - } -#else // not Windows - { - int f; - if (localAddress->sa_family == AF_INET6) { - f = 1; setsockopt(s,IPPROTO_IPV6,IPV6_V6ONLY,(void *)&f,sizeof(f)); + { + BOOL f; + if (localAddress->sa_family == AF_INET6) { + f = TRUE; + setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, (const char*)&f, sizeof(f)); + f = FALSE; + setsockopt(s, IPPROTO_IPV6, IPV6_DONTFRAG, (const char*)&f, sizeof(f)); + } + f = FALSE; + setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (const char*)&f, sizeof(f)); + f = TRUE; + setsockopt(s, SOL_SOCKET, SO_BROADCAST, (const char*)&f, sizeof(f)); + } +#else // not Windows + { + int f; + if (localAddress->sa_family == AF_INET6) { + f = 1; + setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, (void*)&f, sizeof(f)); #ifdef IPV6_MTU_DISCOVER - f = 0; setsockopt(s,IPPROTO_IPV6,IPV6_MTU_DISCOVER,&f,sizeof(f)); + f = 0; + setsockopt(s, IPPROTO_IPV6, IPV6_MTU_DISCOVER, &f, sizeof(f)); #endif #ifdef IPV6_DONTFRAG - f = 0; setsockopt(s,IPPROTO_IPV6,IPV6_DONTFRAG,&f,sizeof(f)); + f = 0; + setsockopt(s, IPPROTO_IPV6, IPV6_DONTFRAG, &f, sizeof(f)); #endif - } - f = 0; setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(void *)&f,sizeof(f)); - f = 1; setsockopt(s,SOL_SOCKET,SO_BROADCAST,(void *)&f,sizeof(f)); + } + f = 0; + setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (void*)&f, sizeof(f)); + f = 1; + setsockopt(s, SOL_SOCKET, SO_BROADCAST, (void*)&f, sizeof(f)); #ifdef IP_DONTFRAG - f = 0; setsockopt(s,IPPROTO_IP,IP_DONTFRAG,&f,sizeof(f)); + f = 0; + setsockopt(s, IPPROTO_IP, IP_DONTFRAG, &f, sizeof(f)); #endif #ifdef IP_MTU_DISCOVER - f = 0; setsockopt(s,IPPROTO_IP,IP_MTU_DISCOVER,&f,sizeof(f)); + f = 0; + setsockopt(s, IPPROTO_IP, IP_MTU_DISCOVER, &f, sizeof(f)); #endif #ifdef SO_NO_CHECK - // For now at least we only set SO_NO_CHECK on IPv4 sockets since some - // IPv6 stacks incorrectly discard zero checksum packets. May remove - // this restriction later once broken stuff dies more. - if ((localAddress->sa_family == AF_INET)&&(_noCheck)) { - f = 1; setsockopt(s,SOL_SOCKET,SO_NO_CHECK,(void *)&f,sizeof(f)); - } + // For now at least we only set SO_NO_CHECK on IPv4 sockets since some + // IPv6 stacks incorrectly discard zero checksum packets. May remove + // this restriction later once broken stuff dies more. + if ((localAddress->sa_family == AF_INET) && (_noCheck)) { + f = 1; + setsockopt(s, SOL_SOCKET, SO_NO_CHECK, (void*)&f, sizeof(f)); + } #endif - } -#endif // Windows or not + } +#endif // Windows or not - if (::bind(s,localAddress,(localAddress->sa_family == AF_INET6) ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in))) { - ZT_PHY_CLOSE_SOCKET(s); - return (PhySocket *)0; - } + if (::bind(s, localAddress, (localAddress->sa_family == AF_INET6) ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in))) { + ZT_PHY_CLOSE_SOCKET(s); + return (PhySocket*)0; + } #if defined(_WIN32) || defined(_WIN64) - { u_long iMode=1; ioctlsocket(s,FIONBIO,&iMode); } + { + u_long iMode = 1; + ioctlsocket(s, FIONBIO, &iMode); + } #else - fcntl(s,F_SETFL,O_NONBLOCK); + fcntl(s, F_SETFL, O_NONBLOCK); #endif - try { - _socks.push_back(PhySocketImpl()); - } catch ( ... ) { - ZT_PHY_CLOSE_SOCKET(s); - return (PhySocket *)0; - } - PhySocketImpl &sws = _socks.back(); + try { + _socks.push_back(PhySocketImpl()); + } + catch (...) { + ZT_PHY_CLOSE_SOCKET(s); + return (PhySocket*)0; + } + PhySocketImpl& sws = _socks.back(); - if ((long)s > _nfds) - _nfds = (long)s; - FD_SET(s,&_readfds); - sws.type = ZT_PHY_SOCKET_UDP; - sws.sock = s; - sws.uptr = uptr; + if ((long)s > _nfds) + _nfds = (long)s; + FD_SET(s, &_readfds); + sws.type = ZT_PHY_SOCKET_UDP; + sws.sock = s; + sws.uptr = uptr; #ifdef __UNIX_LIKE__ - struct sockaddr_in *sin = (struct sockaddr_in *)localAddress; - sws.localPort = htons(sin->sin_port); + struct sockaddr_in* sin = (struct sockaddr_in*)localAddress; + sws.localPort = htons(sin->sin_port); #endif - memset(&(sws.saddr),0,sizeof(struct sockaddr_storage)); - memcpy(&(sws.saddr),localAddress,(localAddress->sa_family == AF_INET6) ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in)); + memset(&(sws.saddr), 0, sizeof(struct sockaddr_storage)); + memcpy(&(sws.saddr), localAddress, (localAddress->sa_family == AF_INET6) ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in)); - return (PhySocket *)&sws; - } + return (PhySocket*)&sws; + } - /** - * Set the IP TTL for the next outgoing packet (for IPv4 UDP sockets only) - * - * @param ttl New TTL (0 or >255 will set it to 255) - * @return True on success - */ - inline bool setIp4UdpTtl(PhySocket *sock,unsigned int ttl) - { - PhySocketImpl &sws = *(reinterpret_cast(sock)); + /** + * Set the IP TTL for the next outgoing packet (for IPv4 UDP sockets only) + * + * @param ttl New TTL (0 or >255 will set it to 255) + * @return True on success + */ + inline bool setIp4UdpTtl(PhySocket* sock, unsigned int ttl) + { + PhySocketImpl& sws = *(reinterpret_cast(sock)); #if defined(_WIN32) || defined(_WIN64) - DWORD tmp = ((ttl == 0)||(ttl > 255)) ? 255 : (DWORD)ttl; - return (::setsockopt(sws.sock,IPPROTO_IP,IP_TTL,(const char *)&tmp,sizeof(tmp)) == 0); + DWORD tmp = ((ttl == 0) || (ttl > 255)) ? 255 : (DWORD)ttl; + return (::setsockopt(sws.sock, IPPROTO_IP, IP_TTL, (const char*)&tmp, sizeof(tmp)) == 0); #else - int tmp = ((ttl == 0)||(ttl > 255)) ? 255 : (int)ttl; - return (::setsockopt(sws.sock,IPPROTO_IP,IP_TTL,(void *)&tmp,sizeof(tmp)) == 0); + int tmp = ((ttl == 0) || (ttl > 255)) ? 255 : (int)ttl; + return (::setsockopt(sws.sock, IPPROTO_IP, IP_TTL, (void*)&tmp, sizeof(tmp)) == 0); #endif - } + } - /** - * Send a UDP packet - * - * @param sock UDP socket - * @param remoteAddress Destination address (must be correct type for socket) - * @param data Data to send - * @param len Length of packet - * @return True if packet appears to have been sent successfully - */ - inline bool udpSend(PhySocket *sock,const struct sockaddr *remoteAddress,const void *data,unsigned long len) - { - PhySocketImpl &sws = *(reinterpret_cast(sock)); - bool sent = false; + /** + * Send a UDP packet + * + * @param sock UDP socket + * @param remoteAddress Destination address (must be correct type for socket) + * @param data Data to send + * @param len Length of packet + * @return True if packet appears to have been sent successfully + */ + inline bool udpSend(PhySocket* sock, const struct sockaddr* remoteAddress, const void* data, unsigned long len) + { + PhySocketImpl& sws = *(reinterpret_cast(sock)); + bool sent = false; #if defined(_WIN32) || defined(_WIN64) - sent = ((long)::sendto( - sws.sock, - reinterpret_cast(data), - len, - 0, - remoteAddress, - (remoteAddress->sa_family == AF_INET6) ? - sizeof(struct sockaddr_in6) : - sizeof(struct sockaddr_in)) == (long)len); + sent = ((long)::sendto(sws.sock, reinterpret_cast(data), len, 0, remoteAddress, (remoteAddress->sa_family == AF_INET6) ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in)) == (long)len); #else - sent = ((long)::sendto( - sws.sock, - data, - len, - 0, - remoteAddress, - (remoteAddress->sa_family == AF_INET6) ? - sizeof(struct sockaddr_in6) : - sizeof(struct sockaddr_in)) == (long)len); + sent = ((long)::sendto(sws.sock, data, len, 0, remoteAddress, (remoteAddress->sa_family == AF_INET6) ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in)) == (long)len); #endif - if (sent) { - Metrics::udp_send += len; - } + if (sent) { + Metrics::udp_send += len; + } - return sent; - } + return sent; + } #ifdef __UNIX_LIKE__ - /** - * Listen for connections on a Unix domain socket - * - * @param path Path to Unix domain socket - * @param uptr Arbitrary pointer to associate - * @return PhySocket or NULL if cannot bind - */ - inline PhySocket *unixListen(const char *path,void *uptr = (void *)0) - { - struct sockaddr_un sun; + /** + * Listen for connections on a Unix domain socket + * + * @param path Path to Unix domain socket + * @param uptr Arbitrary pointer to associate + * @return PhySocket or NULL if cannot bind + */ + inline PhySocket* unixListen(const char* path, void* uptr = (void*)0) + { + struct sockaddr_un sun; - if (_socks.size() >= ZT_PHY_MAX_SOCKETS) - return (PhySocket *)0; + if (_socks.size() >= ZT_PHY_MAX_SOCKETS) + return (PhySocket*)0; - memset(&sun,0,sizeof(sun)); - sun.sun_family = AF_UNIX; - if (strlen(path) >= sizeof(sun.sun_path)) - return (PhySocket *)0; - strcpy(sun.sun_path,path); + memset(&sun, 0, sizeof(sun)); + sun.sun_family = AF_UNIX; + if (strlen(path) >= sizeof(sun.sun_path)) + return (PhySocket*)0; + strcpy(sun.sun_path, path); - ZT_PHY_SOCKFD_TYPE s = ::socket(PF_UNIX,SOCK_STREAM,0); - if (!ZT_PHY_SOCKFD_VALID(s)) - return (PhySocket *)0; + ZT_PHY_SOCKFD_TYPE s = ::socket(PF_UNIX, SOCK_STREAM, 0); + if (! ZT_PHY_SOCKFD_VALID(s)) + return (PhySocket*)0; - ::fcntl(s,F_SETFL,O_NONBLOCK); + ::fcntl(s, F_SETFL, O_NONBLOCK); - ::unlink(path); - if (::bind(s,(struct sockaddr *)&sun,sizeof(struct sockaddr_un)) != 0) { - ZT_PHY_CLOSE_SOCKET(s); - return (PhySocket *)0; - } - if (::listen(s,128) != 0) { - ZT_PHY_CLOSE_SOCKET(s); - return (PhySocket *)0; - } + ::unlink(path); + if (::bind(s, (struct sockaddr*)&sun, sizeof(struct sockaddr_un)) != 0) { + ZT_PHY_CLOSE_SOCKET(s); + return (PhySocket*)0; + } + if (::listen(s, 128) != 0) { + ZT_PHY_CLOSE_SOCKET(s); + return (PhySocket*)0; + } - try { - _socks.push_back(PhySocketImpl()); - } catch ( ... ) { - ZT_PHY_CLOSE_SOCKET(s); - return (PhySocket *)0; - } - PhySocketImpl &sws = _socks.back(); + try { + _socks.push_back(PhySocketImpl()); + } + catch (...) { + ZT_PHY_CLOSE_SOCKET(s); + return (PhySocket*)0; + } + PhySocketImpl& sws = _socks.back(); - if ((long)s > _nfds) - _nfds = (long)s; - FD_SET(s,&_readfds); - sws.type = ZT_PHY_SOCKET_UNIX_LISTEN; - sws.sock = s; - sws.uptr = uptr; - memset(&(sws.saddr),0,sizeof(struct sockaddr_storage)); - memcpy(&(sws.saddr),&sun,sizeof(struct sockaddr_un)); + if ((long)s > _nfds) + _nfds = (long)s; + FD_SET(s, &_readfds); + sws.type = ZT_PHY_SOCKET_UNIX_LISTEN; + sws.sock = s; + sws.uptr = uptr; + memset(&(sws.saddr), 0, sizeof(struct sockaddr_storage)); + memcpy(&(sws.saddr), &sun, sizeof(struct sockaddr_un)); - return (PhySocket *)&sws; - } -#endif // __UNIX_LIKE__ + return (PhySocket*)&sws; + } +#endif // __UNIX_LIKE__ - /** - * Bind a local listen socket to listen for new TCP connections - * - * @param localAddress Local address and port - * @param uptr Initial value of uptr for new socket (default: NULL) - * @return Socket or NULL on failure to bind - */ - inline PhySocket *tcpListen(const struct sockaddr *localAddress,void *uptr = (void *)0) - { - if (_socks.size() >= ZT_PHY_MAX_SOCKETS) - return (PhySocket *)0; + /** + * Bind a local listen socket to listen for new TCP connections + * + * @param localAddress Local address and port + * @param uptr Initial value of uptr for new socket (default: NULL) + * @return Socket or NULL on failure to bind + */ + inline PhySocket* tcpListen(const struct sockaddr* localAddress, void* uptr = (void*)0) + { + if (_socks.size() >= ZT_PHY_MAX_SOCKETS) + return (PhySocket*)0; - ZT_PHY_SOCKFD_TYPE s = ::socket(localAddress->sa_family,SOCK_STREAM,0); - if (!ZT_PHY_SOCKFD_VALID(s)) - return (PhySocket *)0; + ZT_PHY_SOCKFD_TYPE s = ::socket(localAddress->sa_family, SOCK_STREAM, 0); + if (! ZT_PHY_SOCKFD_VALID(s)) + return (PhySocket*)0; #if defined(_WIN32) || defined(_WIN64) - { - BOOL f; - f = TRUE; ::setsockopt(s,IPPROTO_IPV6,IPV6_V6ONLY,(const char *)&f,sizeof(f)); - f = TRUE; ::setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(const char *)&f,sizeof(f)); - f = (_noDelay ? TRUE : FALSE); setsockopt(s,IPPROTO_TCP,TCP_NODELAY,(char *)&f,sizeof(f)); - u_long iMode=1; - ioctlsocket(s,FIONBIO,&iMode); - } + { + BOOL f; + f = TRUE; + ::setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, (const char*)&f, sizeof(f)); + f = TRUE; + ::setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (const char*)&f, sizeof(f)); + f = (_noDelay ? TRUE : FALSE); + setsockopt(s, IPPROTO_TCP, TCP_NODELAY, (char*)&f, sizeof(f)); + u_long iMode = 1; + ioctlsocket(s, FIONBIO, &iMode); + } #else - { - int f; - f = 1; ::setsockopt(s,IPPROTO_IPV6,IPV6_V6ONLY,(void *)&f,sizeof(f)); - f = 1; ::setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(void *)&f,sizeof(f)); - f = (_noDelay ? 1 : 0); setsockopt(s,IPPROTO_TCP,TCP_NODELAY,(char *)&f,sizeof(f)); - fcntl(s,F_SETFL,O_NONBLOCK); - } + { + int f; + f = 1; + ::setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, (void*)&f, sizeof(f)); + f = 1; + ::setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (void*)&f, sizeof(f)); + f = (_noDelay ? 1 : 0); + setsockopt(s, IPPROTO_TCP, TCP_NODELAY, (char*)&f, sizeof(f)); + fcntl(s, F_SETFL, O_NONBLOCK); + } #endif - if (::bind(s,localAddress,(localAddress->sa_family == AF_INET6) ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in))) { - ZT_PHY_CLOSE_SOCKET(s); - return (PhySocket *)0; - } + if (::bind(s, localAddress, (localAddress->sa_family == AF_INET6) ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in))) { + ZT_PHY_CLOSE_SOCKET(s); + return (PhySocket*)0; + } - if (::listen(s,1024)) { - ZT_PHY_CLOSE_SOCKET(s); - return (PhySocket *)0; - } + if (::listen(s, 1024)) { + ZT_PHY_CLOSE_SOCKET(s); + return (PhySocket*)0; + } - try { - _socks.push_back(PhySocketImpl()); - } catch ( ... ) { - ZT_PHY_CLOSE_SOCKET(s); - return (PhySocket *)0; - } - PhySocketImpl &sws = _socks.back(); + try { + _socks.push_back(PhySocketImpl()); + } + catch (...) { + ZT_PHY_CLOSE_SOCKET(s); + return (PhySocket*)0; + } + PhySocketImpl& sws = _socks.back(); - if ((long)s > _nfds) - _nfds = (long)s; - FD_SET(s,&_readfds); - sws.type = ZT_PHY_SOCKET_TCP_LISTEN; - sws.sock = s; - sws.uptr = uptr; - memset(&(sws.saddr),0,sizeof(struct sockaddr_storage)); - memcpy(&(sws.saddr),localAddress,(localAddress->sa_family == AF_INET6) ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in)); + if ((long)s > _nfds) + _nfds = (long)s; + FD_SET(s, &_readfds); + sws.type = ZT_PHY_SOCKET_TCP_LISTEN; + sws.sock = s; + sws.uptr = uptr; + memset(&(sws.saddr), 0, sizeof(struct sockaddr_storage)); + memcpy(&(sws.saddr), localAddress, (localAddress->sa_family == AF_INET6) ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in)); - return (PhySocket *)&sws; - } + return (PhySocket*)&sws; + } - /** - * Start a non-blocking connect; CONNECT handler is called on success or failure - * - * A return value of NULL indicates a synchronous failure such as a - * failure to open a socket. The TCP connection handler is not called - * in this case. - * - * It is possible on some platforms for an "instant connect" to occur, - * such as when connecting to a loopback address. In this case, the - * 'connected' result parameter will be set to 'true' and if the - * 'callConnectHandler' flag is true (the default) the TCP connect - * handler will be called before the function returns. - * - * These semantics can be a bit confusing, but they're less so than - * the underlying semantics of asynchronous TCP connect. - * - * @param remoteAddress Remote address - * @param connected Result parameter: set to whether an "instant connect" has occurred (true if yes) - * @param uptr Initial value of uptr for new socket (default: NULL) - * @param callConnectHandler If true, call TCP connect handler even if result is known before function exit (default: true) - * @return New socket or NULL on failure - */ - inline PhySocket *tcpConnect(const struct sockaddr *remoteAddress,bool &connected,void *uptr = (void *)0,bool callConnectHandler = true) - { - if (_socks.size() >= ZT_PHY_MAX_SOCKETS) - return (PhySocket *)0; + /** + * Start a non-blocking connect; CONNECT handler is called on success or failure + * + * A return value of NULL indicates a synchronous failure such as a + * failure to open a socket. The TCP connection handler is not called + * in this case. + * + * It is possible on some platforms for an "instant connect" to occur, + * such as when connecting to a loopback address. In this case, the + * 'connected' result parameter will be set to 'true' and if the + * 'callConnectHandler' flag is true (the default) the TCP connect + * handler will be called before the function returns. + * + * These semantics can be a bit confusing, but they're less so than + * the underlying semantics of asynchronous TCP connect. + * + * @param remoteAddress Remote address + * @param connected Result parameter: set to whether an "instant connect" has occurred (true if yes) + * @param uptr Initial value of uptr for new socket (default: NULL) + * @param callConnectHandler If true, call TCP connect handler even if result is known before function exit (default: true) + * @return New socket or NULL on failure + */ + inline PhySocket* tcpConnect(const struct sockaddr* remoteAddress, bool& connected, void* uptr = (void*)0, bool callConnectHandler = true) + { + if (_socks.size() >= ZT_PHY_MAX_SOCKETS) + return (PhySocket*)0; - ZT_PHY_SOCKFD_TYPE s = ::socket(remoteAddress->sa_family,SOCK_STREAM,0); - if (!ZT_PHY_SOCKFD_VALID(s)) { - connected = false; - return (PhySocket *)0; - } + ZT_PHY_SOCKFD_TYPE s = ::socket(remoteAddress->sa_family, SOCK_STREAM, 0); + if (! ZT_PHY_SOCKFD_VALID(s)) { + connected = false; + return (PhySocket*)0; + } #if defined(_WIN32) || defined(_WIN64) - { - BOOL f; - if (remoteAddress->sa_family == AF_INET6) { f = TRUE; ::setsockopt(s,IPPROTO_IPV6,IPV6_V6ONLY,(const char *)&f,sizeof(f)); } - f = TRUE; ::setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(const char *)&f,sizeof(f)); - f = (_noDelay ? TRUE : FALSE); setsockopt(s,IPPROTO_TCP,TCP_NODELAY,(char *)&f,sizeof(f)); - u_long iMode=1; - ioctlsocket(s,FIONBIO,&iMode); - } + { + BOOL f; + if (remoteAddress->sa_family == AF_INET6) { + f = TRUE; + ::setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, (const char*)&f, sizeof(f)); + } + f = TRUE; + ::setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (const char*)&f, sizeof(f)); + f = (_noDelay ? TRUE : FALSE); + setsockopt(s, IPPROTO_TCP, TCP_NODELAY, (char*)&f, sizeof(f)); + u_long iMode = 1; + ioctlsocket(s, FIONBIO, &iMode); + } #else - { - int f; - if (remoteAddress->sa_family == AF_INET6) { f = 1; ::setsockopt(s,IPPROTO_IPV6,IPV6_V6ONLY,(void *)&f,sizeof(f)); } - f = 1; ::setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(void *)&f,sizeof(f)); - f = (_noDelay ? 1 : 0); setsockopt(s,IPPROTO_TCP,TCP_NODELAY,(char *)&f,sizeof(f)); - fcntl(s,F_SETFL,O_NONBLOCK); - } + { + int f; + if (remoteAddress->sa_family == AF_INET6) { + f = 1; + ::setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, (void*)&f, sizeof(f)); + } + f = 1; + ::setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (void*)&f, sizeof(f)); + f = (_noDelay ? 1 : 0); + setsockopt(s, IPPROTO_TCP, TCP_NODELAY, (char*)&f, sizeof(f)); + fcntl(s, F_SETFL, O_NONBLOCK); + } #endif - connected = true; - if (::connect(s,remoteAddress,(remoteAddress->sa_family == AF_INET6) ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in))) { - connected = false; + connected = true; + if (::connect(s, remoteAddress, (remoteAddress->sa_family == AF_INET6) ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in))) { + connected = false; #if defined(_WIN32) || defined(_WIN64) - if (WSAGetLastError() != WSAEWOULDBLOCK) { + if (WSAGetLastError() != WSAEWOULDBLOCK) { #else - if (errno != EINPROGRESS) { + if (errno != EINPROGRESS) { #endif - ZT_PHY_CLOSE_SOCKET(s); - return (PhySocket *)0; - } // else connection is proceeding asynchronously... - } + ZT_PHY_CLOSE_SOCKET(s); + return (PhySocket*)0; + } // else connection is proceeding asynchronously... + } - try { - _socks.push_back(PhySocketImpl()); - } catch ( ... ) { - ZT_PHY_CLOSE_SOCKET(s); - return (PhySocket *)0; - } - PhySocketImpl &sws = _socks.back(); + try { + _socks.push_back(PhySocketImpl()); + } + catch (...) { + ZT_PHY_CLOSE_SOCKET(s); + return (PhySocket*)0; + } + PhySocketImpl& sws = _socks.back(); - if ((long)s > _nfds) - _nfds = (long)s; - if (connected) { - FD_SET(s,&_readfds); - sws.type = ZT_PHY_SOCKET_TCP_OUT_CONNECTED; - } else { - FD_SET(s,&_writefds); + if ((long)s > _nfds) + _nfds = (long)s; + if (connected) { + FD_SET(s, &_readfds); + sws.type = ZT_PHY_SOCKET_TCP_OUT_CONNECTED; + } + else { + FD_SET(s, &_writefds); #if defined(_WIN32) || defined(_WIN64) - FD_SET(s,&_exceptfds); + FD_SET(s, &_exceptfds); #endif - sws.type = ZT_PHY_SOCKET_TCP_OUT_PENDING; - } - sws.sock = s; - sws.uptr = uptr; - memset(&(sws.saddr),0,sizeof(struct sockaddr_storage)); - memcpy(&(sws.saddr),remoteAddress,(remoteAddress->sa_family == AF_INET6) ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in)); + sws.type = ZT_PHY_SOCKET_TCP_OUT_PENDING; + } + sws.sock = s; + sws.uptr = uptr; + memset(&(sws.saddr), 0, sizeof(struct sockaddr_storage)); + memcpy(&(sws.saddr), remoteAddress, (remoteAddress->sa_family == AF_INET6) ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in)); - if ((callConnectHandler)&&(connected)) { - try { - _handler->phyOnTcpConnect((PhySocket *)&sws,&(sws.uptr),true); - } catch ( ... ) {} - } + if ((callConnectHandler) && (connected)) { + try { + _handler->phyOnTcpConnect((PhySocket*)&sws, &(sws.uptr), true); + } + catch (...) { + } + } - return (PhySocket *)&sws; - } + return (PhySocket*)&sws; + } - /** - * Try to set buffer sizes as close to the given value as possible - * - * This will try the specified value and then lower values in 16K increments - * until one works. - * - * @param sock Socket - * @param receiveBufferSize Desired size of receive buffer - * @param sendBufferSize Desired size of send buffer - */ - inline void setBufferSizes(const PhySocket *sock,int receiveBufferSize,int sendBufferSize) - { - PhySocketImpl &sws = *(reinterpret_cast(sock)); - if (receiveBufferSize > 0) { - while (receiveBufferSize > 0) { - int tmpbs = receiveBufferSize; - if (::setsockopt(sws.sock,SOL_SOCKET,SO_RCVBUF,(const char *)&tmpbs,sizeof(tmpbs)) == 0) - break; - receiveBufferSize -= 16384; - } - } - if (sendBufferSize > 0) { - while (sendBufferSize > 0) { - int tmpbs = sendBufferSize; - if (::setsockopt(sws.sock,SOL_SOCKET,SO_SNDBUF,(const char *)&tmpbs,sizeof(tmpbs)) == 0) - break; - sendBufferSize -= 16384; - } - } - } + /** + * Try to set buffer sizes as close to the given value as possible + * + * This will try the specified value and then lower values in 16K increments + * until one works. + * + * @param sock Socket + * @param receiveBufferSize Desired size of receive buffer + * @param sendBufferSize Desired size of send buffer + */ + inline void setBufferSizes(const PhySocket* sock, int receiveBufferSize, int sendBufferSize) + { + PhySocketImpl& sws = *(reinterpret_cast(sock)); + if (receiveBufferSize > 0) { + while (receiveBufferSize > 0) { + int tmpbs = receiveBufferSize; + if (::setsockopt(sws.sock, SOL_SOCKET, SO_RCVBUF, (const char*)&tmpbs, sizeof(tmpbs)) == 0) + break; + receiveBufferSize -= 16384; + } + } + if (sendBufferSize > 0) { + while (sendBufferSize > 0) { + int tmpbs = sendBufferSize; + if (::setsockopt(sws.sock, SOL_SOCKET, SO_SNDBUF, (const char*)&tmpbs, sizeof(tmpbs)) == 0) + break; + sendBufferSize -= 16384; + } + } + } - /** - * Attempt to send data to a stream socket (non-blocking) - * - * If -1 is returned, the socket should no longer be used as it is now - * destroyed. If callCloseHandler is true, the close handler will be - * called before the function returns. - * - * This can be used with TCP, Unix, or socket pair sockets. - * - * @param sock An open stream socket (other socket types will fail) - * @param data Data to send - * @param len Length of data - * @param callCloseHandler If true, call close handler on socket closing failure condition (default: true) - * @return Number of bytes actually sent or -1 on fatal error (socket closure) - */ - inline long streamSend(PhySocket *sock,const void *data,unsigned long len,bool callCloseHandler = true) - { - PhySocketImpl &sws = *(reinterpret_cast(sock)); + /** + * Attempt to send data to a stream socket (non-blocking) + * + * If -1 is returned, the socket should no longer be used as it is now + * destroyed. If callCloseHandler is true, the close handler will be + * called before the function returns. + * + * This can be used with TCP, Unix, or socket pair sockets. + * + * @param sock An open stream socket (other socket types will fail) + * @param data Data to send + * @param len Length of data + * @param callCloseHandler If true, call close handler on socket closing failure condition (default: true) + * @return Number of bytes actually sent or -1 on fatal error (socket closure) + */ + inline long streamSend(PhySocket* sock, const void* data, unsigned long len, bool callCloseHandler = true) + { + PhySocketImpl& sws = *(reinterpret_cast(sock)); #if defined(_WIN32) || defined(_WIN64) - long n = (long)::send(sws.sock,reinterpret_cast(data),len,0); - if (n == SOCKET_ERROR) { - switch(WSAGetLastError()) { - case WSAEINTR: - case WSAEWOULDBLOCK: - return 0; - default: - this->close(sock,callCloseHandler); - return -1; - } - } -#else // not Windows - long n = (long)::send(sws.sock,data,len,0); - if (n < 0) { - switch(errno) { + long n = (long)::send(sws.sock, reinterpret_cast(data), len, 0); + if (n == SOCKET_ERROR) { + switch (WSAGetLastError()) { + case WSAEINTR: + case WSAEWOULDBLOCK: + return 0; + default: + this->close(sock, callCloseHandler); + return -1; + } + } +#else // not Windows + long n = (long)::send(sws.sock, data, len, 0); + if (n < 0) { + switch (errno) { #ifdef EAGAIN - case EAGAIN: + case EAGAIN: #endif -#if defined(EWOULDBLOCK) && ( !defined(EAGAIN) || (EWOULDBLOCK != EAGAIN) ) - case EWOULDBLOCK: +#if defined(EWOULDBLOCK) && (! defined(EAGAIN) || (EWOULDBLOCK != EAGAIN)) + case EWOULDBLOCK: #endif #ifdef EINTR - case EINTR: + case EINTR: #endif - return 0; - default: - this->close(sock,callCloseHandler); - return -1; - } - } -#endif // Windows or not - return n; - } + return 0; + default: + this->close(sock, callCloseHandler); + return -1; + } + } +#endif // Windows or not + return n; + } #ifdef __UNIX_LIKE__ - /** - * Attempt to send data to a Unix domain socket connection (non-blocking) - * - * If -1 is returned, the socket should no longer be used as it is now - * destroyed. If callCloseHandler is true, the close handler will be - * called before the function returns. - * - * @param sock An open Unix socket (other socket types will fail) - * @param data Data to send - * @param len Length of data - * @param callCloseHandler If true, call close handler on socket closing failure condition (default: true) - * @return Number of bytes actually sent or -1 on fatal error (socket closure) - */ - inline long unixSend(PhySocket *sock,const void *data,unsigned long len,bool callCloseHandler = true) - { - PhySocketImpl &sws = *(reinterpret_cast(sock)); - long n = (long)::write(sws.sock,data,len); - if (n < 0) { - switch(errno) { + /** + * Attempt to send data to a Unix domain socket connection (non-blocking) + * + * If -1 is returned, the socket should no longer be used as it is now + * destroyed. If callCloseHandler is true, the close handler will be + * called before the function returns. + * + * @param sock An open Unix socket (other socket types will fail) + * @param data Data to send + * @param len Length of data + * @param callCloseHandler If true, call close handler on socket closing failure condition (default: true) + * @return Number of bytes actually sent or -1 on fatal error (socket closure) + */ + inline long unixSend(PhySocket* sock, const void* data, unsigned long len, bool callCloseHandler = true) + { + PhySocketImpl& sws = *(reinterpret_cast(sock)); + long n = (long)::write(sws.sock, data, len); + if (n < 0) { + switch (errno) { #ifdef EAGAIN - case EAGAIN: + case EAGAIN: #endif -#if defined(EWOULDBLOCK) && ( !defined(EAGAIN) || (EWOULDBLOCK != EAGAIN) ) - case EWOULDBLOCK: +#if defined(EWOULDBLOCK) && (! defined(EAGAIN) || (EWOULDBLOCK != EAGAIN)) + case EWOULDBLOCK: #endif #ifdef EINTR - case EINTR: + case EINTR: #endif - return 0; - default: - this->close(sock,callCloseHandler); - return -1; - } - } - return n; - } -#endif // __UNIX_LIKE__ + return 0; + default: + this->close(sock, callCloseHandler); + return -1; + } + } + return n; + } +#endif // __UNIX_LIKE__ - /** - * For streams, sets whether we want to be notified that the socket is writable - * - * This can be used with TCP, Unix, or socket pair sockets. - * - * Call whack() if this is being done from another thread and you want - * it to take effect immediately. Otherwise it is only guaranteed to - * take effect on the next poll(). - * - * @param sock Stream connection socket - * @param notifyWritable Want writable notifications? - */ - inline void setNotifyWritable(PhySocket *sock,bool notifyWritable) - { - PhySocketImpl &sws = *(reinterpret_cast(sock)); - if (notifyWritable) { - FD_SET(sws.sock,&_writefds); - } else { - FD_CLR(sws.sock,&_writefds); - } - } + /** + * For streams, sets whether we want to be notified that the socket is writable + * + * This can be used with TCP, Unix, or socket pair sockets. + * + * Call whack() if this is being done from another thread and you want + * it to take effect immediately. Otherwise it is only guaranteed to + * take effect on the next poll(). + * + * @param sock Stream connection socket + * @param notifyWritable Want writable notifications? + */ + inline void setNotifyWritable(PhySocket* sock, bool notifyWritable) + { + PhySocketImpl& sws = *(reinterpret_cast(sock)); + if (notifyWritable) { + FD_SET(sws.sock, &_writefds); + } + else { + FD_CLR(sws.sock, &_writefds); + } + } - /** - * Set whether we want to be notified that a socket is readable - * - * This is primarily for raw sockets added with wrapSocket(). It could be - * used with others, but doing so would essentially lock them and prevent - * data from being read from them until this is set to 'true' again. - * - * @param sock Socket to modify - * @param notifyReadable True if socket should be monitored for readability - */ - inline void setNotifyReadable(PhySocket *sock,bool notifyReadable) - { - PhySocketImpl &sws = *(reinterpret_cast(sock)); - if (notifyReadable) { - FD_SET(sws.sock,&_readfds); - } else { - FD_CLR(sws.sock,&_readfds); - } - } + /** + * Set whether we want to be notified that a socket is readable + * + * This is primarily for raw sockets added with wrapSocket(). It could be + * used with others, but doing so would essentially lock them and prevent + * data from being read from them until this is set to 'true' again. + * + * @param sock Socket to modify + * @param notifyReadable True if socket should be monitored for readability + */ + inline void setNotifyReadable(PhySocket* sock, bool notifyReadable) + { + PhySocketImpl& sws = *(reinterpret_cast(sock)); + if (notifyReadable) { + FD_SET(sws.sock, &_readfds); + } + else { + FD_CLR(sws.sock, &_readfds); + } + } - /** - * Wait for activity and handle one or more events - * - * Note that this is not guaranteed to wait up to 'timeout' even - * if nothing happens, as whack() or other events such as signals - * may cause premature termination. - * - * @param timeout Timeout in milliseconds or 0 for none (forever) - */ - inline void poll(unsigned long timeout) - { - char buf[131072]; - struct sockaddr_storage ss; - struct timeval tv; - fd_set rfds,wfds,efds; + /** + * Wait for activity and handle one or more events + * + * Note that this is not guaranteed to wait up to 'timeout' even + * if nothing happens, as whack() or other events such as signals + * may cause premature termination. + * + * @param timeout Timeout in milliseconds or 0 for none (forever) + */ + inline void poll(unsigned long timeout) + { + char buf[131072]; + struct sockaddr_storage ss; + struct timeval tv; + fd_set rfds, wfds, efds; - memcpy(&rfds,&_readfds,sizeof(rfds)); - memcpy(&wfds,&_writefds,sizeof(wfds)); + memcpy(&rfds, &_readfds, sizeof(rfds)); + memcpy(&wfds, &_writefds, sizeof(wfds)); #if defined(_WIN32) || defined(_WIN64) - memcpy(&efds,&_exceptfds,sizeof(efds)); + memcpy(&efds, &_exceptfds, sizeof(efds)); #else - FD_ZERO(&efds); + FD_ZERO(&efds); #endif - tv.tv_sec = (long)(timeout / 1000); - tv.tv_usec = (long)((timeout % 1000) * 1000); - if (::select((int)_nfds + 1,&rfds,&wfds,&efds,(timeout > 0) ? &tv : (struct timeval *)0) <= 0) - return; + tv.tv_sec = (long)(timeout / 1000); + tv.tv_usec = (long)((timeout % 1000) * 1000); + if (::select((int)_nfds + 1, &rfds, &wfds, &efds, (timeout > 0) ? &tv : (struct timeval*)0) <= 0) + return; - if (FD_ISSET(_whackReceiveSocket,&rfds)) { - char tmp[16]; + if (FD_ISSET(_whackReceiveSocket, &rfds)) { + char tmp[16]; #if defined(_WIN32) || defined(_WIN64) - ::recv(_whackReceiveSocket,tmp,16,0); + ::recv(_whackReceiveSocket, tmp, 16, 0); #else - ::read(_whackReceiveSocket,tmp,16); + ::read(_whackReceiveSocket, tmp, 16); #endif - } + } - for(typename std::list::iterator s(_socks.begin());s!=_socks.end();) { - switch (s->type) { - - case ZT_PHY_SOCKET_TCP_OUT_PENDING: + for (typename std::list::iterator s(_socks.begin()); s != _socks.end();) { + switch (s->type) { + case ZT_PHY_SOCKET_TCP_OUT_PENDING: #if defined(_WIN32) || defined(_WIN64) - if (FD_ISSET(s->sock,&efds)) { - this->close((PhySocket *)&(*s),true); - } else // ... if + if (FD_ISSET(s->sock, &efds)) { + this->close((PhySocket*)&(*s), true); + } + else // ... if #endif - if (FD_ISSET(s->sock,&wfds)) { - socklen_t slen = sizeof(ss); - if (::getpeername(s->sock,(struct sockaddr *)&ss,&slen) != 0) { - this->close((PhySocket *)&(*s),true); - } else { - s->type = ZT_PHY_SOCKET_TCP_OUT_CONNECTED; - FD_SET(s->sock,&_readfds); - FD_CLR(s->sock,&_writefds); + if (FD_ISSET(s->sock, &wfds)) { + socklen_t slen = sizeof(ss); + if (::getpeername(s->sock, (struct sockaddr*)&ss, &slen) != 0) { + this->close((PhySocket*)&(*s), true); + } + else { + s->type = ZT_PHY_SOCKET_TCP_OUT_CONNECTED; + FD_SET(s->sock, &_readfds); + FD_CLR(s->sock, &_writefds); #if defined(_WIN32) || defined(_WIN64) - FD_CLR(s->sock,&_exceptfds); + FD_CLR(s->sock, &_exceptfds); #endif - try { - _handler->phyOnTcpConnect((PhySocket *)&(*s),&(s->uptr),true); - } catch ( ... ) {} - } - } - break; + try { + _handler->phyOnTcpConnect((PhySocket*)&(*s), &(s->uptr), true); + } + catch (...) { + } + } + } + break; - case ZT_PHY_SOCKET_TCP_OUT_CONNECTED: - case ZT_PHY_SOCKET_TCP_IN: { - ZT_PHY_SOCKFD_TYPE sock = s->sock; // if closed, s->sock becomes invalid as s is no longer dereferencable - if (FD_ISSET(sock,&rfds)) { - long n = (long)::recv(sock,buf,sizeof(buf),0); - if (n <= 0) { - this->close((PhySocket *)&(*s),true); - } else { - try { - _handler->phyOnTcpData((PhySocket *)&(*s),&(s->uptr),(void *)buf,(unsigned long)n); - } catch ( ... ) {} - } - } - if ((FD_ISSET(sock,&wfds))&&(FD_ISSET(sock,&_writefds))) { - try { - _handler->phyOnTcpWritable((PhySocket *)&(*s),&(s->uptr)); - } catch ( ... ) {} - } - } break; + case ZT_PHY_SOCKET_TCP_OUT_CONNECTED: + case ZT_PHY_SOCKET_TCP_IN: { + ZT_PHY_SOCKFD_TYPE sock = s->sock; // if closed, s->sock becomes invalid as s is no longer dereferencable + if (FD_ISSET(sock, &rfds)) { + long n = (long)::recv(sock, buf, sizeof(buf), 0); + if (n <= 0) { + this->close((PhySocket*)&(*s), true); + } + else { + try { + _handler->phyOnTcpData((PhySocket*)&(*s), &(s->uptr), (void*)buf, (unsigned long)n); + } + catch (...) { + } + } + } + if ((FD_ISSET(sock, &wfds)) && (FD_ISSET(sock, &_writefds))) { + try { + _handler->phyOnTcpWritable((PhySocket*)&(*s), &(s->uptr)); + } + catch (...) { + } + } + } break; - case ZT_PHY_SOCKET_TCP_LISTEN: - if (FD_ISSET(s->sock,&rfds)) { - memset(&ss,0,sizeof(ss)); - socklen_t slen = sizeof(ss); - ZT_PHY_SOCKFD_TYPE newSock = ::accept(s->sock,(struct sockaddr *)&ss,&slen); - if (ZT_PHY_SOCKFD_VALID(newSock)) { - if (_socks.size() >= ZT_PHY_MAX_SOCKETS) { - ZT_PHY_CLOSE_SOCKET(newSock); - } else { + case ZT_PHY_SOCKET_TCP_LISTEN: + if (FD_ISSET(s->sock, &rfds)) { + memset(&ss, 0, sizeof(ss)); + socklen_t slen = sizeof(ss); + ZT_PHY_SOCKFD_TYPE newSock = ::accept(s->sock, (struct sockaddr*)&ss, &slen); + if (ZT_PHY_SOCKFD_VALID(newSock)) { + if (_socks.size() >= ZT_PHY_MAX_SOCKETS) { + ZT_PHY_CLOSE_SOCKET(newSock); + } + else { #if defined(_WIN32) || defined(_WIN64) - { BOOL f = (_noDelay ? TRUE : FALSE); setsockopt(newSock,IPPROTO_TCP,TCP_NODELAY,(char *)&f,sizeof(f)); } - { u_long iMode=1; ioctlsocket(newSock,FIONBIO,&iMode); } + { + BOOL f = (_noDelay ? TRUE : FALSE); + setsockopt(newSock, IPPROTO_TCP, TCP_NODELAY, (char*)&f, sizeof(f)); + } + { + u_long iMode = 1; + ioctlsocket(newSock, FIONBIO, &iMode); + } #else - { int f = (_noDelay ? 1 : 0); setsockopt(newSock,IPPROTO_TCP,TCP_NODELAY,(char *)&f,sizeof(f)); } - fcntl(newSock,F_SETFL,O_NONBLOCK); + { + int f = (_noDelay ? 1 : 0); + setsockopt(newSock, IPPROTO_TCP, TCP_NODELAY, (char*)&f, sizeof(f)); + } + fcntl(newSock, F_SETFL, O_NONBLOCK); #endif - _socks.push_back(PhySocketImpl()); - PhySocketImpl &sws = _socks.back(); - FD_SET(newSock,&_readfds); - if ((long)newSock > _nfds) - _nfds = (long)newSock; - sws.type = ZT_PHY_SOCKET_TCP_IN; - sws.sock = newSock; - sws.uptr = (void *)0; - memcpy(&(sws.saddr),&ss,sizeof(struct sockaddr_storage)); - try { - _handler->phyOnTcpAccept((PhySocket *)&(*s),(PhySocket *)&(_socks.back()),&(s->uptr),&(sws.uptr),(const struct sockaddr *)&(sws.saddr)); - } catch ( ... ) {} - } - } - } - break; + _socks.push_back(PhySocketImpl()); + PhySocketImpl& sws = _socks.back(); + FD_SET(newSock, &_readfds); + if ((long)newSock > _nfds) + _nfds = (long)newSock; + sws.type = ZT_PHY_SOCKET_TCP_IN; + sws.sock = newSock; + sws.uptr = (void*)0; + memcpy(&(sws.saddr), &ss, sizeof(struct sockaddr_storage)); + try { + _handler->phyOnTcpAccept((PhySocket*)&(*s), (PhySocket*)&(_socks.back()), &(s->uptr), &(sws.uptr), (const struct sockaddr*)&(sws.saddr)); + } + catch (...) { + } + } + } + } + break; - case ZT_PHY_SOCKET_UDP: - if (FD_ISSET(s->sock, &rfds)) { + case ZT_PHY_SOCKET_UDP: + if (FD_ISSET(s->sock, &rfds)) { #if (defined(__linux__) || defined(linux) || defined(__linux)) && defined(MSG_WAITFORONE) #define RECVMMSG_WINDOW_SIZE 128 -#define RECVMMSG_BUF_SIZE 1500 - iovec iovs[RECVMMSG_WINDOW_SIZE]; - uint8_t bufs[RECVMMSG_WINDOW_SIZE][RECVMMSG_BUF_SIZE]; - sockaddr_storage addrs[RECVMMSG_WINDOW_SIZE]; - memset(addrs, 0, sizeof(addrs)); - mmsghdr mm[RECVMMSG_WINDOW_SIZE]; - memset(mm, 0, sizeof(mm)); - for (int i = 0; i < RECVMMSG_WINDOW_SIZE; ++i) { - iovs[i].iov_base = (void*)bufs[i]; - iovs[i].iov_len = RECVMMSG_BUF_SIZE; - mm[i].msg_hdr.msg_name = (void*)&(addrs[i]); - mm[i].msg_hdr.msg_iov = &(iovs[i]); - mm[i].msg_hdr.msg_iovlen = 1; - } - for (int k = 0; k < 1024; ++k) { - for (int i = 0; i < RECVMMSG_WINDOW_SIZE; ++i) { - mm[i].msg_hdr.msg_namelen = sizeof(sockaddr_storage); - mm[i].msg_len = 0; - } - int received_count = recvmmsg(s->sock, mm, RECVMMSG_WINDOW_SIZE, MSG_WAITFORONE, nullptr); - if (received_count > 0) { - for (int i = 0; i < received_count; ++i) { - long n = (long)mm[i].msg_len; - if (n > 0) { - try { - _handler->phyOnDatagram((PhySocket*)&(*s), &(s->uptr), (const struct sockaddr*)&(s->saddr), (const struct sockaddr*)&(addrs[i]), bufs[i], (unsigned long)n); - } - catch (...) { - } - } - } - } - else { - break; - } - } +#define RECVMMSG_BUF_SIZE 1500 + iovec iovs[RECVMMSG_WINDOW_SIZE]; + uint8_t bufs[RECVMMSG_WINDOW_SIZE][RECVMMSG_BUF_SIZE]; + sockaddr_storage addrs[RECVMMSG_WINDOW_SIZE]; + memset(addrs, 0, sizeof(addrs)); + mmsghdr mm[RECVMMSG_WINDOW_SIZE]; + memset(mm, 0, sizeof(mm)); + for (int i = 0; i < RECVMMSG_WINDOW_SIZE; ++i) { + iovs[i].iov_base = (void*)bufs[i]; + iovs[i].iov_len = RECVMMSG_BUF_SIZE; + mm[i].msg_hdr.msg_name = (void*)&(addrs[i]); + mm[i].msg_hdr.msg_iov = &(iovs[i]); + mm[i].msg_hdr.msg_iovlen = 1; + } + for (int k = 0; k < 1024; ++k) { + for (int i = 0; i < RECVMMSG_WINDOW_SIZE; ++i) { + mm[i].msg_hdr.msg_namelen = sizeof(sockaddr_storage); + mm[i].msg_len = 0; + } + int received_count = recvmmsg(s->sock, mm, RECVMMSG_WINDOW_SIZE, MSG_WAITFORONE, nullptr); + if (received_count > 0) { + for (int i = 0; i < received_count; ++i) { + long n = (long)mm[i].msg_len; + if (n > 0) { + try { + _handler->phyOnDatagram((PhySocket*)&(*s), &(s->uptr), (const struct sockaddr*)&(s->saddr), (const struct sockaddr*)&(addrs[i]), bufs[i], (unsigned long)n); + } + catch (...) { + } + } + } + } + else { + break; + } + } #else - for (int k = 0; k < 1024; ++k) { - memset(&ss, 0, sizeof(ss)); - socklen_t slen = sizeof(ss); - long n = (long)::recvfrom(s->sock, buf, sizeof(buf), 0, (struct sockaddr*)&ss, &slen); - if (n > 0) { - try { - _handler->phyOnDatagram((PhySocket*)&(*s), &(s->uptr), (const struct sockaddr*)&(s->saddr), (const struct sockaddr*)&ss, (void*)buf, (unsigned long)n); - } - catch (...) { - } - } - else if (n < 0) - break; - } + for (int k = 0; k < 1024; ++k) { + memset(&ss, 0, sizeof(ss)); + socklen_t slen = sizeof(ss); + long n = (long)::recvfrom(s->sock, buf, sizeof(buf), 0, (struct sockaddr*)&ss, &slen); + if (n > 0) { + try { + _handler->phyOnDatagram((PhySocket*)&(*s), &(s->uptr), (const struct sockaddr*)&(s->saddr), (const struct sockaddr*)&ss, (void*)buf, (unsigned long)n); + } + catch (...) { + } + } + else if (n < 0) + break; + } #endif - } - break; + } + break; - case ZT_PHY_SOCKET_UNIX_IN: { + case ZT_PHY_SOCKET_UNIX_IN: { #ifdef __UNIX_LIKE__ - ZT_PHY_SOCKFD_TYPE sock = s->sock; // if closed, s->sock becomes invalid as s is no longer dereferencable - if ((FD_ISSET(sock,&wfds))&&(FD_ISSET(sock,&_writefds))) { - try { - _handler->phyOnUnixWritable((PhySocket *)&(*s),&(s->uptr)); - } catch ( ... ) {} - } - if (FD_ISSET(sock,&rfds)) { - long n = (long)::read(sock,buf,sizeof(buf)); - if (n <= 0) { - this->close((PhySocket *)&(*s),true); - } else { - try { - _handler->phyOnUnixData((PhySocket *)&(*s),&(s->uptr),(void *)buf,(unsigned long)n); - } catch ( ... ) {} - } - } -#endif // __UNIX_LIKE__ - } break; + ZT_PHY_SOCKFD_TYPE sock = s->sock; // if closed, s->sock becomes invalid as s is no longer dereferencable + if ((FD_ISSET(sock, &wfds)) && (FD_ISSET(sock, &_writefds))) { + try { + _handler->phyOnUnixWritable((PhySocket*)&(*s), &(s->uptr)); + } + catch (...) { + } + } + if (FD_ISSET(sock, &rfds)) { + long n = (long)::read(sock, buf, sizeof(buf)); + if (n <= 0) { + this->close((PhySocket*)&(*s), true); + } + else { + try { + _handler->phyOnUnixData((PhySocket*)&(*s), &(s->uptr), (void*)buf, (unsigned long)n); + } + catch (...) { + } + } + } +#endif // __UNIX_LIKE__ + } break; - case ZT_PHY_SOCKET_UNIX_LISTEN: + case ZT_PHY_SOCKET_UNIX_LISTEN: #ifdef __UNIX_LIKE__ - if (FD_ISSET(s->sock,&rfds)) { - memset(&ss,0,sizeof(ss)); - socklen_t slen = sizeof(ss); - ZT_PHY_SOCKFD_TYPE newSock = ::accept(s->sock,(struct sockaddr *)&ss,&slen); - if (ZT_PHY_SOCKFD_VALID(newSock)) { - if (_socks.size() >= ZT_PHY_MAX_SOCKETS) { - ZT_PHY_CLOSE_SOCKET(newSock); - } else { - fcntl(newSock,F_SETFL,O_NONBLOCK); - _socks.push_back(PhySocketImpl()); - PhySocketImpl &sws = _socks.back(); - FD_SET(newSock,&_readfds); - if ((long)newSock > _nfds) - _nfds = (long)newSock; - sws.type = ZT_PHY_SOCKET_UNIX_IN; - sws.sock = newSock; - sws.uptr = (void *)0; - memcpy(&(sws.saddr),&ss,sizeof(struct sockaddr_storage)); - try { - //_handler->phyOnUnixAccept((PhySocket *)&(*s),(PhySocket *)&(_socks.back()),&(s->uptr),&(sws.uptr)); - } catch ( ... ) {} - } - } - } -#endif // __UNIX_LIKE__ - break; + if (FD_ISSET(s->sock, &rfds)) { + memset(&ss, 0, sizeof(ss)); + socklen_t slen = sizeof(ss); + ZT_PHY_SOCKFD_TYPE newSock = ::accept(s->sock, (struct sockaddr*)&ss, &slen); + if (ZT_PHY_SOCKFD_VALID(newSock)) { + if (_socks.size() >= ZT_PHY_MAX_SOCKETS) { + ZT_PHY_CLOSE_SOCKET(newSock); + } + else { + fcntl(newSock, F_SETFL, O_NONBLOCK); + _socks.push_back(PhySocketImpl()); + PhySocketImpl& sws = _socks.back(); + FD_SET(newSock, &_readfds); + if ((long)newSock > _nfds) + _nfds = (long)newSock; + sws.type = ZT_PHY_SOCKET_UNIX_IN; + sws.sock = newSock; + sws.uptr = (void*)0; + memcpy(&(sws.saddr), &ss, sizeof(struct sockaddr_storage)); + try { + //_handler->phyOnUnixAccept((PhySocket *)&(*s),(PhySocket *)&(_socks.back()),&(s->uptr),&(sws.uptr)); + } + catch (...) { + } + } + } + } +#endif // __UNIX_LIKE__ + break; - case ZT_PHY_SOCKET_FD: { - ZT_PHY_SOCKFD_TYPE sock = s->sock; - const bool readable = ((FD_ISSET(sock,&rfds))&&(FD_ISSET(sock,&_readfds))); - const bool writable = ((FD_ISSET(sock,&wfds))&&(FD_ISSET(sock,&_writefds))); - if ((readable)||(writable)) { - try { - //_handler->phyOnFileDescriptorActivity((PhySocket *)&(*s),&(s->uptr),readable,writable); - } catch ( ... ) {} - } - } break; + case ZT_PHY_SOCKET_FD: { + ZT_PHY_SOCKFD_TYPE sock = s->sock; + const bool readable = ((FD_ISSET(sock, &rfds)) && (FD_ISSET(sock, &_readfds))); + const bool writable = ((FD_ISSET(sock, &wfds)) && (FD_ISSET(sock, &_writefds))); + if ((readable) || (writable)) { + try { + //_handler->phyOnFileDescriptorActivity((PhySocket *)&(*s),&(s->uptr),readable,writable); + } + catch (...) { + } + } + } break; - default: - break; + default: + break; + } - } + if (s->type == ZT_PHY_SOCKET_CLOSED) + _socks.erase(s++); + else + ++s; + } + } - if (s->type == ZT_PHY_SOCKET_CLOSED) - _socks.erase(s++); - else ++s; - } - } + /** + * @param sock Socket to close + * @param callHandlers If true, call handlers for TCP connect (success: false) or close (default: true) + */ + inline void close(PhySocket* sock, bool callHandlers = true) + { + if (! sock) + return; + PhySocketImpl& sws = *(reinterpret_cast(sock)); + if (sws.type == ZT_PHY_SOCKET_CLOSED) + return; - /** - * @param sock Socket to close - * @param callHandlers If true, call handlers for TCP connect (success: false) or close (default: true) - */ - inline void close(PhySocket *sock,bool callHandlers = true) - { - if (!sock) - return; - PhySocketImpl &sws = *(reinterpret_cast(sock)); - if (sws.type == ZT_PHY_SOCKET_CLOSED) - return; - - FD_CLR(sws.sock,&_readfds); - FD_CLR(sws.sock,&_writefds); + FD_CLR(sws.sock, &_readfds); + FD_CLR(sws.sock, &_writefds); #if defined(_WIN32) || defined(_WIN64) - FD_CLR(sws.sock,&_exceptfds); + FD_CLR(sws.sock, &_exceptfds); #endif - if (sws.type != ZT_PHY_SOCKET_FD) - ZT_PHY_CLOSE_SOCKET(sws.sock); + if (sws.type != ZT_PHY_SOCKET_FD) + ZT_PHY_CLOSE_SOCKET(sws.sock); #ifdef __UNIX_LIKE__ - if (sws.type == ZT_PHY_SOCKET_UNIX_LISTEN) - ::unlink(((struct sockaddr_un *)(&(sws.saddr)))->sun_path); -#endif // __UNIX_LIKE__ + if (sws.type == ZT_PHY_SOCKET_UNIX_LISTEN) + ::unlink(((struct sockaddr_un*)(&(sws.saddr)))->sun_path); +#endif // __UNIX_LIKE__ - if (callHandlers) { - switch(sws.type) { - case ZT_PHY_SOCKET_TCP_OUT_PENDING: - try { - _handler->phyOnTcpConnect(sock,&(sws.uptr),false); - } catch ( ... ) {} - break; - case ZT_PHY_SOCKET_TCP_OUT_CONNECTED: - case ZT_PHY_SOCKET_TCP_IN: - try { - _handler->phyOnTcpClose(sock,&(sws.uptr)); - } catch ( ... ) {} - break; - case ZT_PHY_SOCKET_UNIX_IN: + if (callHandlers) { + switch (sws.type) { + case ZT_PHY_SOCKET_TCP_OUT_PENDING: + try { + _handler->phyOnTcpConnect(sock, &(sws.uptr), false); + } + catch (...) { + } + break; + case ZT_PHY_SOCKET_TCP_OUT_CONNECTED: + case ZT_PHY_SOCKET_TCP_IN: + try { + _handler->phyOnTcpClose(sock, &(sws.uptr)); + } + catch (...) { + } + break; + case ZT_PHY_SOCKET_UNIX_IN: #ifdef __UNIX_LIKE__ - try { - _handler->phyOnUnixClose(sock,&(sws.uptr)); - } catch ( ... ) {} -#endif // __UNIX_LIKE__ - break; - default: - break; - } - } + try { + _handler->phyOnUnixClose(sock, &(sws.uptr)); + } + catch (...) { + } +#endif // __UNIX_LIKE__ + break; + default: + break; + } + } - // Causes entry to be deleted from list in poll(), ignored elsewhere - sws.type = ZT_PHY_SOCKET_CLOSED; + // Causes entry to be deleted from list in poll(), ignored elsewhere + sws.type = ZT_PHY_SOCKET_CLOSED; - if ((long)sws.sock >= (long)_nfds) { - long nfds = (long)_whackSendSocket; - if ((long)_whackReceiveSocket > nfds) - nfds = (long)_whackReceiveSocket; - for(typename std::list::iterator s(_socks.begin());s!=_socks.end();++s) { - if ((s->type != ZT_PHY_SOCKET_CLOSED)&&((long)s->sock > nfds)) - nfds = (long)s->sock; - } - _nfds = nfds; - } - } + if ((long)sws.sock >= (long)_nfds) { + long nfds = (long)_whackSendSocket; + if ((long)_whackReceiveSocket > nfds) + nfds = (long)_whackReceiveSocket; + for (typename std::list::iterator s(_socks.begin()); s != _socks.end(); ++s) { + if ((s->type != ZT_PHY_SOCKET_CLOSED) && ((long)s->sock > nfds)) + nfds = (long)s->sock; + } + _nfds = nfds; + } + } }; -} // namespace ZeroTier +} // namespace ZeroTier #endif diff --git a/osdep/PortMapper.cpp b/osdep/PortMapper.cpp index 49e88c8a..bab4bd3d 100644 --- a/osdep/PortMapper.cpp +++ b/osdep/PortMapper.cpp @@ -14,7 +14,7 @@ #ifdef ZT_USE_MINIUPNPC // Uncomment to dump debug messages -//#define ZT_PORTMAPPER_TRACE 1 +// #define ZT_PORTMAPPER_TRACE 1 #ifdef __ANDROID__ #include @@ -23,16 +23,15 @@ #define PM_TRACE(...) fprintf(stderr, __VA_ARGS__) #endif -#include -#include -#include - -#include - #include "../node/Utils.hpp" #include "OSUtils.hpp" #include "PortMapper.hpp" +#include +#include +#include +#include + // These must be defined to get rid of dynamic export stuff in libminiupnpc and libnatpmp #ifdef __WINDOWS__ #ifndef MINIUPNP_STATICLIB @@ -63,296 +62,298 @@ namespace ZeroTier { -class PortMapperImpl -{ -public: - PortMapperImpl(int localUdpPortToMap,const char *un) : - run(true), - localPort(localUdpPortToMap), - uniqueName(un) - { - } +class PortMapperImpl { + public: + PortMapperImpl(int localUdpPortToMap, const char* un) : run(true), localPort(localUdpPortToMap), uniqueName(un) + { + } - ~PortMapperImpl() {} + ~PortMapperImpl() + { + } - void threadMain() - throw() - { - int mode = 0; // 0 == NAT-PMP, 1 == UPnP - int retrytime = 500; + void threadMain() throw() + { + int mode = 0; // 0 == NAT-PMP, 1 == UPnP + int retrytime = 500; #ifdef ZT_PORTMAPPER_TRACE - fprintf(stderr,"PortMapper: started for UDP port %d" ZT_EOL_S,localPort); + fprintf(stderr, "PortMapper: started for UDP port %d" ZT_EOL_S, localPort); #endif - while (run) { - - { - // use initnatpmp to check if we can bind a port at all - natpmp_t _natpmp; - int result = initnatpmp(&_natpmp,0,0); - if (result == NATPMP_ERR_CANNOTGETGATEWAY || result == NATPMP_ERR_SOCKETERROR) { - closenatpmp(&_natpmp); + while (run) { + { + // use initnatpmp to check if we can bind a port at all + natpmp_t _natpmp; + int result = initnatpmp(&_natpmp, 0, 0); + if (result == NATPMP_ERR_CANNOTGETGATEWAY || result == NATPMP_ERR_SOCKETERROR) { + closenatpmp(&_natpmp); #ifdef ZT_PORTMAPPER_TRACE - PM_TRACE("PortMapper: init failed %d. You might not have an internet connection yet. Trying again in %d" ZT_EOL_S, result, retrytime); + PM_TRACE("PortMapper: init failed %d. You might not have an internet connection yet. Trying again in %d" ZT_EOL_S, result, retrytime); #endif - Thread::sleep(retrytime); - retrytime = retrytime * 2; - if (retrytime > ZT_PORTMAPPER_REFRESH_DELAY / 10) { - retrytime = ZT_PORTMAPPER_REFRESH_DELAY / 10; - } - continue; - } else { - closenatpmp(&_natpmp); - retrytime = 500; - } - } - // --------------------------------------------------------------------- - // NAT-PMP mode (preferred) - // --------------------------------------------------------------------- - if (mode == 0) { - natpmp_t natpmp; - natpmpresp_t response; - int r = 0; + Thread::sleep(retrytime); + retrytime = retrytime * 2; + if (retrytime > ZT_PORTMAPPER_REFRESH_DELAY / 10) { + retrytime = ZT_PORTMAPPER_REFRESH_DELAY / 10; + } + continue; + } + else { + closenatpmp(&_natpmp); + retrytime = 500; + } + } + // --------------------------------------------------------------------- + // NAT-PMP mode (preferred) + // --------------------------------------------------------------------- + if (mode == 0) { + natpmp_t natpmp; + natpmpresp_t response; + int r = 0; - bool natPmpSuccess = false; - for(int tries=0;tries<60;++tries) { - int tryPort = (int)localPort + tries; - if (tryPort >= 65535) - tryPort = (tryPort - 65535) + 1025; + bool natPmpSuccess = false; + for (int tries = 0; tries < 60; ++tries) { + int tryPort = (int)localPort + tries; + if (tryPort >= 65535) + tryPort = (tryPort - 65535) + 1025; - memset(&natpmp,0,sizeof(natpmp)); - memset(&response,0,sizeof(response)); + memset(&natpmp, 0, sizeof(natpmp)); + memset(&response, 0, sizeof(response)); - if (initnatpmp(&natpmp,0,0) != 0) { - mode = 1; - closenatpmp(&natpmp); + if (initnatpmp(&natpmp, 0, 0) != 0) { + mode = 1; + closenatpmp(&natpmp); #ifdef ZT_PORTMAPPER_TRACE PM_TRACE("PortMapper: NAT-PMP: init failed, switching to UPnP mode" ZT_EOL_S); #endif - break; - } + break; + } - InetAddress publicAddress; - sendpublicaddressrequest(&natpmp); - int64_t myTimeout = OSUtils::now() + 5000; - do { - fd_set fds; - struct timeval timeout; - FD_ZERO(&fds); - FD_SET(natpmp.s, &fds); - getnatpmprequesttimeout(&natpmp, &timeout); - select(FD_SETSIZE, &fds, NULL, NULL, &timeout); - r = readnatpmpresponseorretry(&natpmp, &response); - if (OSUtils::now() >= myTimeout) - break; - } while (r == NATPMP_TRYAGAIN); - if (r == 0) { - publicAddress = InetAddress((uint32_t)response.pnu.publicaddress.addr.s_addr,0); - } else { + InetAddress publicAddress; + sendpublicaddressrequest(&natpmp); + int64_t myTimeout = OSUtils::now() + 5000; + do { + fd_set fds; + struct timeval timeout; + FD_ZERO(&fds); + FD_SET(natpmp.s, &fds); + getnatpmprequesttimeout(&natpmp, &timeout); + select(FD_SETSIZE, &fds, NULL, NULL, &timeout); + r = readnatpmpresponseorretry(&natpmp, &response); + if (OSUtils::now() >= myTimeout) + break; + } while (r == NATPMP_TRYAGAIN); + if (r == 0) { + publicAddress = InetAddress((uint32_t)response.pnu.publicaddress.addr.s_addr, 0); + } + else { #ifdef ZT_PORTMAPPER_TRACE PM_TRACE("PortMapper: NAT-PMP: request for external address failed, aborting..." ZT_EOL_S); #endif - closenatpmp(&natpmp); - break; - } + closenatpmp(&natpmp); + break; + } - sendnewportmappingrequest(&natpmp,NATPMP_PROTOCOL_UDP,localPort,tryPort,(ZT_PORTMAPPER_REFRESH_DELAY * 2) / 1000); - myTimeout = OSUtils::now() + 10000; - do { - fd_set fds; - struct timeval timeout; - FD_ZERO(&fds); - FD_SET(natpmp.s, &fds); - getnatpmprequesttimeout(&natpmp, &timeout); - select(FD_SETSIZE, &fds, NULL, NULL, &timeout); - r = readnatpmpresponseorretry(&natpmp, &response); - if (OSUtils::now() >= myTimeout) - break; - } while (r == NATPMP_TRYAGAIN); - if (r == 0) { - publicAddress.setPort(response.pnu.newportmapping.mappedpublicport); + sendnewportmappingrequest(&natpmp, NATPMP_PROTOCOL_UDP, localPort, tryPort, (ZT_PORTMAPPER_REFRESH_DELAY * 2) / 1000); + myTimeout = OSUtils::now() + 10000; + do { + fd_set fds; + struct timeval timeout; + FD_ZERO(&fds); + FD_SET(natpmp.s, &fds); + getnatpmprequesttimeout(&natpmp, &timeout); + select(FD_SETSIZE, &fds, NULL, NULL, &timeout); + r = readnatpmpresponseorretry(&natpmp, &response); + if (OSUtils::now() >= myTimeout) + break; + } while (r == NATPMP_TRYAGAIN); + if (r == 0) { + publicAddress.setPort(response.pnu.newportmapping.mappedpublicport); #ifdef ZT_PORTMAPPER_TRACE char paddr[128]; - PM_TRACE("PortMapper: NAT-PMP: mapped %u to %s" ZT_EOL_S,(unsigned int)localPort,publicAddress.toString(paddr)); + PM_TRACE("PortMapper: NAT-PMP: mapped %u to %s" ZT_EOL_S, (unsigned int)localPort, publicAddress.toString(paddr)); #endif - Mutex::Lock sl(surface_l); - surface.clear(); - surface.push_back(publicAddress); - natPmpSuccess = true; - closenatpmp(&natpmp); - break; - } else { - closenatpmp(&natpmp); - // continue - } - } + Mutex::Lock sl(surface_l); + surface.clear(); + surface.push_back(publicAddress); + natPmpSuccess = true; + closenatpmp(&natpmp); + break; + } + else { + closenatpmp(&natpmp); + // continue + } + } - if (!natPmpSuccess) { - mode = 1; + if (! natPmpSuccess) { + mode = 1; #ifdef ZT_PORTMAPPER_TRACE PM_TRACE("PortMapper: NAT-PMP: request failed, switching to UPnP mode" ZT_EOL_S); #endif - continue; - } - } - // --------------------------------------------------------------------- + continue; + } + } + // --------------------------------------------------------------------- - // --------------------------------------------------------------------- - // UPnP mode - // --------------------------------------------------------------------- - if (mode == 1) { - char lanaddr[4096]; - char externalip[4096]; // no range checking? so make these buffers larger than any UDP packet a uPnP server could send us as a precaution :P - char inport[16]; - char outport[16]; - struct UPNPUrls urls; - struct IGDdatas data; - - int upnpError = 0; - UPNPDev *devlist = upnpDiscoverAll(5000,(const char *)0,(const char *)0,0,0,2,&upnpError); - if (devlist) { + // --------------------------------------------------------------------- + // UPnP mode + // --------------------------------------------------------------------- + if (mode == 1) { + char lanaddr[4096]; + char externalip[4096]; // no range checking? so make these buffers larger than any UDP packet a uPnP server could send us as a precaution :P + char inport[16]; + char outport[16]; + struct UPNPUrls urls; + struct IGDdatas data; + int upnpError = 0; + UPNPDev* devlist = upnpDiscoverAll(5000, (const char*)0, (const char*)0, 0, 0, 2, &upnpError); + if (devlist) { #ifdef ZT_PORTMAPPER_TRACE - { - UPNPDev *dev = devlist; - while (dev) { - PM_TRACE("PortMapper: found UPnP device at URL '%s': %s" ZT_EOL_S,dev->descURL,dev->st); - dev = dev->pNext; - } - } + { + UPNPDev* dev = devlist; + while (dev) { + PM_TRACE("PortMapper: found UPnP device at URL '%s': %s" ZT_EOL_S, dev->descURL, dev->st); + dev = dev->pNext; + } + } #endif - memset(lanaddr,0,sizeof(lanaddr)); - memset(externalip,0,sizeof(externalip)); - memset(&urls,0,sizeof(urls)); - memset(&data,0,sizeof(data)); - OSUtils::ztsnprintf(inport,sizeof(inport),"%d",localPort); + memset(lanaddr, 0, sizeof(lanaddr)); + memset(externalip, 0, sizeof(externalip)); + memset(&urls, 0, sizeof(urls)); + memset(&data, 0, sizeof(data)); + OSUtils::ztsnprintf(inport, sizeof(inport), "%d", localPort); - int foundValidIGD = 0; - if ((foundValidIGD = UPNP_GetValidIGD(devlist,&urls,&data,lanaddr,sizeof(lanaddr)))&&(lanaddr[0])) { + int foundValidIGD = 0; + if ((foundValidIGD = UPNP_GetValidIGD(devlist, &urls, &data, lanaddr, sizeof(lanaddr))) && (lanaddr[0])) { #ifdef ZT_PORTMAPPER_TRACE - PM_TRACE("PortMapper: UPnP: my LAN IP address: %s" ZT_EOL_S,lanaddr); + PM_TRACE("PortMapper: UPnP: my LAN IP address: %s" ZT_EOL_S, lanaddr); #endif - if ((UPNP_GetExternalIPAddress(urls.controlURL,data.first.servicetype,externalip) == UPNPCOMMAND_SUCCESS)&&(externalip[0])) { + if ((UPNP_GetExternalIPAddress(urls.controlURL, data.first.servicetype, externalip) == UPNPCOMMAND_SUCCESS) && (externalip[0])) { #ifdef ZT_PORTMAPPER_TRACE - PM_TRACE("PortMapper: UPnP: my external IP address: %s" ZT_EOL_S,externalip); + PM_TRACE("PortMapper: UPnP: my external IP address: %s" ZT_EOL_S, externalip); #endif - for(int tries=0;tries<60;++tries) { - int tryPort = (int)localPort + tries; - if (tryPort >= 65535) - tryPort = (tryPort - 65535) + 1025; - OSUtils::ztsnprintf(outport,sizeof(outport),"%u",tryPort); + for (int tries = 0; tries < 60; ++tries) { + int tryPort = (int)localPort + tries; + if (tryPort >= 65535) + tryPort = (tryPort - 65535) + 1025; + OSUtils::ztsnprintf(outport, sizeof(outport), "%u", tryPort); - // First check and see if this port is already mapped to the - // same unique name. If so, keep this mapping and don't try - // to map again since this can break buggy routers. But don't - // fail if this command fails since not all routers support it. - { - char haveIntClient[128]; // 128 == big enough for all these as per miniupnpc "documentation" - char haveIntPort[128]; - char haveDesc[128]; - char haveEnabled[128]; - char haveLeaseDuration[128]; - memset(haveIntClient,0,sizeof(haveIntClient)); - memset(haveIntPort,0,sizeof(haveIntPort)); - memset(haveDesc,0,sizeof(haveDesc)); - memset(haveEnabled,0,sizeof(haveEnabled)); - memset(haveLeaseDuration,0,sizeof(haveLeaseDuration)); - if ((UPNP_GetSpecificPortMappingEntry(urls.controlURL,data.first.servicetype,outport,"UDP",(const char *)0,haveIntClient,haveIntPort,haveDesc,haveEnabled,haveLeaseDuration) == UPNPCOMMAND_SUCCESS)&&(uniqueName == haveDesc)) { + // First check and see if this port is already mapped to the + // same unique name. If so, keep this mapping and don't try + // to map again since this can break buggy routers. But don't + // fail if this command fails since not all routers support it. + { + char haveIntClient[128]; // 128 == big enough for all these as per miniupnpc "documentation" + char haveIntPort[128]; + char haveDesc[128]; + char haveEnabled[128]; + char haveLeaseDuration[128]; + memset(haveIntClient, 0, sizeof(haveIntClient)); + memset(haveIntPort, 0, sizeof(haveIntPort)); + memset(haveDesc, 0, sizeof(haveDesc)); + memset(haveEnabled, 0, sizeof(haveEnabled)); + memset(haveLeaseDuration, 0, sizeof(haveLeaseDuration)); + if ((UPNP_GetSpecificPortMappingEntry(urls.controlURL, data.first.servicetype, outport, "UDP", (const char*)0, haveIntClient, haveIntPort, haveDesc, haveEnabled, haveLeaseDuration) == UPNPCOMMAND_SUCCESS) + && (uniqueName == haveDesc)) { #ifdef ZT_PORTMAPPER_TRACE - PM_TRACE("PortMapper: UPnP: reusing previously reserved external port: %s" ZT_EOL_S,outport); + PM_TRACE("PortMapper: UPnP: reusing previously reserved external port: %s" ZT_EOL_S, outport); #endif - Mutex::Lock sl(surface_l); - surface.clear(); - InetAddress tmp(externalip); - tmp.setPort(tryPort); - surface.push_back(tmp); - break; - } - } + Mutex::Lock sl(surface_l); + surface.clear(); + InetAddress tmp(externalip); + tmp.setPort(tryPort); + surface.push_back(tmp); + break; + } + } - // Try to map this port - int mapResult = 0; - if ((mapResult = UPNP_AddPortMapping(urls.controlURL,data.first.servicetype,outport,inport,lanaddr,uniqueName.c_str(),"UDP",(const char *)0,"0")) == UPNPCOMMAND_SUCCESS) { + // Try to map this port + int mapResult = 0; + if ((mapResult = UPNP_AddPortMapping(urls.controlURL, data.first.servicetype, outport, inport, lanaddr, uniqueName.c_str(), "UDP", (const char*)0, "0")) == UPNPCOMMAND_SUCCESS) { #ifdef ZT_PORTMAPPER_TRACE - PM_TRACE("PortMapper: UPnP: reserved external port: %s" ZT_EOL_S,outport); + PM_TRACE("PortMapper: UPnP: reserved external port: %s" ZT_EOL_S, outport); #endif - Mutex::Lock sl(surface_l); - surface.clear(); - InetAddress tmp(externalip); - tmp.setPort(tryPort); - surface.push_back(tmp); - break; - } else { + Mutex::Lock sl(surface_l); + surface.clear(); + InetAddress tmp(externalip); + tmp.setPort(tryPort); + surface.push_back(tmp); + break; + } + else { #ifdef ZT_PORTMAPPER_TRACE - PM_TRACE("PortMapper: UPnP: UPNP_AddPortMapping(%s) failed: %d" ZT_EOL_S,outport,mapResult); + PM_TRACE("PortMapper: UPnP: UPNP_AddPortMapping(%s) failed: %d" ZT_EOL_S, outport, mapResult); #endif - Thread::sleep(1000); - } - } - - } else { - mode = 0; + Thread::sleep(1000); + } + } + } + else { + mode = 0; #ifdef ZT_PORTMAPPER_TRACE PM_TRACE("PortMapper: UPnP: UPNP_GetExternalIPAddress failed, returning to NAT-PMP mode" ZT_EOL_S); #endif - } - } else { - mode = 0; + } + } + else { + mode = 0; #ifdef ZT_PORTMAPPER_TRACE PM_TRACE("PortMapper: UPnP: UPNP_GetValidIGD failed, returning to NAT-PMP mode" ZT_EOL_S); #endif - } - freeUPNPDevlist(devlist); + } + freeUPNPDevlist(devlist); - if(foundValidIGD) { - FreeUPNPUrls(&urls); - } - } else { - mode = 0; + if (foundValidIGD) { + FreeUPNPUrls(&urls); + } + } + else { + mode = 0; #ifdef ZT_PORTMAPPER_TRACE - PM_TRACE("PortMapper: upnpDiscover failed, returning to NAT-PMP mode: %d" ZT_EOL_S,upnpError); + PM_TRACE("PortMapper: upnpDiscover failed, returning to NAT-PMP mode: %d" ZT_EOL_S, upnpError); #endif - } - } - // --------------------------------------------------------------------- + } + } + // --------------------------------------------------------------------- #ifdef ZT_PORTMAPPER_TRACE - PM_TRACE("UPNPClient: rescanning in %d ms" ZT_EOL_S,ZT_PORTMAPPER_REFRESH_DELAY); + PM_TRACE("UPNPClient: rescanning in %d ms" ZT_EOL_S, ZT_PORTMAPPER_REFRESH_DELAY); #endif - Thread::sleep(ZT_PORTMAPPER_REFRESH_DELAY); - } + Thread::sleep(ZT_PORTMAPPER_REFRESH_DELAY); + } - delete this; - } + delete this; + } - volatile bool run; - int localPort; - std::string uniqueName; + volatile bool run; + int localPort; + std::string uniqueName; - Mutex surface_l; - std::vector surface; + Mutex surface_l; + std::vector surface; }; -PortMapper::PortMapper(int localUdpPortToMap,const char *uniqueName) +PortMapper::PortMapper(int localUdpPortToMap, const char* uniqueName) { - _impl = new PortMapperImpl(localUdpPortToMap,uniqueName); - Thread::start(_impl); + _impl = new PortMapperImpl(localUdpPortToMap, uniqueName); + Thread::start(_impl); } PortMapper::~PortMapper() { - _impl->run = false; + _impl->run = false; } std::vector PortMapper::get() const { - Mutex::Lock _l(_impl->surface_l); - return _impl->surface; + Mutex::Lock _l(_impl->surface_l); + return _impl->surface; } -} // namespace ZeroTier +} // namespace ZeroTier -#endif // ZT_USE_MINIUPNPC +#endif // ZT_USE_MINIUPNPC diff --git a/osdep/PortMapper.hpp b/osdep/PortMapper.hpp index c74df0c1..ab1161ac 100644 --- a/osdep/PortMapper.hpp +++ b/osdep/PortMapper.hpp @@ -16,13 +16,13 @@ #ifndef ZT_PORTMAPPER_HPP #define ZT_PORTMAPPER_HPP -#include - #include "../node/Constants.hpp" #include "../node/InetAddress.hpp" #include "../node/Mutex.hpp" #include "Thread.hpp" +#include + /** * How frequently should we refresh our UPNP/NAT-PnP/whatever state? */ @@ -35,32 +35,31 @@ class PortMapperImpl; /** * UPnP/NAT-PnP port mapping "daemon" */ -class PortMapper -{ - friend class PortMapperImpl; +class PortMapper { + friend class PortMapperImpl; -public: - /** - * Create and start port mapper service - * - * @param localUdpPortToMap Port we want visible to the outside world - * @param name Unique name of this endpoint (based on ZeroTier address) - */ - PortMapper(int localUdpPortToMap,const char *uniqueName); + public: + /** + * Create and start port mapper service + * + * @param localUdpPortToMap Port we want visible to the outside world + * @param name Unique name of this endpoint (based on ZeroTier address) + */ + PortMapper(int localUdpPortToMap, const char* uniqueName); - ~PortMapper(); + ~PortMapper(); - /** - * @return All current external mappings for our port - */ - std::vector get() const; + /** + * @return All current external mappings for our port + */ + std::vector get() const; -private: - PortMapperImpl *_impl; + private: + PortMapperImpl* _impl; }; -} // namespace ZeroTier +} // namespace ZeroTier #endif -#endif // ZT_USE_MINIUPNPC +#endif // ZT_USE_MINIUPNPC diff --git a/osdep/Thread.hpp b/osdep/Thread.hpp index 96d257f4..a77e8bbe 100644 --- a/osdep/Thread.hpp +++ b/osdep/Thread.hpp @@ -14,179 +14,188 @@ #ifndef ZT_THREAD_HPP #define ZT_THREAD_HPP -#include - #include "../node/Constants.hpp" +#include + #ifdef __WINDOWS__ -#include -#include -#include - #include "../node/Mutex.hpp" +#include +#include +#include + namespace ZeroTier { -template -static DWORD WINAPI ___zt_threadMain(LPVOID lpParam) +template static DWORD WINAPI ___zt_threadMain(LPVOID lpParam) { - try { - ((C *)lpParam)->threadMain(); - } catch ( ... ) {} - return 0; + try { + ((C*)lpParam)->threadMain(); + } + catch (...) { + } + return 0; } -class Thread -{ -public: - Thread() - { - _th = NULL; - _tid = 0; - } +class Thread { + public: + Thread() + { + _th = NULL; + _tid = 0; + } - template - static inline Thread start(C *instance) - { - Thread t; - t._th = CreateThread(NULL,0,&___zt_threadMain,(LPVOID)instance,0,&t._tid); - if (t._th == NULL) - throw std::runtime_error("CreateThread() failed"); - return t; - } + template static inline Thread start(C* instance) + { + Thread t; + t._th = CreateThread(NULL, 0, &___zt_threadMain, (LPVOID)instance, 0, &t._tid); + if (t._th == NULL) + throw std::runtime_error("CreateThread() failed"); + return t; + } - static inline void join(const Thread &t) - { - if (t._th != NULL) { - for(;;) { - DWORD ec = STILL_ACTIVE; - GetExitCodeThread(t._th,&ec); - if (ec == STILL_ACTIVE) - WaitForSingleObject(t._th,1000); - else break; - } - } - } + static inline void join(const Thread& t) + { + if (t._th != NULL) { + for (;;) { + DWORD ec = STILL_ACTIVE; + GetExitCodeThread(t._th, &ec); + if (ec == STILL_ACTIVE) + WaitForSingleObject(t._th, 1000); + else + break; + } + } + } - static inline void sleep(unsigned long ms) - { - Sleep((DWORD)ms); - } + static inline void sleep(unsigned long ms) + { + Sleep((DWORD)ms); + } - // Not available on *nix platforms - static inline void cancelIO(const Thread &t) - { -#if !defined(__MINGW32__) && !defined(__MINGW64__) // CancelSynchronousIo not available in MSYS2 - if (t._th != NULL) - CancelSynchronousIo(t._th); + // Not available on *nix platforms + static inline void cancelIO(const Thread& t) + { +#if ! defined(__MINGW32__) && ! defined(__MINGW64__) // CancelSynchronousIo not available in MSYS2 + if (t._th != NULL) + CancelSynchronousIo(t._th); #endif - } + } - inline operator bool() const { return (_th != NULL); } + inline operator bool() const + { + return (_th != NULL); + } -private: - HANDLE _th; - DWORD _tid; + private: + HANDLE _th; + DWORD _tid; }; -} // namespace ZeroTier +} // namespace ZeroTier #else +#include #include #include #include -#include #include namespace ZeroTier { -template -static void *___zt_threadMain(void *instance) +template static void* ___zt_threadMain(void* instance) { - try { - ((C *)instance)->threadMain(); - } catch ( ... ) {} - return (void *)0; + try { + ((C*)instance)->threadMain(); + } + catch (...) { + } + return (void*)0; } /** * A thread identifier, and static methods to start and join threads */ -class Thread -{ -public: - Thread() - { - memset(this,0,sizeof(Thread)); - } +class Thread { + public: + Thread() + { + memset(this, 0, sizeof(Thread)); + } - Thread(const Thread &t) - { - memcpy(this,&t,sizeof(Thread)); - } + Thread(const Thread& t) + { + memcpy(this, &t, sizeof(Thread)); + } - inline Thread &operator=(const Thread &t) - { - memcpy(this,&t,sizeof(Thread)); - return *this; - } + inline Thread& operator=(const Thread& t) + { + memcpy(this, &t, sizeof(Thread)); + return *this; + } - /** - * Start a new thread - * - * @param instance Instance whose threadMain() method gets called by new thread - * @return Thread identifier - * @throws std::runtime_error Unable to create thread - * @tparam C Class containing threadMain() - */ - template - static inline Thread start(C *instance) - { - Thread t; - pthread_attr_t tattr; - pthread_attr_init(&tattr); - // This corrects for systems with abnormally small defaults (musl) and also - // shrinks the stack on systems with large defaults to save a bit of memory. - pthread_attr_setstacksize(&tattr,ZT_THREAD_MIN_STACK_SIZE); - if (pthread_create(&t._tid,&tattr,&___zt_threadMain,instance)) { - pthread_attr_destroy(&tattr); - throw std::runtime_error("pthread_create() failed, unable to create thread"); - } else { - t._started = true; - pthread_attr_destroy(&tattr); - } - return t; - } + /** + * Start a new thread + * + * @param instance Instance whose threadMain() method gets called by new thread + * @return Thread identifier + * @throws std::runtime_error Unable to create thread + * @tparam C Class containing threadMain() + */ + template static inline Thread start(C* instance) + { + Thread t; + pthread_attr_t tattr; + pthread_attr_init(&tattr); + // This corrects for systems with abnormally small defaults (musl) and also + // shrinks the stack on systems with large defaults to save a bit of memory. + pthread_attr_setstacksize(&tattr, ZT_THREAD_MIN_STACK_SIZE); + if (pthread_create(&t._tid, &tattr, &___zt_threadMain, instance)) { + pthread_attr_destroy(&tattr); + throw std::runtime_error("pthread_create() failed, unable to create thread"); + } + else { + t._started = true; + pthread_attr_destroy(&tattr); + } + return t; + } - /** - * Join to a thread, waiting for it to terminate (does nothing on null Thread values) - * - * @param t Thread to join - */ - static inline void join(const Thread &t) - { - if (t._started) - pthread_join(t._tid,(void **)0); - } + /** + * Join to a thread, waiting for it to terminate (does nothing on null Thread values) + * + * @param t Thread to join + */ + static inline void join(const Thread& t) + { + if (t._started) + pthread_join(t._tid, (void**)0); + } - /** - * Sleep the current thread - * - * @param ms Number of milliseconds to sleep - */ - static inline void sleep(unsigned long ms) { usleep(ms * 1000); } + /** + * Sleep the current thread + * + * @param ms Number of milliseconds to sleep + */ + static inline void sleep(unsigned long ms) + { + usleep(ms * 1000); + } - inline operator bool() const { return (_started); } + inline operator bool() const + { + return (_started); + } -private: - pthread_t _tid; - volatile bool _started; + private: + pthread_t _tid; + volatile bool _started; }; -} // namespace ZeroTier +} // namespace ZeroTier -#endif // __WINDOWS__ / !__WINDOWS__ +#endif // __WINDOWS__ / !__WINDOWS__ #endif diff --git a/osdep/WinDNSHelper.cpp b/osdep/WinDNSHelper.cpp index 6bcd2b47..a1f9c50e 100644 --- a/osdep/WinDNSHelper.cpp +++ b/osdep/WinDNSHelper.cpp @@ -1,97 +1,89 @@ #include "WinDNSHelper.hpp" -#include #include - -#include -#include +#include #include +#include #include +#include #define MAX_KEY_LENGTH 255 #define MAX_VALUE_NAME 16383 -namespace ZeroTier -{ +namespace ZeroTier { BOOL RegDelnodeRecurse(HKEY hKeyRoot, LPTSTR lpSubKey) { - LPTSTR lpEnd; - LONG lResult; - DWORD dwSize; - TCHAR szName[MAX_PATH]; - HKEY hKey; - FILETIME ftWrite; + LPTSTR lpEnd; + LONG lResult; + DWORD dwSize; + TCHAR szName[MAX_PATH]; + HKEY hKey; + FILETIME ftWrite; - // First, see if we can delete the key without having - // to recurse. + // First, see if we can delete the key without having + // to recurse. - lResult = RegDeleteKey(hKeyRoot, lpSubKey); + lResult = RegDeleteKey(hKeyRoot, lpSubKey); - if (lResult == ERROR_SUCCESS) - return TRUE; + if (lResult == ERROR_SUCCESS) + return TRUE; - lResult = RegOpenKeyEx(hKeyRoot, lpSubKey, 0, KEY_READ, &hKey); + lResult = RegOpenKeyEx(hKeyRoot, lpSubKey, 0, KEY_READ, &hKey); - if (lResult != ERROR_SUCCESS) - { - if (lResult == ERROR_FILE_NOT_FOUND) { - return TRUE; - } - else { - return FALSE; - } - } + if (lResult != ERROR_SUCCESS) { + if (lResult == ERROR_FILE_NOT_FOUND) { + return TRUE; + } + else { + return FALSE; + } + } - // Check for an ending slash and add one if it is missing. + // Check for an ending slash and add one if it is missing. - lpEnd = lpSubKey + lstrlen(lpSubKey); + lpEnd = lpSubKey + lstrlen(lpSubKey); - if (*(lpEnd - 1) != TEXT('\\')) - { - *lpEnd = TEXT('\\'); - lpEnd++; - *lpEnd = TEXT('\0'); - } + if (*(lpEnd - 1) != TEXT('\\')) { + *lpEnd = TEXT('\\'); + lpEnd++; + *lpEnd = TEXT('\0'); + } - // Enumerate the keys + // Enumerate the keys - dwSize = MAX_PATH; - lResult = RegEnumKeyEx(hKey, 0, szName, &dwSize, NULL, - NULL, NULL, &ftWrite); + dwSize = MAX_PATH; + lResult = RegEnumKeyEx(hKey, 0, szName, &dwSize, NULL, NULL, NULL, &ftWrite); - if (lResult == ERROR_SUCCESS) - { - do { + if (lResult == ERROR_SUCCESS) { + do { + *lpEnd = TEXT('\0'); + StringCchCat(lpSubKey, MAX_PATH * 2, szName); - *lpEnd = TEXT('\0'); - StringCchCat(lpSubKey, MAX_PATH * 2, szName); + if (! RegDelnodeRecurse(hKeyRoot, lpSubKey)) { + break; + } - if (!RegDelnodeRecurse(hKeyRoot, lpSubKey)) { - break; - } + dwSize = MAX_PATH; - dwSize = MAX_PATH; + lResult = RegEnumKeyEx(hKey, 0, szName, &dwSize, NULL, NULL, NULL, &ftWrite); - lResult = RegEnumKeyEx(hKey, 0, szName, &dwSize, NULL, - NULL, NULL, &ftWrite); + } while (lResult == ERROR_SUCCESS); + } - } while (lResult == ERROR_SUCCESS); - } + lpEnd--; + *lpEnd = TEXT('\0'); - lpEnd--; - *lpEnd = TEXT('\0'); + RegCloseKey(hKey); - RegCloseKey(hKey); + // Try again to delete the key. - // Try again to delete the key. + lResult = RegDeleteKey(hKeyRoot, lpSubKey); - lResult = RegDeleteKey(hKeyRoot, lpSubKey); + if (lResult == ERROR_SUCCESS) + return TRUE; - if (lResult == ERROR_SUCCESS) - return TRUE; - - return FALSE; + return FALSE; } //************************************************************* @@ -110,244 +102,206 @@ BOOL RegDelnodeRecurse(HKEY hKeyRoot, LPTSTR lpSubKey) BOOL RegDelnode(HKEY hKeyRoot, LPCTSTR lpSubKey) { - TCHAR szDelKey[MAX_PATH * 2]; - - StringCchCopy(szDelKey, MAX_PATH * 2, lpSubKey); - return RegDelnodeRecurse(hKeyRoot, szDelKey); + TCHAR szDelKey[MAX_PATH * 2]; + StringCchCopy(szDelKey, MAX_PATH * 2, lpSubKey); + return RegDelnodeRecurse(hKeyRoot, szDelKey); } std::vector getSubKeys(const char* key) { - std::vector subkeys; - HKEY hKey; - if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, - key, - 0, - KEY_READ, - &hKey) == ERROR_SUCCESS) { + std::vector subkeys; + HKEY hKey; + if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, key, 0, KEY_READ, &hKey) == ERROR_SUCCESS) { + TCHAR achKey[MAX_KEY_LENGTH]; // buffer for subkey name + DWORD cbName; // size of name string + TCHAR achClass[MAX_PATH] = TEXT(""); // buffer for class name + DWORD cchClassName = MAX_PATH; // size of class string + DWORD cSubKeys = 0; // number of subkeys + DWORD cbMaxSubKey; // longest subkey size + DWORD cchMaxClass; // longest class string + DWORD cValues; // number of values for key + DWORD cchMaxValue; // longest value name + DWORD cbMaxValueData; // longest value data + DWORD cbSecurityDescriptor; // size of security descriptor + FILETIME ftLastWriteTime; // last write time - TCHAR achKey[MAX_KEY_LENGTH]; // buffer for subkey name - DWORD cbName; // size of name string - TCHAR achClass[MAX_PATH] = TEXT(""); // buffer for class name - DWORD cchClassName = MAX_PATH; // size of class string - DWORD cSubKeys = 0; // number of subkeys - DWORD cbMaxSubKey; // longest subkey size - DWORD cchMaxClass; // longest class string - DWORD cValues; // number of values for key - DWORD cchMaxValue; // longest value name - DWORD cbMaxValueData; // longest value data - DWORD cbSecurityDescriptor; // size of security descriptor - FILETIME ftLastWriteTime; // last write time + DWORD i, retCode; - DWORD i, retCode; + TCHAR achValue[MAX_VALUE_NAME]; + DWORD cchValue = MAX_VALUE_NAME; - TCHAR achValue[MAX_VALUE_NAME]; - DWORD cchValue = MAX_VALUE_NAME; + retCode = RegQueryInfoKey( + hKey, // key handle + achClass, // buffer for class name + &cchClassName, // size of class string + NULL, // reserved + &cSubKeys, // number of subkeys + &cbMaxSubKey, // longest subkey size + &cchMaxClass, // longest class string + &cValues, // number of values for this key + &cchMaxValue, // longest value name + &cbMaxValueData, // longest value data + &cbSecurityDescriptor, // security descriptor + &ftLastWriteTime); // last write time - retCode = RegQueryInfoKey( - hKey, // key handle - achClass, // buffer for class name - &cchClassName, // size of class string - NULL, // reserved - &cSubKeys, // number of subkeys - &cbMaxSubKey, // longest subkey size - &cchMaxClass, // longest class string - &cValues, // number of values for this key - &cchMaxValue, // longest value name - &cbMaxValueData, // longest value data - &cbSecurityDescriptor, // security descriptor - &ftLastWriteTime); // last write time - - for (i = 0; i < cSubKeys; ++i) { - cbName = MAX_KEY_LENGTH; - retCode = RegEnumKeyEx( - hKey, - i, - achKey, - &cbName, - NULL, - NULL, - NULL, - &ftLastWriteTime); - if (retCode == ERROR_SUCCESS) { - subkeys.push_back(achKey); - } - } - } - RegCloseKey(hKey); - return subkeys; + for (i = 0; i < cSubKeys; ++i) { + cbName = MAX_KEY_LENGTH; + retCode = RegEnumKeyEx(hKey, i, achKey, &cbName, NULL, NULL, NULL, &ftLastWriteTime); + if (retCode == ERROR_SUCCESS) { + subkeys.push_back(achKey); + } + } + } + RegCloseKey(hKey); + return subkeys; } -std::vector getValueList(const char* key) { - std::vector values; - HKEY hKey; - if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, - key, - 0, - KEY_READ, - &hKey) == ERROR_SUCCESS) { +std::vector getValueList(const char* key) +{ + std::vector values; + HKEY hKey; + if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, key, 0, KEY_READ, &hKey) == ERROR_SUCCESS) { + TCHAR achKey[MAX_KEY_LENGTH]; // buffer for subkey name + DWORD cbName; // size of name string + TCHAR achClass[MAX_PATH] = TEXT(""); // buffer for class name + DWORD cchClassName = MAX_PATH; // size of class string + DWORD cSubKeys = 0; // number of subkeys + DWORD cbMaxSubKey; // longest subkey size + DWORD cchMaxClass; // longest class string + DWORD cValues; // number of values for key + DWORD cchMaxValue; // longest value name + DWORD cbMaxValueData; // longest value data + DWORD cbSecurityDescriptor; // size of security descriptor + FILETIME ftLastWriteTime; // last write time - TCHAR achKey[MAX_KEY_LENGTH]; // buffer for subkey name - DWORD cbName; // size of name string - TCHAR achClass[MAX_PATH] = TEXT(""); // buffer for class name - DWORD cchClassName = MAX_PATH; // size of class string - DWORD cSubKeys = 0; // number of subkeys - DWORD cbMaxSubKey; // longest subkey size - DWORD cchMaxClass; // longest class string - DWORD cValues; // number of values for key - DWORD cchMaxValue; // longest value name - DWORD cbMaxValueData; // longest value data - DWORD cbSecurityDescriptor; // size of security descriptor - FILETIME ftLastWriteTime; // last write time + DWORD i, retCode; - DWORD i, retCode; + TCHAR achValue[MAX_VALUE_NAME]; + DWORD cchValue = MAX_VALUE_NAME; - TCHAR achValue[MAX_VALUE_NAME]; - DWORD cchValue = MAX_VALUE_NAME; + retCode = RegQueryInfoKey( + hKey, // key handle + achClass, // buffer for class name + &cchClassName, // size of class string + NULL, // reserved + &cSubKeys, // number of subkeys + &cbMaxSubKey, // longest subkey size + &cchMaxClass, // longest class string + &cValues, // number of values for this key + &cchMaxValue, // longest value name + &cbMaxValueData, // longest value data + &cbSecurityDescriptor, // security descriptor + &ftLastWriteTime); // last write time - retCode = RegQueryInfoKey( - hKey, // key handle - achClass, // buffer for class name - &cchClassName, // size of class string - NULL, // reserved - &cSubKeys, // number of subkeys - &cbMaxSubKey, // longest subkey size - &cchMaxClass, // longest class string - &cValues, // number of values for this key - &cchMaxValue, // longest value name - &cbMaxValueData, // longest value data - &cbSecurityDescriptor, // security descriptor - &ftLastWriteTime); // last write time - - for (i = 0, retCode = ERROR_SUCCESS; i < cValues; ++i) { - cchValue = MAX_VALUE_NAME; - achValue[0] = '\0'; - retCode = RegEnumValue( - hKey, - i, - achValue, - &cchValue, - NULL, - NULL, - NULL, - NULL); - if (retCode == ERROR_SUCCESS) { - values.push_back(achValue); - } - } - } - RegCloseKey(hKey); - return values; + for (i = 0, retCode = ERROR_SUCCESS; i < cValues; ++i) { + cchValue = MAX_VALUE_NAME; + achValue[0] = '\0'; + retCode = RegEnumValue(hKey, i, achValue, &cchValue, NULL, NULL, NULL, NULL); + if (retCode == ERROR_SUCCESS) { + values.push_back(achValue); + } + } + } + RegCloseKey(hKey); + return values; } std::pair WinDNSHelper::hasDNSConfig(uint64_t nwid) { - char networkStr[20] = { 0 }; - sprintf(networkStr, "%.16llx", nwid); + char networkStr[20] = { 0 }; + sprintf(networkStr, "%.16llx", nwid); - const char* baseKey = "SYSTEM\\CurrentControlSet\\Services\\Dnscache\\Parameters\\DnsPolicyConfig"; - auto subkeys = getSubKeys(baseKey); - for (auto it = subkeys.begin(); it != subkeys.end(); ++it) { - char sub[MAX_KEY_LENGTH] = { 0 }; - sprintf(sub, "%s\\%s", baseKey, it->c_str()); - auto dnsRecords = getValueList(sub); - for (auto it2 = dnsRecords.begin(); it2 != dnsRecords.end(); ++it2) { - if ((*it2) == "Comment") { - HKEY hKey; - if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, - sub, - 0, - KEY_READ, - &hKey) == ERROR_SUCCESS) { + const char* baseKey = "SYSTEM\\CurrentControlSet\\Services\\Dnscache\\Parameters\\DnsPolicyConfig"; + auto subkeys = getSubKeys(baseKey); + for (auto it = subkeys.begin(); it != subkeys.end(); ++it) { + char sub[MAX_KEY_LENGTH] = { 0 }; + sprintf(sub, "%s\\%s", baseKey, it->c_str()); + auto dnsRecords = getValueList(sub); + for (auto it2 = dnsRecords.begin(); it2 != dnsRecords.end(); ++it2) { + if ((*it2) == "Comment") { + HKEY hKey; + if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, sub, 0, KEY_READ, &hKey) == ERROR_SUCCESS) { + char buf[16384] = { 0 }; + DWORD size = sizeof(buf); + DWORD retCode = RegGetValueA(HKEY_LOCAL_MACHINE, sub, it2->c_str(), RRF_RT_REG_SZ, NULL, &buf, &size); + if (retCode == ERROR_SUCCESS) { + if (std::string(networkStr) == std::string(buf)) { + RegCloseKey(hKey); + return std::make_pair(true, std::string(sub)); + } + } + else { + } + } + RegCloseKey(hKey); + } + } + } - char buf[16384] = { 0 }; - DWORD size = sizeof(buf); - DWORD retCode = RegGetValueA( - HKEY_LOCAL_MACHINE, - sub, - it2->c_str(), - RRF_RT_REG_SZ, - NULL, - &buf, - &size); - if (retCode == ERROR_SUCCESS) { - if (std::string(networkStr) == std::string(buf)) { - RegCloseKey(hKey); - return std::make_pair(true, std::string(sub)); - } - } - else { - - } - } - RegCloseKey(hKey); - } - } - } - - return std::make_pair(false, std::string()); + return std::make_pair(false, std::string()); } void WinDNSHelper::setDNS(uint64_t nwid, const char* domain, const std::vector& servers) { - auto hasConfig = hasDNSConfig(nwid); + auto hasConfig = hasDNSConfig(nwid); - std::stringstream ss; - for (auto it = servers.begin(); it != servers.end(); ++it) { - char ipaddr[256] = { 0 }; - ss << it->toIpString(ipaddr); - if ((it + 1) != servers.end()) { - ss << ";"; - } - } - std::string serverValue = ss.str(); + std::stringstream ss; + for (auto it = servers.begin(); it != servers.end(); ++it) { + char ipaddr[256] = { 0 }; + ss << it->toIpString(ipaddr); + if ((it + 1) != servers.end()) { + ss << ";"; + } + } + std::string serverValue = ss.str(); - if (hasConfig.first) { - // update existing config - HKEY dnsKey; - if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, hasConfig.second.c_str(), 0, KEY_READ | KEY_WRITE, &dnsKey) == ERROR_SUCCESS) { - auto retCode = RegSetKeyValueA(dnsKey, NULL, "GenericDNSServers", REG_SZ, serverValue.data(), (DWORD)serverValue.length()); - if (retCode != ERROR_SUCCESS) { - fprintf(stderr, "Error writing dns servers: %d\n", retCode); - } - } - } else { - // add new config - const char* baseKey = "SYSTEM\\CurrentControlSet\\Services\\Dnscache\\Parameters\\DnsPolicyConfig"; - GUID guid; - CoCreateGuid(&guid); - wchar_t guidTmp[128] = { 0 }; - char guidStr[128] = { 0 }; - StringFromGUID2(guid, guidTmp, 128); - wcstombs(guidStr, guidTmp, 128); - char fullKey[MAX_KEY_LENGTH] = { 0 }; - sprintf(fullKey, "%s\\%s", baseKey, guidStr); - HKEY dnsKey; - RegCreateKeyA(HKEY_LOCAL_MACHINE, fullKey, &dnsKey); - if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, fullKey, 0, KEY_READ | KEY_WRITE, &dnsKey) == ERROR_SUCCESS) { - char nwString[32] = { 0 }; - sprintf(nwString, "%.16llx", nwid); - RegSetKeyValueA(dnsKey, NULL, "Comment", REG_SZ, nwString, strlen(nwString)); + if (hasConfig.first) { + // update existing config + HKEY dnsKey; + if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, hasConfig.second.c_str(), 0, KEY_READ | KEY_WRITE, &dnsKey) == ERROR_SUCCESS) { + auto retCode = RegSetKeyValueA(dnsKey, NULL, "GenericDNSServers", REG_SZ, serverValue.data(), (DWORD)serverValue.length()); + if (retCode != ERROR_SUCCESS) { + fprintf(stderr, "Error writing dns servers: %d\n", retCode); + } + } + } + else { + // add new config + const char* baseKey = "SYSTEM\\CurrentControlSet\\Services\\Dnscache\\Parameters\\DnsPolicyConfig"; + GUID guid; + CoCreateGuid(&guid); + wchar_t guidTmp[128] = { 0 }; + char guidStr[128] = { 0 }; + StringFromGUID2(guid, guidTmp, 128); + wcstombs(guidStr, guidTmp, 128); + char fullKey[MAX_KEY_LENGTH] = { 0 }; + sprintf(fullKey, "%s\\%s", baseKey, guidStr); + HKEY dnsKey; + RegCreateKeyA(HKEY_LOCAL_MACHINE, fullKey, &dnsKey); + if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, fullKey, 0, KEY_READ | KEY_WRITE, &dnsKey) == ERROR_SUCCESS) { + char nwString[32] = { 0 }; + sprintf(nwString, "%.16llx", nwid); + RegSetKeyValueA(dnsKey, NULL, "Comment", REG_SZ, nwString, strlen(nwString)); - DWORD configOpts = 8; - RegSetKeyValueA(dnsKey, NULL, "ConfigOptions", REG_DWORD, &configOpts, sizeof(DWORD)); - RegSetKeyValueA(dnsKey, NULL, "DisplayName", REG_SZ, "", 0); - RegSetKeyValueA(dnsKey, NULL, "GenericDNSServers", REG_SZ, serverValue.data(), serverValue.length()); - RegSetKeyValueA(dnsKey, NULL, "IPSECCARestriction", REG_SZ, "", 0); - std::string d = "." + std::string(domain); - RegSetKeyValueA(dnsKey, NULL, "Name", REG_MULTI_SZ, d.data(), d.length()); - DWORD version = 2; - RegSetKeyValueA(dnsKey, NULL, "Version", REG_DWORD, &version, sizeof(DWORD)); - } - } + DWORD configOpts = 8; + RegSetKeyValueA(dnsKey, NULL, "ConfigOptions", REG_DWORD, &configOpts, sizeof(DWORD)); + RegSetKeyValueA(dnsKey, NULL, "DisplayName", REG_SZ, "", 0); + RegSetKeyValueA(dnsKey, NULL, "GenericDNSServers", REG_SZ, serverValue.data(), serverValue.length()); + RegSetKeyValueA(dnsKey, NULL, "IPSECCARestriction", REG_SZ, "", 0); + std::string d = "." + std::string(domain); + RegSetKeyValueA(dnsKey, NULL, "Name", REG_MULTI_SZ, d.data(), d.length()); + DWORD version = 2; + RegSetKeyValueA(dnsKey, NULL, "Version", REG_DWORD, &version, sizeof(DWORD)); + } + } } void WinDNSHelper::removeDNS(uint64_t nwid) { - auto hasConfig = hasDNSConfig(nwid); - if (hasConfig.first) { - RegDelnode(HKEY_LOCAL_MACHINE, hasConfig.second.c_str()); - } + auto hasConfig = hasDNSConfig(nwid); + if (hasConfig.first) { + RegDelnode(HKEY_LOCAL_MACHINE, hasConfig.second.c_str()); + } } -} \ No newline at end of file +} // namespace ZeroTier \ No newline at end of file diff --git a/osdep/WinDNSHelper.hpp b/osdep/WinDNSHelper.hpp index c42ba077..f017e701 100644 --- a/osdep/WinDNSHelper.hpp +++ b/osdep/WinDNSHelper.hpp @@ -1,24 +1,22 @@ #ifndef WIN_DNS_HELPER_H_ #define WIN_DNS_HELPER_H_ -#include -#include #include "../node/InetAddress.hpp" +#include +#include -namespace ZeroTier -{ +namespace ZeroTier { -class WinDNSHelper -{ -public: - static void setDNS(uint64_t nwid, const char* domain, const std::vector& servers); - static void removeDNS(uint64_t nwid); +class WinDNSHelper { + public: + static void setDNS(uint64_t nwid, const char* domain, const std::vector& servers); + static void removeDNS(uint64_t nwid); -private: - static std::pair hasDNSConfig(uint64_t nwid); + private: + static std::pair hasDNSConfig(uint64_t nwid); }; -} +} // namespace ZeroTier #endif \ No newline at end of file diff --git a/osdep/WinFWHelper.cpp b/osdep/WinFWHelper.cpp index 40f38977..86c4a1e8 100644 --- a/osdep/WinFWHelper.cpp +++ b/osdep/WinFWHelper.cpp @@ -1,172 +1,157 @@ #include "WinFWHelper.hpp" - namespace ZeroTier { - - void ZeroTier::WinFWHelper::newICMPRule(const InetAddress& ip, uint64_t nwid) { - char nwString[32] = { 0 }; - char ipbuf[64]; + char nwString[32] = { 0 }; + char ipbuf[64]; - sprintf(nwString, "%.16llx", nwid); - std::string nwString2 = { nwString }; - - ip.toString(ipbuf); + sprintf(nwString, "%.16llx", nwid); + std::string nwString2 = { nwString }; - if (ip.isV4()) { - WinFWHelper::newICMPv4Rule(ipbuf, nwid); - } - else { - WinFWHelper::newICMPv6Rule(ipbuf, nwid); - } + ip.toString(ipbuf); + + if (ip.isV4()) { + WinFWHelper::newICMPv4Rule(ipbuf, nwid); + } + else { + WinFWHelper::newICMPv6Rule(ipbuf, nwid); + } } void ZeroTier::WinFWHelper::removeICMPRule(const InetAddress& ip, uint64_t nwid) { - char nwString[32] = { 0 }; - char ipbuf[64]; + char nwString[32] = { 0 }; + char ipbuf[64]; - sprintf(nwString, "%.16llx", nwid); - std::string nwString2 = { nwString }; + sprintf(nwString, "%.16llx", nwid); + std::string nwString2 = { nwString }; - ip.toString(ipbuf); + ip.toString(ipbuf); - if (ip.isV4()) { - WinFWHelper::removeICMPv4Rule(ipbuf, nwid); - } - else { - WinFWHelper::removeICMPv6Rule(ipbuf, nwid); - } + if (ip.isV4()) { + WinFWHelper::removeICMPv4Rule(ipbuf, nwid); + } + else { + WinFWHelper::removeICMPv6Rule(ipbuf, nwid); + } } - void WinFWHelper::newICMPv4Rule(std::string address, uint64_t nwid) { - // allows icmp, scoped to a specific ip address and interface name + // allows icmp, scoped to a specific ip address and interface name - char nwString[32] = { 0 }; - sprintf(nwString, "%.16llx", nwid); - std::string nwString2 = { nwString }; + char nwString[32] = { 0 }; + sprintf(nwString, "%.16llx", nwid); + std::string nwString2 = { nwString }; - std::string cmd = R"(C:\Windows\System32\WindowsPowershell\v1.0\powershell.exe "New-NetFirewallRule -DisplayName zerotier-icmpv4-)" + nwString2 + address + - R"( -InterfaceAlias 'ZeroTier One `[)" + nwString2 + R"(`]')" + - " -Protocol ICMPv4 -Action Allow" + - " -LocalAddress " + address + "\"\r\n"; - - _run(cmd); + std::string cmd = R"(C:\Windows\System32\WindowsPowershell\v1.0\powershell.exe "New-NetFirewallRule -DisplayName zerotier-icmpv4-)" + nwString2 + address + R"( -InterfaceAlias 'ZeroTier One `[)" + nwString2 + R"(`]')" + + " -Protocol ICMPv4 -Action Allow" + " -LocalAddress " + address + "\"\r\n"; + + _run(cmd); } void WinFWHelper::newICMPv6Rule(std::string address, uint64_t nwid) { - // allows icmp, scoped to a specific ip address and interface name + // allows icmp, scoped to a specific ip address and interface name - char nwString[32] = { 0 }; - sprintf(nwString, "%.16llx", nwid); - std::string nwString2 = { nwString }; + char nwString[32] = { 0 }; + sprintf(nwString, "%.16llx", nwid); + std::string nwString2 = { nwString }; - std::string cmd = R"(C:\Windows\System32\WindowsPowershell\v1.0\powershell.exe "New-NetFirewallRule -DisplayName zerotier-icmpv6-)" + nwString2 + address + - R"( -InterfaceAlias 'ZeroTier One `[)" + nwString2 + R"(`]')" + - " -Protocol ICMPv6 -Action Allow" + - " -LocalAddress " + address + "\"\r\n"; + std::string cmd = R"(C:\Windows\System32\WindowsPowershell\v1.0\powershell.exe "New-NetFirewallRule -DisplayName zerotier-icmpv6-)" + nwString2 + address + R"( -InterfaceAlias 'ZeroTier One `[)" + nwString2 + R"(`]')" + + " -Protocol ICMPv6 -Action Allow" + " -LocalAddress " + address + "\"\r\n"; - _run(cmd); + _run(cmd); } void WinFWHelper::removeICMPv4Rule(std::string addr, uint64_t nwid) { - // removes 1 icmp firewall rule + // removes 1 icmp firewall rule - char nwString[32] = { 0 }; - sprintf(nwString, "%.16llx", nwid); - std::string nwString2 = { nwString }; + char nwString[32] = { 0 }; + sprintf(nwString, "%.16llx", nwid); + std::string nwString2 = { nwString }; - std::string cmd = R"(C:\Windows\System32\WindowsPowershell\v1.0\powershell.exe "Remove-NetFirewallRule -DisplayName zerotier-icmpv4-)" + nwString2 + addr + - "\"\r\n"; + std::string cmd = R"(C:\Windows\System32\WindowsPowershell\v1.0\powershell.exe "Remove-NetFirewallRule -DisplayName zerotier-icmpv4-)" + nwString2 + addr + "\"\r\n"; - _run(cmd); + _run(cmd); } void WinFWHelper::removeICMPv6Rule(std::string addr, uint64_t nwid) { - // removes 1 icmp firewall rule + // removes 1 icmp firewall rule - char nwString[32] = { 0 }; - sprintf(nwString, "%.16llx", nwid); - std::string nwString2 = { nwString }; + char nwString[32] = { 0 }; + sprintf(nwString, "%.16llx", nwid); + std::string nwString2 = { nwString }; - std::string cmd = R"(C:\Windows\System32\WindowsPowershell\v1.0\powershell.exe "Remove-NetFirewallRule -DisplayName zerotier-icmpv6-)" + nwString2 + addr + - "\"\r\n"; + std::string cmd = R"(C:\Windows\System32\WindowsPowershell\v1.0\powershell.exe "Remove-NetFirewallRule -DisplayName zerotier-icmpv6-)" + nwString2 + addr + "\"\r\n"; - _run(cmd); + _run(cmd); } void WinFWHelper::removeICMPv4Rules(uint64_t nwid) { - // removes all icmp firewall rules for this network id + // removes all icmp firewall rules for this network id - char nwString[32] = { 0 }; - sprintf(nwString, "%.16llx", nwid); - std::string nwString2 = { nwString }; + char nwString[32] = { 0 }; + sprintf(nwString, "%.16llx", nwid); + std::string nwString2 = { nwString }; - std::string cmd = R"(C:\Windows\System32\WindowsPowershell\v1.0\powershell.exe "Remove-NetFirewallRule -DisplayName zerotier-icmpv4-)" + nwString2 + "*\" \r\n"; - - _run(cmd); + std::string cmd = R"(C:\Windows\System32\WindowsPowershell\v1.0\powershell.exe "Remove-NetFirewallRule -DisplayName zerotier-icmpv4-)" + nwString2 + "*\" \r\n"; + + _run(cmd); } void WinFWHelper::removeICMPv6Rules(uint64_t nwid) { - // removes all icmp firewall rules for this network id + // removes all icmp firewall rules for this network id - char nwString[32] = { 0 }; - sprintf(nwString, "%.16llx", nwid); - std::string nwString2 = { nwString }; + char nwString[32] = { 0 }; + sprintf(nwString, "%.16llx", nwid); + std::string nwString2 = { nwString }; - std::string cmd = R"(C:\Windows\System32\WindowsPowershell\v1.0\powershell.exe "Remove-NetFirewallRule -DisplayName zerotier-icmpv6-)" + nwString2 + "*\" \r\n"; + std::string cmd = R"(C:\Windows\System32\WindowsPowershell\v1.0\powershell.exe "Remove-NetFirewallRule -DisplayName zerotier-icmpv6-)" + nwString2 + "*\" \r\n"; - _run(cmd); + _run(cmd); } void WinFWHelper::removeICMPRules() { - // removes all icmp firewall rules for all networks + // removes all icmp firewall rules for all networks - std::string cmd = R"(C:\Windows\System32\WindowsPowershell\v1.0\powershell.exe "Remove-NetFirewallRule -DisplayName zerotier-icmp*)" + std::string("\r\n"); + std::string cmd = R"(C:\Windows\System32\WindowsPowershell\v1.0\powershell.exe "Remove-NetFirewallRule -DisplayName zerotier-icmp*)" + std::string("\r\n"); - _run(cmd); + _run(cmd); } void WinFWHelper::removeICMPRules(uint64_t nwid) { - // removes all icmp firewall rules for this network - WinFWHelper::removeICMPv4Rules(nwid); - WinFWHelper::removeICMPv6Rules(nwid); + // removes all icmp firewall rules for this network + WinFWHelper::removeICMPv4Rules(nwid); + WinFWHelper::removeICMPv6Rules(nwid); } - - void WinFWHelper::_run(std::string cmd) { - - #ifdef ZT_DEBUG - fprintf(stderr, cmd.c_str()); - #endif +#ifdef ZT_DEBUG + fprintf(stderr, cmd.c_str()); +#endif - STARTUPINFOA startupInfo; - PROCESS_INFORMATION processInfo; - startupInfo.cb = sizeof(startupInfo); - memset(&startupInfo, 0, sizeof(STARTUPINFOA)); - memset(&processInfo, 0, sizeof(PROCESS_INFORMATION)); + STARTUPINFOA startupInfo; + PROCESS_INFORMATION processInfo; + startupInfo.cb = sizeof(startupInfo); + memset(&startupInfo, 0, sizeof(STARTUPINFOA)); + memset(&processInfo, 0, sizeof(PROCESS_INFORMATION)); - if (CreateProcessA(NULL, (LPSTR)cmd.c_str(), NULL, NULL, FALSE, CREATE_NO_WINDOW, NULL, NULL, &startupInfo, &processInfo)) { - WaitForSingleObject(processInfo.hProcess, INFINITE); + if (CreateProcessA(NULL, (LPSTR)cmd.c_str(), NULL, NULL, FALSE, CREATE_NO_WINDOW, NULL, NULL, &startupInfo, &processInfo)) { + WaitForSingleObject(processInfo.hProcess, INFINITE); - CloseHandle(processInfo.hProcess); - CloseHandle(processInfo.hThread); - } + CloseHandle(processInfo.hProcess); + CloseHandle(processInfo.hThread); + } } - - -} // namespace ZeroTier \ No newline at end of file +} // namespace ZeroTier \ No newline at end of file diff --git a/osdep/WinFWHelper.hpp b/osdep/WinFWHelper.hpp index a8d9e27a..2eb6cca5 100644 --- a/osdep/WinFWHelper.hpp +++ b/osdep/WinFWHelper.hpp @@ -10,22 +10,21 @@ namespace ZeroTier { class WinFWHelper { public: - static void newICMPRule(const InetAddress& ip, uint64_t nwid); - static void removeICMPRule(const InetAddress& ip, uint64_t nwid); - static void removeICMPRules(uint64_t nwid); - static void removeICMPRules(); - + static void newICMPRule(const InetAddress& ip, uint64_t nwid); + static void removeICMPRule(const InetAddress& ip, uint64_t nwid); + static void removeICMPRules(uint64_t nwid); + static void removeICMPRules(); private: - static void _run(std::string cmd); - static void newICMPv4Rule(std::string address, uint64_t nwid); - static void newICMPv6Rule(std::string address, uint64_t nwid); - static void removeICMPv4Rule(std::string address, uint64_t nwid); - static void removeICMPv6Rule(std::string address, uint64_t nwid); - static void removeICMPv4Rules(uint64_t nwid); - static void removeICMPv6Rules(uint64_t nwid); + static void _run(std::string cmd); + static void newICMPv4Rule(std::string address, uint64_t nwid); + static void newICMPv6Rule(std::string address, uint64_t nwid); + static void removeICMPv4Rule(std::string address, uint64_t nwid); + static void removeICMPv6Rule(std::string address, uint64_t nwid); + static void removeICMPv4Rules(uint64_t nwid); + static void removeICMPv6Rules(uint64_t nwid); }; -} // namespace ZeroTier +} // namespace ZeroTier #endif \ No newline at end of file diff --git a/osdep/WindowsEthernetTap.cpp b/osdep/WindowsEthernetTap.cpp index 9d644b17..d000b9ec 100644 --- a/osdep/WindowsEthernetTap.cpp +++ b/osdep/WindowsEthernetTap.cpp @@ -11,181 +11,187 @@ */ /****/ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include +#include "WindowsEthernetTap.hpp" #include "../node/Constants.hpp" -#include "../node/Utils.hpp" #include "../node/Mutex.hpp" - -#include "WindowsEthernetTap.hpp" -#include "OSUtils.hpp" - +#include "../node/Utils.hpp" #include "..\windows\TapDriver6\tap-windows.h" +#include "OSUtils.hpp" #include "WinDNSHelper.hpp" +#include +#include +#include +#include +#include +#include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include // Create a fake unused default route to force detection of network type on networks without gateways #define ZT_WINDOWS_CREATE_FAKE_DEFAULT_ROUTE // Function signatures of dynamically loaded functions, from newdev.h, setupapi.h, and cfgmgr32.h -typedef BOOL (WINAPI *UpdateDriverForPlugAndPlayDevicesA_t)(_In_opt_ HWND hwndParent,_In_ LPCSTR HardwareId,_In_ LPCSTR FullInfPath,_In_ DWORD InstallFlags,_Out_opt_ PBOOL bRebootRequired); -typedef BOOL (WINAPI *SetupDiGetINFClassA_t)(_In_ PCSTR InfName,_Out_ LPGUID ClassGuid,_Out_writes_(ClassNameSize) PSTR ClassName,_In_ DWORD ClassNameSize,_Out_opt_ PDWORD RequiredSize); -typedef HDEVINFO (WINAPI *SetupDiCreateDeviceInfoList_t)(_In_opt_ CONST GUID *ClassGuid,_In_opt_ HWND hwndParent); -typedef BOOL (WINAPI *SetupDiCreateDeviceInfoA_t)(_In_ HDEVINFO DeviceInfoSet,_In_ PCSTR DeviceName,_In_ CONST GUID *ClassGuid,_In_opt_ PCSTR DeviceDescription,_In_opt_ HWND hwndParent,_In_ DWORD CreationFlags,_Out_opt_ PSP_DEVINFO_DATA DeviceInfoData); -typedef BOOL (WINAPI *SetupDiSetDeviceRegistryPropertyA_t)(_In_ HDEVINFO DeviceInfoSet,_Inout_ PSP_DEVINFO_DATA DeviceInfoData,_In_ DWORD Property,_In_reads_bytes_opt_(PropertyBufferSize) CONST BYTE *PropertyBuffer,_In_ DWORD PropertyBufferSize); -typedef BOOL (WINAPI *SetupDiCallClassInstaller_t)(_In_ DI_FUNCTION InstallFunction,_In_ HDEVINFO DeviceInfoSet,_In_opt_ PSP_DEVINFO_DATA DeviceInfoData); -typedef BOOL (WINAPI *SetupDiDestroyDeviceInfoList_t)(_In_ HDEVINFO DeviceInfoSet); -typedef HDEVINFO (WINAPI *SetupDiGetClassDevsExA_t)(_In_opt_ CONST GUID *ClassGuid,_In_opt_ PCSTR Enumerator,_In_opt_ HWND hwndParent,_In_ DWORD Flags,_In_opt_ HDEVINFO DeviceInfoSet,_In_opt_ PCSTR MachineName,_Reserved_ PVOID Reserved); -typedef BOOL (WINAPI *SetupDiOpenDeviceInfoA_t)(_In_ HDEVINFO DeviceInfoSet,_In_ PCSTR DeviceInstanceId,_In_opt_ HWND hwndParent,_In_ DWORD OpenFlags,_Out_opt_ PSP_DEVINFO_DATA DeviceInfoData); -typedef BOOL (WINAPI *SetupDiEnumDeviceInfo_t)(_In_ HDEVINFO DeviceInfoSet,_In_ DWORD MemberIndex,_Out_ PSP_DEVINFO_DATA DeviceInfoData); -typedef BOOL (WINAPI *SetupDiSetClassInstallParamsA_t)(_In_ HDEVINFO DeviceInfoSet,_In_opt_ PSP_DEVINFO_DATA DeviceInfoData,_In_reads_bytes_opt_(ClassInstallParamsSize) PSP_CLASSINSTALL_HEADER ClassInstallParams,_In_ DWORD ClassInstallParamsSize); -typedef CONFIGRET (WINAPI *CM_Get_Device_ID_ExA_t)(_In_ DEVINST dnDevInst,_Out_writes_(BufferLen) PSTR Buffer,_In_ ULONG BufferLen,_In_ ULONG ulFlags,_In_opt_ HMACHINE hMachine); -typedef BOOL (WINAPI *SetupDiGetDeviceInstanceIdA_t)(_In_ HDEVINFO DeviceInfoSet,_In_ PSP_DEVINFO_DATA DeviceInfoData,_Out_writes_opt_(DeviceInstanceIdSize) PSTR DeviceInstanceId,_In_ DWORD DeviceInstanceIdSize,_Out_opt_ PDWORD RequiredSize); +typedef BOOL(WINAPI* UpdateDriverForPlugAndPlayDevicesA_t)(_In_opt_ HWND hwndParent, _In_ LPCSTR HardwareId, _In_ LPCSTR FullInfPath, _In_ DWORD InstallFlags, _Out_opt_ PBOOL bRebootRequired); +typedef BOOL(WINAPI* SetupDiGetINFClassA_t)(_In_ PCSTR InfName, _Out_ LPGUID ClassGuid, _Out_writes_(ClassNameSize) PSTR ClassName, _In_ DWORD ClassNameSize, _Out_opt_ PDWORD RequiredSize); +typedef HDEVINFO(WINAPI* SetupDiCreateDeviceInfoList_t)(_In_opt_ CONST GUID* ClassGuid, _In_opt_ HWND hwndParent); +typedef BOOL(WINAPI* SetupDiCreateDeviceInfoA_t)( + _In_ HDEVINFO DeviceInfoSet, + _In_ PCSTR DeviceName, + _In_ CONST GUID* ClassGuid, + _In_opt_ PCSTR DeviceDescription, + _In_opt_ HWND hwndParent, + _In_ DWORD CreationFlags, + _Out_opt_ PSP_DEVINFO_DATA DeviceInfoData); +typedef BOOL( + WINAPI* SetupDiSetDeviceRegistryPropertyA_t)(_In_ HDEVINFO DeviceInfoSet, _Inout_ PSP_DEVINFO_DATA DeviceInfoData, _In_ DWORD Property, _In_reads_bytes_opt_(PropertyBufferSize) CONST BYTE* PropertyBuffer, _In_ DWORD PropertyBufferSize); +typedef BOOL(WINAPI* SetupDiCallClassInstaller_t)(_In_ DI_FUNCTION InstallFunction, _In_ HDEVINFO DeviceInfoSet, _In_opt_ PSP_DEVINFO_DATA DeviceInfoData); +typedef BOOL(WINAPI* SetupDiDestroyDeviceInfoList_t)(_In_ HDEVINFO DeviceInfoSet); +typedef HDEVINFO( + WINAPI* SetupDiGetClassDevsExA_t)(_In_opt_ CONST GUID* ClassGuid, _In_opt_ PCSTR Enumerator, _In_opt_ HWND hwndParent, _In_ DWORD Flags, _In_opt_ HDEVINFO DeviceInfoSet, _In_opt_ PCSTR MachineName, _Reserved_ PVOID Reserved); +typedef BOOL(WINAPI* SetupDiOpenDeviceInfoA_t)(_In_ HDEVINFO DeviceInfoSet, _In_ PCSTR DeviceInstanceId, _In_opt_ HWND hwndParent, _In_ DWORD OpenFlags, _Out_opt_ PSP_DEVINFO_DATA DeviceInfoData); +typedef BOOL(WINAPI* SetupDiEnumDeviceInfo_t)(_In_ HDEVINFO DeviceInfoSet, _In_ DWORD MemberIndex, _Out_ PSP_DEVINFO_DATA DeviceInfoData); +typedef BOOL( + WINAPI* SetupDiSetClassInstallParamsA_t)(_In_ HDEVINFO DeviceInfoSet, _In_opt_ PSP_DEVINFO_DATA DeviceInfoData, _In_reads_bytes_opt_(ClassInstallParamsSize) PSP_CLASSINSTALL_HEADER ClassInstallParams, _In_ DWORD ClassInstallParamsSize); +typedef CONFIGRET(WINAPI* CM_Get_Device_ID_ExA_t)(_In_ DEVINST dnDevInst, _Out_writes_(BufferLen) PSTR Buffer, _In_ ULONG BufferLen, _In_ ULONG ulFlags, _In_opt_ HMACHINE hMachine); +typedef BOOL( + WINAPI* SetupDiGetDeviceInstanceIdA_t)(_In_ HDEVINFO DeviceInfoSet, _In_ PSP_DEVINFO_DATA DeviceInfoData, _Out_writes_opt_(DeviceInstanceIdSize) PSTR DeviceInstanceId, _In_ DWORD DeviceInstanceIdSize, _Out_opt_ PDWORD RequiredSize); namespace ZeroTier { namespace { // Static/singleton class that when initialized loads a bunch of environment information and a few dynamically loaded DLLs -class WindowsEthernetTapEnv -{ -public: - WindowsEthernetTapEnv() - { +class WindowsEthernetTapEnv { + public: + WindowsEthernetTapEnv() + { #ifdef _WIN64 - is64Bit = TRUE; - //tapDriverPath = "\\tap-windows\\x64\\zttap300.inf"; + is64Bit = TRUE; + // tapDriverPath = "\\tap-windows\\x64\\zttap300.inf"; #else - is64Bit = FALSE; - IsWow64Process(GetCurrentProcess(),&is64Bit); - if (is64Bit) { - fprintf(stderr,"FATAL: you must use the 64-bit ZeroTier One service on 64-bit Windows systems\r\n"); - _exit(1); - } - //tapDriverPath = "\\tap-windows\\x86\\zttap300.inf"; + is64Bit = FALSE; + IsWow64Process(GetCurrentProcess(), &is64Bit); + if (is64Bit) { + fprintf(stderr, "FATAL: you must use the 64-bit ZeroTier One service on 64-bit Windows systems\r\n"); + _exit(1); + } + // tapDriverPath = "\\tap-windows\\x86\\zttap300.inf"; #endif - tapDriverName = "zttap300"; - tapDriverPath = "\\zttap300.inf"; + tapDriverName = "zttap300"; + tapDriverPath = "\\zttap300.inf"; - setupApiMod = LoadLibraryA("setupapi.dll"); - if (!setupApiMod) { - fprintf(stderr,"FATAL: unable to dynamically load setupapi.dll\r\n"); - _exit(1); - } - if (!(this->SetupDiGetINFClassA = (SetupDiGetINFClassA_t)GetProcAddress(setupApiMod,"SetupDiGetINFClassA"))) { - fprintf(stderr,"FATAL: SetupDiGetINFClassA not found in setupapi.dll\r\n"); - _exit(1); - } - if (!(this->SetupDiCreateDeviceInfoList = (SetupDiCreateDeviceInfoList_t)GetProcAddress(setupApiMod,"SetupDiCreateDeviceInfoList"))) { - fprintf(stderr,"FATAL: SetupDiCreateDeviceInfoList not found in setupapi.dll\r\n"); - _exit(1); - } - if (!(this->SetupDiCreateDeviceInfoA = (SetupDiCreateDeviceInfoA_t)GetProcAddress(setupApiMod,"SetupDiCreateDeviceInfoA"))) { - fprintf(stderr,"FATAL: SetupDiCreateDeviceInfoA not found in setupapi.dll\r\n"); - _exit(1); - } - if (!(this->SetupDiSetDeviceRegistryPropertyA = (SetupDiSetDeviceRegistryPropertyA_t)GetProcAddress(setupApiMod,"SetupDiSetDeviceRegistryPropertyA"))) { - fprintf(stderr,"FATAL: SetupDiSetDeviceRegistryPropertyA not found in setupapi.dll\r\n"); - _exit(1); - } - if (!(this->SetupDiCallClassInstaller = (SetupDiCallClassInstaller_t)GetProcAddress(setupApiMod,"SetupDiCallClassInstaller"))) { - fprintf(stderr,"FATAL: SetupDiCallClassInstaller not found in setupapi.dll\r\n"); - _exit(1); - } - if (!(this->SetupDiDestroyDeviceInfoList = (SetupDiDestroyDeviceInfoList_t)GetProcAddress(setupApiMod,"SetupDiDestroyDeviceInfoList"))) { - fprintf(stderr,"FATAL: SetupDiDestroyDeviceInfoList not found in setupapi.dll\r\n"); - _exit(1); - } - if (!(this->SetupDiGetClassDevsExA = (SetupDiGetClassDevsExA_t)GetProcAddress(setupApiMod,"SetupDiGetClassDevsExA"))) { - fprintf(stderr,"FATAL: SetupDiGetClassDevsExA not found in setupapi.dll\r\n"); - _exit(1); - } - if (!(this->SetupDiOpenDeviceInfoA = (SetupDiOpenDeviceInfoA_t)GetProcAddress(setupApiMod,"SetupDiOpenDeviceInfoA"))) { - fprintf(stderr,"FATAL: SetupDiOpenDeviceInfoA not found in setupapi.dll\r\n"); - _exit(1); - } - if (!(this->SetupDiEnumDeviceInfo = (SetupDiEnumDeviceInfo_t)GetProcAddress(setupApiMod,"SetupDiEnumDeviceInfo"))) { - fprintf(stderr,"FATAL: SetupDiEnumDeviceInfo not found in setupapi.dll\r\n"); - _exit(1); - } - if (!(this->SetupDiSetClassInstallParamsA = (SetupDiSetClassInstallParamsA_t)GetProcAddress(setupApiMod,"SetupDiSetClassInstallParamsA"))) { - fprintf(stderr,"FATAL: SetupDiSetClassInstallParamsA not found in setupapi.dll\r\n"); - _exit(1); - } - if (!(this->SetupDiGetDeviceInstanceIdA = (SetupDiGetDeviceInstanceIdA_t)GetProcAddress(setupApiMod,"SetupDiGetDeviceInstanceIdA"))) { - fprintf(stderr,"FATAL: SetupDiGetDeviceInstanceIdA not found in setupapi.dll\r\n"); - _exit(1); - } + setupApiMod = LoadLibraryA("setupapi.dll"); + if (! setupApiMod) { + fprintf(stderr, "FATAL: unable to dynamically load setupapi.dll\r\n"); + _exit(1); + } + if (! (this->SetupDiGetINFClassA = (SetupDiGetINFClassA_t)GetProcAddress(setupApiMod, "SetupDiGetINFClassA"))) { + fprintf(stderr, "FATAL: SetupDiGetINFClassA not found in setupapi.dll\r\n"); + _exit(1); + } + if (! (this->SetupDiCreateDeviceInfoList = (SetupDiCreateDeviceInfoList_t)GetProcAddress(setupApiMod, "SetupDiCreateDeviceInfoList"))) { + fprintf(stderr, "FATAL: SetupDiCreateDeviceInfoList not found in setupapi.dll\r\n"); + _exit(1); + } + if (! (this->SetupDiCreateDeviceInfoA = (SetupDiCreateDeviceInfoA_t)GetProcAddress(setupApiMod, "SetupDiCreateDeviceInfoA"))) { + fprintf(stderr, "FATAL: SetupDiCreateDeviceInfoA not found in setupapi.dll\r\n"); + _exit(1); + } + if (! (this->SetupDiSetDeviceRegistryPropertyA = (SetupDiSetDeviceRegistryPropertyA_t)GetProcAddress(setupApiMod, "SetupDiSetDeviceRegistryPropertyA"))) { + fprintf(stderr, "FATAL: SetupDiSetDeviceRegistryPropertyA not found in setupapi.dll\r\n"); + _exit(1); + } + if (! (this->SetupDiCallClassInstaller = (SetupDiCallClassInstaller_t)GetProcAddress(setupApiMod, "SetupDiCallClassInstaller"))) { + fprintf(stderr, "FATAL: SetupDiCallClassInstaller not found in setupapi.dll\r\n"); + _exit(1); + } + if (! (this->SetupDiDestroyDeviceInfoList = (SetupDiDestroyDeviceInfoList_t)GetProcAddress(setupApiMod, "SetupDiDestroyDeviceInfoList"))) { + fprintf(stderr, "FATAL: SetupDiDestroyDeviceInfoList not found in setupapi.dll\r\n"); + _exit(1); + } + if (! (this->SetupDiGetClassDevsExA = (SetupDiGetClassDevsExA_t)GetProcAddress(setupApiMod, "SetupDiGetClassDevsExA"))) { + fprintf(stderr, "FATAL: SetupDiGetClassDevsExA not found in setupapi.dll\r\n"); + _exit(1); + } + if (! (this->SetupDiOpenDeviceInfoA = (SetupDiOpenDeviceInfoA_t)GetProcAddress(setupApiMod, "SetupDiOpenDeviceInfoA"))) { + fprintf(stderr, "FATAL: SetupDiOpenDeviceInfoA not found in setupapi.dll\r\n"); + _exit(1); + } + if (! (this->SetupDiEnumDeviceInfo = (SetupDiEnumDeviceInfo_t)GetProcAddress(setupApiMod, "SetupDiEnumDeviceInfo"))) { + fprintf(stderr, "FATAL: SetupDiEnumDeviceInfo not found in setupapi.dll\r\n"); + _exit(1); + } + if (! (this->SetupDiSetClassInstallParamsA = (SetupDiSetClassInstallParamsA_t)GetProcAddress(setupApiMod, "SetupDiSetClassInstallParamsA"))) { + fprintf(stderr, "FATAL: SetupDiSetClassInstallParamsA not found in setupapi.dll\r\n"); + _exit(1); + } + if (! (this->SetupDiGetDeviceInstanceIdA = (SetupDiGetDeviceInstanceIdA_t)GetProcAddress(setupApiMod, "SetupDiGetDeviceInstanceIdA"))) { + fprintf(stderr, "FATAL: SetupDiGetDeviceInstanceIdA not found in setupapi.dll\r\n"); + _exit(1); + } - newDevMod = LoadLibraryA("newdev.dll"); - if (!newDevMod) { - fprintf(stderr,"FATAL: unable to dynamically load newdev.dll\r\n"); - _exit(1); - } - if (!(this->UpdateDriverForPlugAndPlayDevicesA = (UpdateDriverForPlugAndPlayDevicesA_t)GetProcAddress(newDevMod,"UpdateDriverForPlugAndPlayDevicesA"))) { - fprintf(stderr,"FATAL: UpdateDriverForPlugAndPlayDevicesA not found in newdev.dll\r\n"); - _exit(1); - } + newDevMod = LoadLibraryA("newdev.dll"); + if (! newDevMod) { + fprintf(stderr, "FATAL: unable to dynamically load newdev.dll\r\n"); + _exit(1); + } + if (! (this->UpdateDriverForPlugAndPlayDevicesA = (UpdateDriverForPlugAndPlayDevicesA_t)GetProcAddress(newDevMod, "UpdateDriverForPlugAndPlayDevicesA"))) { + fprintf(stderr, "FATAL: UpdateDriverForPlugAndPlayDevicesA not found in newdev.dll\r\n"); + _exit(1); + } - cfgMgrMod = LoadLibraryA("cfgmgr32.dll"); - if (!cfgMgrMod) { - fprintf(stderr,"FATAL: unable to dynamically load cfgmgr32.dll\r\n"); - _exit(1); - } - if (!(this->CM_Get_Device_ID_ExA = (CM_Get_Device_ID_ExA_t)GetProcAddress(cfgMgrMod,"CM_Get_Device_ID_ExA"))) { - fprintf(stderr,"FATAL: CM_Get_Device_ID_ExA not found in cfgmgr32.dll\r\n"); - _exit(1); - } - } + cfgMgrMod = LoadLibraryA("cfgmgr32.dll"); + if (! cfgMgrMod) { + fprintf(stderr, "FATAL: unable to dynamically load cfgmgr32.dll\r\n"); + _exit(1); + } + if (! (this->CM_Get_Device_ID_ExA = (CM_Get_Device_ID_ExA_t)GetProcAddress(cfgMgrMod, "CM_Get_Device_ID_ExA"))) { + fprintf(stderr, "FATAL: CM_Get_Device_ID_ExA not found in cfgmgr32.dll\r\n"); + _exit(1); + } + } - BOOL is64Bit; // is the system 64-bit, regardless of whether this binary is or not - std::string tapDriverPath; - std::string tapDriverName; + BOOL is64Bit; // is the system 64-bit, regardless of whether this binary is or not + std::string tapDriverPath; + std::string tapDriverName; - UpdateDriverForPlugAndPlayDevicesA_t UpdateDriverForPlugAndPlayDevicesA; + UpdateDriverForPlugAndPlayDevicesA_t UpdateDriverForPlugAndPlayDevicesA; - SetupDiGetINFClassA_t SetupDiGetINFClassA; - SetupDiCreateDeviceInfoList_t SetupDiCreateDeviceInfoList; - SetupDiCreateDeviceInfoA_t SetupDiCreateDeviceInfoA; - SetupDiSetDeviceRegistryPropertyA_t SetupDiSetDeviceRegistryPropertyA; - SetupDiCallClassInstaller_t SetupDiCallClassInstaller; - SetupDiDestroyDeviceInfoList_t SetupDiDestroyDeviceInfoList; - SetupDiGetClassDevsExA_t SetupDiGetClassDevsExA; - SetupDiOpenDeviceInfoA_t SetupDiOpenDeviceInfoA; - SetupDiEnumDeviceInfo_t SetupDiEnumDeviceInfo; - SetupDiSetClassInstallParamsA_t SetupDiSetClassInstallParamsA; - SetupDiGetDeviceInstanceIdA_t SetupDiGetDeviceInstanceIdA; + SetupDiGetINFClassA_t SetupDiGetINFClassA; + SetupDiCreateDeviceInfoList_t SetupDiCreateDeviceInfoList; + SetupDiCreateDeviceInfoA_t SetupDiCreateDeviceInfoA; + SetupDiSetDeviceRegistryPropertyA_t SetupDiSetDeviceRegistryPropertyA; + SetupDiCallClassInstaller_t SetupDiCallClassInstaller; + SetupDiDestroyDeviceInfoList_t SetupDiDestroyDeviceInfoList; + SetupDiGetClassDevsExA_t SetupDiGetClassDevsExA; + SetupDiOpenDeviceInfoA_t SetupDiOpenDeviceInfoA; + SetupDiEnumDeviceInfo_t SetupDiEnumDeviceInfo; + SetupDiSetClassInstallParamsA_t SetupDiSetClassInstallParamsA; + SetupDiGetDeviceInstanceIdA_t SetupDiGetDeviceInstanceIdA; - CM_Get_Device_ID_ExA_t CM_Get_Device_ID_ExA; + CM_Get_Device_ID_ExA_t CM_Get_Device_ID_ExA; -private: - HMODULE setupApiMod; - HMODULE newDevMod; - HMODULE cfgMgrMod; + private: + HMODULE setupApiMod; + HMODULE newDevMod; + HMODULE cfgMgrMod; }; static const WindowsEthernetTapEnv WINENV; @@ -195,1132 +201,1171 @@ static Mutex _systemTapInitLock; // Only perform installation or uninstallation options one at a time static Mutex _systemDeviceManagementLock; -} // anonymous namespace +} // anonymous namespace -std::string WindowsEthernetTap::addNewPersistentTapDevice(const char *pathToInf,std::string &deviceInstanceId) +std::string WindowsEthernetTap::addNewPersistentTapDevice(const char* pathToInf, std::string& deviceInstanceId) { - Mutex::Lock _l(_systemDeviceManagementLock); + Mutex::Lock _l(_systemDeviceManagementLock); - GUID classGuid; - char className[1024]; - if (!WINENV.SetupDiGetINFClassA(pathToInf,&classGuid,className,sizeof(className),(PDWORD)0)) { - return std::string("SetupDiGetINFClassA() failed -- unable to read zttap driver INF file"); - } + GUID classGuid; + char className[1024]; + if (! WINENV.SetupDiGetINFClassA(pathToInf, &classGuid, className, sizeof(className), (PDWORD)0)) { + return std::string("SetupDiGetINFClassA() failed -- unable to read zttap driver INF file"); + } - HDEVINFO deviceInfoSet = WINENV.SetupDiCreateDeviceInfoList(&classGuid,(HWND)0); - if (deviceInfoSet == INVALID_HANDLE_VALUE) { - return std::string("SetupDiCreateDeviceInfoList() failed"); - } + HDEVINFO deviceInfoSet = WINENV.SetupDiCreateDeviceInfoList(&classGuid, (HWND)0); + if (deviceInfoSet == INVALID_HANDLE_VALUE) { + return std::string("SetupDiCreateDeviceInfoList() failed"); + } - SP_DEVINFO_DATA deviceInfoData; - memset(&deviceInfoData,0,sizeof(deviceInfoData)); - deviceInfoData.cbSize = sizeof(deviceInfoData); - if (!WINENV.SetupDiCreateDeviceInfoA(deviceInfoSet,className,&classGuid,(PCSTR)0,(HWND)0,DICD_GENERATE_ID,&deviceInfoData)) { - WINENV.SetupDiDestroyDeviceInfoList(deviceInfoSet); - return std::string("SetupDiCreateDeviceInfoA() failed"); - } + SP_DEVINFO_DATA deviceInfoData; + memset(&deviceInfoData, 0, sizeof(deviceInfoData)); + deviceInfoData.cbSize = sizeof(deviceInfoData); + if (! WINENV.SetupDiCreateDeviceInfoA(deviceInfoSet, className, &classGuid, (PCSTR)0, (HWND)0, DICD_GENERATE_ID, &deviceInfoData)) { + WINENV.SetupDiDestroyDeviceInfoList(deviceInfoSet); + return std::string("SetupDiCreateDeviceInfoA() failed"); + } - if (!WINENV.SetupDiSetDeviceRegistryPropertyA(deviceInfoSet,&deviceInfoData,SPDRP_HARDWAREID,(const BYTE *)WINENV.tapDriverName.c_str(),(DWORD)(WINENV.tapDriverName.length() + 1))) { - WINENV.SetupDiDestroyDeviceInfoList(deviceInfoSet); - return std::string("SetupDiSetDeviceRegistryPropertyA() failed"); - } + if (! WINENV.SetupDiSetDeviceRegistryPropertyA(deviceInfoSet, &deviceInfoData, SPDRP_HARDWAREID, (const BYTE*)WINENV.tapDriverName.c_str(), (DWORD)(WINENV.tapDriverName.length() + 1))) { + WINENV.SetupDiDestroyDeviceInfoList(deviceInfoSet); + return std::string("SetupDiSetDeviceRegistryPropertyA() failed"); + } - if (!WINENV.SetupDiCallClassInstaller(DIF_REGISTERDEVICE,deviceInfoSet,&deviceInfoData)) { - WINENV.SetupDiDestroyDeviceInfoList(deviceInfoSet); - return std::string("SetupDiCallClassInstaller(DIF_REGISTERDEVICE) failed"); - } + if (! WINENV.SetupDiCallClassInstaller(DIF_REGISTERDEVICE, deviceInfoSet, &deviceInfoData)) { + WINENV.SetupDiDestroyDeviceInfoList(deviceInfoSet); + return std::string("SetupDiCallClassInstaller(DIF_REGISTERDEVICE) failed"); + } - // HACK: During upgrades, this can fail while the installer is still running. So make 60 attempts - // with a 1s delay between each attempt. - bool driverInstalled = false; - for(int retryCounter=0;retryCounter<60;++retryCounter) { - BOOL rebootRequired = FALSE; - if (WINENV.UpdateDriverForPlugAndPlayDevicesA((HWND)0,WINENV.tapDriverName.c_str(),pathToInf,INSTALLFLAG_FORCE|INSTALLFLAG_NONINTERACTIVE,&rebootRequired)) { - driverInstalled = true; - break; - } else Sleep(1000); - } - if (!driverInstalled) { - WINENV.SetupDiDestroyDeviceInfoList(deviceInfoSet); - return std::string("UpdateDriverForPlugAndPlayDevices() failed (made 60 attempts)"); - } + // HACK: During upgrades, this can fail while the installer is still running. So make 60 attempts + // with a 1s delay between each attempt. + bool driverInstalled = false; + for (int retryCounter = 0; retryCounter < 60; ++retryCounter) { + BOOL rebootRequired = FALSE; + if (WINENV.UpdateDriverForPlugAndPlayDevicesA((HWND)0, WINENV.tapDriverName.c_str(), pathToInf, INSTALLFLAG_FORCE | INSTALLFLAG_NONINTERACTIVE, &rebootRequired)) { + driverInstalled = true; + break; + } + else + Sleep(1000); + } + if (! driverInstalled) { + WINENV.SetupDiDestroyDeviceInfoList(deviceInfoSet); + return std::string("UpdateDriverForPlugAndPlayDevices() failed (made 60 attempts)"); + } - char iidbuf[1024]; - DWORD iidReqSize = sizeof(iidbuf); - if (WINENV.SetupDiGetDeviceInstanceIdA(deviceInfoSet,&deviceInfoData,iidbuf,sizeof(iidbuf),&iidReqSize)) { - deviceInstanceId = iidbuf; - } // failure here is not fatal since we only need this on Vista and 2008 -- other versions fill it into the registry automatically + char iidbuf[1024]; + DWORD iidReqSize = sizeof(iidbuf); + if (WINENV.SetupDiGetDeviceInstanceIdA(deviceInfoSet, &deviceInfoData, iidbuf, sizeof(iidbuf), &iidReqSize)) { + deviceInstanceId = iidbuf; + } // failure here is not fatal since we only need this on Vista and 2008 -- other versions fill it into the registry automatically - WINENV.SetupDiDestroyDeviceInfoList(deviceInfoSet); + WINENV.SetupDiDestroyDeviceInfoList(deviceInfoSet); - return std::string(); + return std::string(); } std::string WindowsEthernetTap::destroyAllLegacyPersistentTapDevices() { - char subkeyName[1024]; - char subkeyClass[1024]; - char data[1024]; + char subkeyName[1024]; + char subkeyClass[1024]; + char data[1024]; - std::set instanceIdPathsToRemove; - { - HKEY nwAdapters; - if (RegOpenKeyExA(HKEY_LOCAL_MACHINE,"SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002BE10318}",0,KEY_READ|KEY_WRITE,&nwAdapters) != ERROR_SUCCESS) - return std::string("Could not open registry key"); + std::set instanceIdPathsToRemove; + { + HKEY nwAdapters; + if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002BE10318}", 0, KEY_READ | KEY_WRITE, &nwAdapters) != ERROR_SUCCESS) + return std::string("Could not open registry key"); - for(DWORD subkeyIndex=0;;++subkeyIndex) { - DWORD type; - DWORD dataLen; - DWORD subkeyNameLen = sizeof(subkeyName); - DWORD subkeyClassLen = sizeof(subkeyClass); - FILETIME lastWriteTime; - if (RegEnumKeyExA(nwAdapters,subkeyIndex,subkeyName,&subkeyNameLen,(DWORD *)0,subkeyClass,&subkeyClassLen,&lastWriteTime) == ERROR_SUCCESS) { - type = 0; - dataLen = sizeof(data); - if (RegGetValueA(nwAdapters,subkeyName,"ComponentId",RRF_RT_ANY,&type,(PVOID)data,&dataLen) == ERROR_SUCCESS) { - data[dataLen] = '\0'; + for (DWORD subkeyIndex = 0;; ++subkeyIndex) { + DWORD type; + DWORD dataLen; + DWORD subkeyNameLen = sizeof(subkeyName); + DWORD subkeyClassLen = sizeof(subkeyClass); + FILETIME lastWriteTime; + if (RegEnumKeyExA(nwAdapters, subkeyIndex, subkeyName, &subkeyNameLen, (DWORD*)0, subkeyClass, &subkeyClassLen, &lastWriteTime) == ERROR_SUCCESS) { + type = 0; + dataLen = sizeof(data); + if (RegGetValueA(nwAdapters, subkeyName, "ComponentId", RRF_RT_ANY, &type, (PVOID)data, &dataLen) == ERROR_SUCCESS) { + data[dataLen] = '\0'; - if ((!strnicmp(data,"zttap",5))&&(WINENV.tapDriverName != data)) { - std::string instanceIdPath; - type = 0; - dataLen = sizeof(data); - if (RegGetValueA(nwAdapters,subkeyName,"DeviceInstanceID",RRF_RT_ANY,&type,(PVOID)data,&dataLen) == ERROR_SUCCESS) - instanceIdPath.assign(data,dataLen); - if (instanceIdPath.length() != 0) - instanceIdPathsToRemove.insert(instanceIdPath); - } - } - } else break; // end of list or failure - } + if ((! strnicmp(data, "zttap", 5)) && (WINENV.tapDriverName != data)) { + std::string instanceIdPath; + type = 0; + dataLen = sizeof(data); + if (RegGetValueA(nwAdapters, subkeyName, "DeviceInstanceID", RRF_RT_ANY, &type, (PVOID)data, &dataLen) == ERROR_SUCCESS) + instanceIdPath.assign(data, dataLen); + if (instanceIdPath.length() != 0) + instanceIdPathsToRemove.insert(instanceIdPath); + } + } + } + else + break; // end of list or failure + } - RegCloseKey(nwAdapters); - } + RegCloseKey(nwAdapters); + } - std::string errlist; - for(std::set::iterator iidp(instanceIdPathsToRemove.begin());iidp!=instanceIdPathsToRemove.end();++iidp) { - std::string err = deletePersistentTapDevice(iidp->c_str()); - if (err.length() > 0) { - if (errlist.length() > 0) - errlist.push_back(','); - errlist.append(err); - } - } - return errlist; + std::string errlist; + for (std::set::iterator iidp(instanceIdPathsToRemove.begin()); iidp != instanceIdPathsToRemove.end(); ++iidp) { + std::string err = deletePersistentTapDevice(iidp->c_str()); + if (err.length() > 0) { + if (errlist.length() > 0) + errlist.push_back(','); + errlist.append(err); + } + } + return errlist; } std::string WindowsEthernetTap::destroyAllPersistentTapDevices() { - char subkeyName[1024]; - char subkeyClass[1024]; - char data[1024]; + char subkeyName[1024]; + char subkeyClass[1024]; + char data[1024]; - std::set instanceIdPathsToRemove; - { - HKEY nwAdapters; - if (RegOpenKeyExA(HKEY_LOCAL_MACHINE,"SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002BE10318}",0,KEY_READ|KEY_WRITE,&nwAdapters) != ERROR_SUCCESS) - return std::string("Could not open registry key"); + std::set instanceIdPathsToRemove; + { + HKEY nwAdapters; + if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002BE10318}", 0, KEY_READ | KEY_WRITE, &nwAdapters) != ERROR_SUCCESS) + return std::string("Could not open registry key"); - for(DWORD subkeyIndex=0;;++subkeyIndex) { - DWORD type; - DWORD dataLen; - DWORD subkeyNameLen = sizeof(subkeyName); - DWORD subkeyClassLen = sizeof(subkeyClass); - FILETIME lastWriteTime; - if (RegEnumKeyExA(nwAdapters,subkeyIndex,subkeyName,&subkeyNameLen,(DWORD *)0,subkeyClass,&subkeyClassLen,&lastWriteTime) == ERROR_SUCCESS) { - type = 0; - dataLen = sizeof(data); - if (RegGetValueA(nwAdapters,subkeyName,"ComponentId",RRF_RT_ANY,&type,(PVOID)data,&dataLen) == ERROR_SUCCESS) { - data[dataLen] = '\0'; + for (DWORD subkeyIndex = 0;; ++subkeyIndex) { + DWORD type; + DWORD dataLen; + DWORD subkeyNameLen = sizeof(subkeyName); + DWORD subkeyClassLen = sizeof(subkeyClass); + FILETIME lastWriteTime; + if (RegEnumKeyExA(nwAdapters, subkeyIndex, subkeyName, &subkeyNameLen, (DWORD*)0, subkeyClass, &subkeyClassLen, &lastWriteTime) == ERROR_SUCCESS) { + type = 0; + dataLen = sizeof(data); + if (RegGetValueA(nwAdapters, subkeyName, "ComponentId", RRF_RT_ANY, &type, (PVOID)data, &dataLen) == ERROR_SUCCESS) { + data[dataLen] = '\0'; - if (!strnicmp(data,"zttap",5)) { - std::string instanceIdPath; - type = 0; - dataLen = sizeof(data); - if (RegGetValueA(nwAdapters,subkeyName,"DeviceInstanceID",RRF_RT_ANY,&type,(PVOID)data,&dataLen) == ERROR_SUCCESS) - instanceIdPath.assign(data,dataLen); - if (instanceIdPath.length() != 0) - instanceIdPathsToRemove.insert(instanceIdPath); - } - } - } else break; // end of list or failure - } + if (! strnicmp(data, "zttap", 5)) { + std::string instanceIdPath; + type = 0; + dataLen = sizeof(data); + if (RegGetValueA(nwAdapters, subkeyName, "DeviceInstanceID", RRF_RT_ANY, &type, (PVOID)data, &dataLen) == ERROR_SUCCESS) + instanceIdPath.assign(data, dataLen); + if (instanceIdPath.length() != 0) + instanceIdPathsToRemove.insert(instanceIdPath); + } + } + } + else + break; // end of list or failure + } - RegCloseKey(nwAdapters); - } + RegCloseKey(nwAdapters); + } - std::string errlist; - for(std::set::iterator iidp(instanceIdPathsToRemove.begin());iidp!=instanceIdPathsToRemove.end();++iidp) { - std::string err = deletePersistentTapDevice(iidp->c_str()); - if (err.length() > 0) { - if (errlist.length() > 0) - errlist.push_back(','); - errlist.append(err); - } - } - return errlist; + std::string errlist; + for (std::set::iterator iidp(instanceIdPathsToRemove.begin()); iidp != instanceIdPathsToRemove.end(); ++iidp) { + std::string err = deletePersistentTapDevice(iidp->c_str()); + if (err.length() > 0) { + if (errlist.length() > 0) + errlist.push_back(','); + errlist.append(err); + } + } + return errlist; } -std::string WindowsEthernetTap::deletePersistentTapDevice(const char *instanceId) +std::string WindowsEthernetTap::deletePersistentTapDevice(const char* instanceId) { - char iid[256]; - SP_REMOVEDEVICE_PARAMS rmdParams; + char iid[256]; + SP_REMOVEDEVICE_PARAMS rmdParams; - memset(&rmdParams,0,sizeof(rmdParams)); - rmdParams.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER); - rmdParams.ClassInstallHeader.InstallFunction = DIF_REMOVE; - rmdParams.Scope = DI_REMOVEDEVICE_GLOBAL; - rmdParams.HwProfile = 0; + memset(&rmdParams, 0, sizeof(rmdParams)); + rmdParams.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER); + rmdParams.ClassInstallHeader.InstallFunction = DIF_REMOVE; + rmdParams.Scope = DI_REMOVEDEVICE_GLOBAL; + rmdParams.HwProfile = 0; - Mutex::Lock _l(_systemDeviceManagementLock); + Mutex::Lock _l(_systemDeviceManagementLock); - HDEVINFO devInfo = WINENV.SetupDiGetClassDevsExA((const GUID *)0,(PCSTR)0,(HWND)0,DIGCF_ALLCLASSES,(HDEVINFO)0,(PCSTR)0,(PVOID)0); - if (devInfo == INVALID_HANDLE_VALUE) - return std::string("SetupDiGetClassDevsExA() failed"); - WINENV.SetupDiOpenDeviceInfoA(devInfo,instanceId,(HWND)0,0,(PSP_DEVINFO_DATA)0); + HDEVINFO devInfo = WINENV.SetupDiGetClassDevsExA((const GUID*)0, (PCSTR)0, (HWND)0, DIGCF_ALLCLASSES, (HDEVINFO)0, (PCSTR)0, (PVOID)0); + if (devInfo == INVALID_HANDLE_VALUE) + return std::string("SetupDiGetClassDevsExA() failed"); + WINENV.SetupDiOpenDeviceInfoA(devInfo, instanceId, (HWND)0, 0, (PSP_DEVINFO_DATA)0); - SP_DEVINFO_DATA devInfoData; - memset(&devInfoData,0,sizeof(devInfoData)); - devInfoData.cbSize = sizeof(devInfoData); - for(DWORD devIndex=0;WINENV.SetupDiEnumDeviceInfo(devInfo,devIndex,&devInfoData);devIndex++) { - if ((WINENV.CM_Get_Device_ID_ExA(devInfoData.DevInst,iid,sizeof(iid),0,(HMACHINE)0) == CR_SUCCESS)&&(!strcmp(iid,instanceId))) { - if (!WINENV.SetupDiSetClassInstallParamsA(devInfo,&devInfoData,&rmdParams.ClassInstallHeader,sizeof(rmdParams))) { - WINENV.SetupDiDestroyDeviceInfoList(devInfo); - return std::string("SetupDiSetClassInstallParams() failed"); - } + SP_DEVINFO_DATA devInfoData; + memset(&devInfoData, 0, sizeof(devInfoData)); + devInfoData.cbSize = sizeof(devInfoData); + for (DWORD devIndex = 0; WINENV.SetupDiEnumDeviceInfo(devInfo, devIndex, &devInfoData); devIndex++) { + if ((WINENV.CM_Get_Device_ID_ExA(devInfoData.DevInst, iid, sizeof(iid), 0, (HMACHINE)0) == CR_SUCCESS) && (! strcmp(iid, instanceId))) { + if (! WINENV.SetupDiSetClassInstallParamsA(devInfo, &devInfoData, &rmdParams.ClassInstallHeader, sizeof(rmdParams))) { + WINENV.SetupDiDestroyDeviceInfoList(devInfo); + return std::string("SetupDiSetClassInstallParams() failed"); + } - if (!WINENV.SetupDiCallClassInstaller(DIF_REMOVE,devInfo,&devInfoData)) { - WINENV.SetupDiDestroyDeviceInfoList(devInfo); - return std::string("SetupDiCallClassInstaller(DIF_REMOVE) failed"); - } + if (! WINENV.SetupDiCallClassInstaller(DIF_REMOVE, devInfo, &devInfoData)) { + WINENV.SetupDiDestroyDeviceInfoList(devInfo); + return std::string("SetupDiCallClassInstaller(DIF_REMOVE) failed"); + } - WINENV.SetupDiDestroyDeviceInfoList(devInfo); - return std::string(); - } - } + WINENV.SetupDiDestroyDeviceInfoList(devInfo); + return std::string(); + } + } - WINENV.SetupDiDestroyDeviceInfoList(devInfo); - return std::string("instance ID not found"); + WINENV.SetupDiDestroyDeviceInfoList(devInfo); + return std::string("instance ID not found"); } -bool WindowsEthernetTap::setPersistentTapDeviceState(const char *instanceId,bool enabled) +bool WindowsEthernetTap::setPersistentTapDeviceState(const char* instanceId, bool enabled) { - char iid[256]; - SP_PROPCHANGE_PARAMS params; + char iid[256]; + SP_PROPCHANGE_PARAMS params; - Mutex::Lock _l(_systemDeviceManagementLock); + Mutex::Lock _l(_systemDeviceManagementLock); - HDEVINFO devInfo = WINENV.SetupDiGetClassDevsExA((const GUID *)0,(PCSTR)0,(HWND)0,DIGCF_ALLCLASSES,(HDEVINFO)0,(PCSTR)0,(PVOID)0); - if (devInfo == INVALID_HANDLE_VALUE) - return false; - WINENV.SetupDiOpenDeviceInfoA(devInfo,instanceId,(HWND)0,0,(PSP_DEVINFO_DATA)0); + HDEVINFO devInfo = WINENV.SetupDiGetClassDevsExA((const GUID*)0, (PCSTR)0, (HWND)0, DIGCF_ALLCLASSES, (HDEVINFO)0, (PCSTR)0, (PVOID)0); + if (devInfo == INVALID_HANDLE_VALUE) + return false; + WINENV.SetupDiOpenDeviceInfoA(devInfo, instanceId, (HWND)0, 0, (PSP_DEVINFO_DATA)0); - SP_DEVINFO_DATA devInfoData; - memset(&devInfoData,0,sizeof(devInfoData)); - devInfoData.cbSize = sizeof(devInfoData); - for(DWORD devIndex=0;WINENV.SetupDiEnumDeviceInfo(devInfo,devIndex,&devInfoData);devIndex++) { - if ((WINENV.CM_Get_Device_ID_ExA(devInfoData.DevInst,iid,sizeof(iid),0,(HMACHINE)0) == CR_SUCCESS)&&(!strcmp(iid,instanceId))) { - memset(¶ms,0,sizeof(params)); - params.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER); - params.ClassInstallHeader.InstallFunction = DIF_PROPERTYCHANGE; - params.StateChange = enabled ? DICS_ENABLE : DICS_DISABLE; - params.Scope = DICS_FLAG_GLOBAL; - params.HwProfile = 0; + SP_DEVINFO_DATA devInfoData; + memset(&devInfoData, 0, sizeof(devInfoData)); + devInfoData.cbSize = sizeof(devInfoData); + for (DWORD devIndex = 0; WINENV.SetupDiEnumDeviceInfo(devInfo, devIndex, &devInfoData); devIndex++) { + if ((WINENV.CM_Get_Device_ID_ExA(devInfoData.DevInst, iid, sizeof(iid), 0, (HMACHINE)0) == CR_SUCCESS) && (! strcmp(iid, instanceId))) { + memset(¶ms, 0, sizeof(params)); + params.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER); + params.ClassInstallHeader.InstallFunction = DIF_PROPERTYCHANGE; + params.StateChange = enabled ? DICS_ENABLE : DICS_DISABLE; + params.Scope = DICS_FLAG_GLOBAL; + params.HwProfile = 0; - WINENV.SetupDiSetClassInstallParamsA(devInfo,&devInfoData,¶ms.ClassInstallHeader,sizeof(params)); - WINENV.SetupDiCallClassInstaller(DIF_PROPERTYCHANGE,devInfo,&devInfoData); + WINENV.SetupDiSetClassInstallParamsA(devInfo, &devInfoData, ¶ms.ClassInstallHeader, sizeof(params)); + WINENV.SetupDiCallClassInstaller(DIF_PROPERTYCHANGE, devInfo, &devInfoData); - memset(¶ms,0,sizeof(params)); - params.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER); - params.ClassInstallHeader.InstallFunction = DIF_PROPERTYCHANGE; - params.StateChange = enabled ? DICS_ENABLE : DICS_DISABLE; - params.Scope = DICS_FLAG_CONFIGSPECIFIC; - params.HwProfile = 0; + memset(¶ms, 0, sizeof(params)); + params.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER); + params.ClassInstallHeader.InstallFunction = DIF_PROPERTYCHANGE; + params.StateChange = enabled ? DICS_ENABLE : DICS_DISABLE; + params.Scope = DICS_FLAG_CONFIGSPECIFIC; + params.HwProfile = 0; - WINENV.SetupDiSetClassInstallParamsA(devInfo,&devInfoData,¶ms.ClassInstallHeader,sizeof(params)); - WINENV.SetupDiCallClassInstaller(DIF_PROPERTYCHANGE,devInfo,&devInfoData); + WINENV.SetupDiSetClassInstallParamsA(devInfo, &devInfoData, ¶ms.ClassInstallHeader, sizeof(params)); + WINENV.SetupDiCallClassInstaller(DIF_PROPERTYCHANGE, devInfo, &devInfoData); - WINENV.SetupDiDestroyDeviceInfoList(devInfo); - return true; - } - } + WINENV.SetupDiDestroyDeviceInfoList(devInfo); + return true; + } + } - WINENV.SetupDiDestroyDeviceInfoList(devInfo); - return false; + WINENV.SetupDiDestroyDeviceInfoList(devInfo); + return false; } WindowsEthernetTap::WindowsEthernetTap( - const char *hp, - const MAC &mac, - unsigned int mtu, - unsigned int metric, - uint64_t nwid, - const char *friendlyName, - void (*handler)(void *,void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int), - void *arg) : - _handler(handler), - _arg(arg), - _mac(mac), - _nwid(nwid), - _mtu(mtu), - _tap(INVALID_HANDLE_VALUE), - _friendlyName(friendlyName), - _injectSemaphore(INVALID_HANDLE_VALUE), - _pathToHelpers(hp), - _run(true), - _initialized(false), - _enabled(true), - _lastIfAddrsUpdate(0) + const char* hp, + const MAC& mac, + unsigned int mtu, + unsigned int metric, + uint64_t nwid, + const char* friendlyName, + void (*handler)(void*, void*, uint64_t, const MAC&, const MAC&, unsigned int, unsigned int, const void*, unsigned int), + void* arg) + : _handler(handler) + , _arg(arg) + , _mac(mac) + , _nwid(nwid) + , _mtu(mtu) + , _tap(INVALID_HANDLE_VALUE) + , _friendlyName(friendlyName) + , _injectSemaphore(INVALID_HANDLE_VALUE) + , _pathToHelpers(hp) + , _run(true) + , _initialized(false) + , _enabled(true) + , _lastIfAddrsUpdate(0) { - char subkeyName[1024]; - char subkeyClass[1024]; - char data[1024]; - char tag[24]; + char subkeyName[1024]; + char subkeyClass[1024]; + char data[1024]; + char tag[24]; - // We "tag" registry entries with the network ID to identify persistent devices - OSUtils::ztsnprintf(tag,sizeof(tag),"%.16llx",(unsigned long long)nwid); + // We "tag" registry entries with the network ID to identify persistent devices + OSUtils::ztsnprintf(tag, sizeof(tag), "%.16llx", (unsigned long long)nwid); - Mutex::Lock _l(_systemTapInitLock); + Mutex::Lock _l(_systemTapInitLock); - HKEY nwAdapters; - if (RegOpenKeyExA(HKEY_LOCAL_MACHINE,"SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002BE10318}",0,KEY_READ|KEY_WRITE,&nwAdapters) != ERROR_SUCCESS) - throw std::runtime_error("unable to open registry key for network adapter enumeration"); + HKEY nwAdapters; + if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002BE10318}", 0, KEY_READ | KEY_WRITE, &nwAdapters) != ERROR_SUCCESS) + throw std::runtime_error("unable to open registry key for network adapter enumeration"); - // Look for the tap instance that corresponds with this network - for(DWORD subkeyIndex=0;;++subkeyIndex) { - DWORD type; - DWORD dataLen; - DWORD subkeyNameLen = sizeof(subkeyName); - DWORD subkeyClassLen = sizeof(subkeyClass); - FILETIME lastWriteTime; - if (RegEnumKeyExA(nwAdapters,subkeyIndex,subkeyName,&subkeyNameLen,(DWORD *)0,subkeyClass,&subkeyClassLen,&lastWriteTime) == ERROR_SUCCESS) { - type = 0; - dataLen = sizeof(data); - if (RegGetValueA(nwAdapters,subkeyName,"ComponentId",RRF_RT_ANY,&type,(PVOID)data,&dataLen) == ERROR_SUCCESS) { - data[dataLen] = (char)0; + // Look for the tap instance that corresponds with this network + for (DWORD subkeyIndex = 0;; ++subkeyIndex) { + DWORD type; + DWORD dataLen; + DWORD subkeyNameLen = sizeof(subkeyName); + DWORD subkeyClassLen = sizeof(subkeyClass); + FILETIME lastWriteTime; + if (RegEnumKeyExA(nwAdapters, subkeyIndex, subkeyName, &subkeyNameLen, (DWORD*)0, subkeyClass, &subkeyClassLen, &lastWriteTime) == ERROR_SUCCESS) { + type = 0; + dataLen = sizeof(data); + if (RegGetValueA(nwAdapters, subkeyName, "ComponentId", RRF_RT_ANY, &type, (PVOID)data, &dataLen) == ERROR_SUCCESS) { + data[dataLen] = (char)0; - if (WINENV.tapDriverName == data) { - std::string instanceId; - type = 0; - dataLen = sizeof(data); - if (RegGetValueA(nwAdapters,subkeyName,"NetCfgInstanceId",RRF_RT_ANY,&type,(PVOID)data,&dataLen) == ERROR_SUCCESS) - instanceId.assign(data,dataLen); + if (WINENV.tapDriverName == data) { + std::string instanceId; + type = 0; + dataLen = sizeof(data); + if (RegGetValueA(nwAdapters, subkeyName, "NetCfgInstanceId", RRF_RT_ANY, &type, (PVOID)data, &dataLen) == ERROR_SUCCESS) + instanceId.assign(data, dataLen); - std::string instanceIdPath; - type = 0; - dataLen = sizeof(data); - if (RegGetValueA(nwAdapters,subkeyName,"DeviceInstanceID",RRF_RT_ANY,&type,(PVOID)data,&dataLen) == ERROR_SUCCESS) - instanceIdPath.assign(data,dataLen); + std::string instanceIdPath; + type = 0; + dataLen = sizeof(data); + if (RegGetValueA(nwAdapters, subkeyName, "DeviceInstanceID", RRF_RT_ANY, &type, (PVOID)data, &dataLen) == ERROR_SUCCESS) + instanceIdPath.assign(data, dataLen); - if ((_netCfgInstanceId.length() == 0)&&(instanceId.length() != 0)&&(instanceIdPath.length() != 0)) { - type = 0; - dataLen = sizeof(data); - if (RegGetValueA(nwAdapters,subkeyName,"_ZeroTierTapIdentifier",RRF_RT_ANY,&type,(PVOID)data,&dataLen) == ERROR_SUCCESS) { - data[dataLen] = '\0'; - if (!strcmp(data,tag)) { - _netCfgInstanceId = instanceId; - _deviceInstanceId = instanceIdPath; + if ((_netCfgInstanceId.length() == 0) && (instanceId.length() != 0) && (instanceIdPath.length() != 0)) { + type = 0; + dataLen = sizeof(data); + if (RegGetValueA(nwAdapters, subkeyName, "_ZeroTierTapIdentifier", RRF_RT_ANY, &type, (PVOID)data, &dataLen) == ERROR_SUCCESS) { + data[dataLen] = '\0'; + if (! strcmp(data, tag)) { + _netCfgInstanceId = instanceId; + _deviceInstanceId = instanceIdPath; - _mySubkeyName = subkeyName; - break; // found it! - } - } - } - } - } - } else break; // no more subkeys or error occurred enumerating them - } + _mySubkeyName = subkeyName; + break; // found it! + } + } + } + } + } + } + else + break; // no more subkeys or error occurred enumerating them + } - // If there is no device, try to create one - bool creatingNewDevice = (_netCfgInstanceId.length() == 0); - std::string newDeviceInstanceId; - if (creatingNewDevice) { - for(int getNewAttemptCounter=0;getNewAttemptCounter<2;++getNewAttemptCounter) { - for(DWORD subkeyIndex=0;;++subkeyIndex) { - DWORD type; - DWORD dataLen; - DWORD subkeyNameLen = sizeof(subkeyName); - DWORD subkeyClassLen = sizeof(subkeyClass); - FILETIME lastWriteTime; - if (RegEnumKeyExA(nwAdapters,subkeyIndex,subkeyName,&subkeyNameLen,(DWORD *)0,subkeyClass,&subkeyClassLen,&lastWriteTime) == ERROR_SUCCESS) { - type = 0; - dataLen = sizeof(data); - if (RegGetValueA(nwAdapters,subkeyName,"ComponentId",RRF_RT_ANY,&type,(PVOID)data,&dataLen) == ERROR_SUCCESS) { - data[dataLen] = '\0'; + // If there is no device, try to create one + bool creatingNewDevice = (_netCfgInstanceId.length() == 0); + std::string newDeviceInstanceId; + if (creatingNewDevice) { + for (int getNewAttemptCounter = 0; getNewAttemptCounter < 2; ++getNewAttemptCounter) { + for (DWORD subkeyIndex = 0;; ++subkeyIndex) { + DWORD type; + DWORD dataLen; + DWORD subkeyNameLen = sizeof(subkeyName); + DWORD subkeyClassLen = sizeof(subkeyClass); + FILETIME lastWriteTime; + if (RegEnumKeyExA(nwAdapters, subkeyIndex, subkeyName, &subkeyNameLen, (DWORD*)0, subkeyClass, &subkeyClassLen, &lastWriteTime) == ERROR_SUCCESS) { + type = 0; + dataLen = sizeof(data); + if (RegGetValueA(nwAdapters, subkeyName, "ComponentId", RRF_RT_ANY, &type, (PVOID)data, &dataLen) == ERROR_SUCCESS) { + data[dataLen] = '\0'; - if (WINENV.tapDriverName == data) { - type = 0; - dataLen = sizeof(data); - if ((RegGetValueA(nwAdapters,subkeyName,"_ZeroTierTapIdentifier",RRF_RT_ANY,&type,(PVOID)data,&dataLen) != ERROR_SUCCESS)||(dataLen <= 0)) { - type = 0; - dataLen = sizeof(data); - if (RegGetValueA(nwAdapters,subkeyName,"NetCfgInstanceId",RRF_RT_ANY,&type,(PVOID)data,&dataLen) == ERROR_SUCCESS) { - RegSetKeyValueA(nwAdapters,subkeyName,"_ZeroTierTapIdentifier",REG_SZ,tag,(DWORD)(strlen(tag)+1)); + if (WINENV.tapDriverName == data) { + type = 0; + dataLen = sizeof(data); + if ((RegGetValueA(nwAdapters, subkeyName, "_ZeroTierTapIdentifier", RRF_RT_ANY, &type, (PVOID)data, &dataLen) != ERROR_SUCCESS) || (dataLen <= 0)) { + type = 0; + dataLen = sizeof(data); + if (RegGetValueA(nwAdapters, subkeyName, "NetCfgInstanceId", RRF_RT_ANY, &type, (PVOID)data, &dataLen) == ERROR_SUCCESS) { + RegSetKeyValueA(nwAdapters, subkeyName, "_ZeroTierTapIdentifier", REG_SZ, tag, (DWORD)(strlen(tag) + 1)); - _netCfgInstanceId.assign(data,dataLen); + _netCfgInstanceId.assign(data, dataLen); - type = 0; - dataLen = sizeof(data); - if (RegGetValueA(nwAdapters,subkeyName,"DeviceInstanceID",RRF_RT_ANY,&type,(PVOID)data,&dataLen) == ERROR_SUCCESS) - _deviceInstanceId.assign(data,dataLen); + type = 0; + dataLen = sizeof(data); + if (RegGetValueA(nwAdapters, subkeyName, "DeviceInstanceID", RRF_RT_ANY, &type, (PVOID)data, &dataLen) == ERROR_SUCCESS) + _deviceInstanceId.assign(data, dataLen); - _mySubkeyName = subkeyName; + _mySubkeyName = subkeyName; - // Disable DHCP by default on new devices - HKEY tcpIpInterfaces; - if (RegOpenKeyExA(HKEY_LOCAL_MACHINE,"SYSTEM\\CurrentControlSet\\services\\Tcpip\\Parameters\\Interfaces",0,KEY_READ|KEY_WRITE,&tcpIpInterfaces) == ERROR_SUCCESS) { - DWORD enable = 0; - RegSetKeyValueA(tcpIpInterfaces,_netCfgInstanceId.c_str(),"EnableDHCP",REG_DWORD,&enable,sizeof(enable)); - RegCloseKey(tcpIpInterfaces); - } + // Disable DHCP by default on new devices + HKEY tcpIpInterfaces; + if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\services\\Tcpip\\Parameters\\Interfaces", 0, KEY_READ | KEY_WRITE, &tcpIpInterfaces) == ERROR_SUCCESS) { + DWORD enable = 0; + RegSetKeyValueA(tcpIpInterfaces, _netCfgInstanceId.c_str(), "EnableDHCP", REG_DWORD, &enable, sizeof(enable)); + RegCloseKey(tcpIpInterfaces); + } - break; // found an unused zttap device - } - } - } - } - } else break; // no more keys or error occurred - } + break; // found an unused zttap device + } + } + } + } + } + else + break; // no more keys or error occurred + } - if (_netCfgInstanceId.length() > 0) { - break; // found an unused zttap device - } else { - // no unused zttap devices, so create one - std::string errm = addNewPersistentTapDevice((std::string(_pathToHelpers) + WINENV.tapDriverPath).c_str(),newDeviceInstanceId); - if (errm.length() > 0) - throw std::runtime_error(std::string("unable to create new device instance: ")+errm); - } - } - } + if (_netCfgInstanceId.length() > 0) { + break; // found an unused zttap device + } + else { + // no unused zttap devices, so create one + std::string errm = addNewPersistentTapDevice((std::string(_pathToHelpers) + WINENV.tapDriverPath).c_str(), newDeviceInstanceId); + if (errm.length() > 0) + throw std::runtime_error(std::string("unable to create new device instance: ") + errm); + } + } + } - if (_netCfgInstanceId.length() > 0) { - char tmps[64]; - unsigned int tmpsl = OSUtils::ztsnprintf(tmps,sizeof(tmps),"%.2X-%.2X-%.2X-%.2X-%.2X-%.2X",(unsigned int)mac[0],(unsigned int)mac[1],(unsigned int)mac[2],(unsigned int)mac[3],(unsigned int)mac[4],(unsigned int)mac[5]) + 1; - RegSetKeyValueA(nwAdapters,_mySubkeyName.c_str(),"NetworkAddress",REG_SZ,tmps,tmpsl); - RegSetKeyValueA(nwAdapters,_mySubkeyName.c_str(),"MAC",REG_SZ,tmps,tmpsl); - tmpsl = OSUtils::ztsnprintf(tmps, sizeof(tmps), "%d", mtu); - RegSetKeyValueA(nwAdapters,_mySubkeyName.c_str(),"MTU",REG_SZ,tmps,tmpsl); + if (_netCfgInstanceId.length() > 0) { + char tmps[64]; + unsigned int tmpsl = OSUtils::ztsnprintf(tmps, sizeof(tmps), "%.2X-%.2X-%.2X-%.2X-%.2X-%.2X", (unsigned int)mac[0], (unsigned int)mac[1], (unsigned int)mac[2], (unsigned int)mac[3], (unsigned int)mac[4], (unsigned int)mac[5]) + 1; + RegSetKeyValueA(nwAdapters, _mySubkeyName.c_str(), "NetworkAddress", REG_SZ, tmps, tmpsl); + RegSetKeyValueA(nwAdapters, _mySubkeyName.c_str(), "MAC", REG_SZ, tmps, tmpsl); + tmpsl = OSUtils::ztsnprintf(tmps, sizeof(tmps), "%d", mtu); + RegSetKeyValueA(nwAdapters, _mySubkeyName.c_str(), "MTU", REG_SZ, tmps, tmpsl); - DWORD tmp = 0; - RegSetKeyValueA(nwAdapters,_mySubkeyName.c_str(),"*NdisDeviceType",REG_DWORD,(LPCVOID)&tmp,sizeof(tmp)); - tmp = IF_TYPE_ETHERNET_CSMACD; - RegSetKeyValueA(nwAdapters,_mySubkeyName.c_str(),"*IfType",REG_DWORD,(LPCVOID)&tmp,sizeof(tmp)); + DWORD tmp = 0; + RegSetKeyValueA(nwAdapters, _mySubkeyName.c_str(), "*NdisDeviceType", REG_DWORD, (LPCVOID)&tmp, sizeof(tmp)); + tmp = IF_TYPE_ETHERNET_CSMACD; + RegSetKeyValueA(nwAdapters, _mySubkeyName.c_str(), "*IfType", REG_DWORD, (LPCVOID)&tmp, sizeof(tmp)); - if (creatingNewDevice) { - // Vista/2008 does not set this - if (newDeviceInstanceId.length() > 0) - RegSetKeyValueA(nwAdapters,_mySubkeyName.c_str(),"DeviceInstanceID",REG_SZ,newDeviceInstanceId.c_str(),(DWORD)newDeviceInstanceId.length()); + if (creatingNewDevice) { + // Vista/2008 does not set this + if (newDeviceInstanceId.length() > 0) + RegSetKeyValueA(nwAdapters, _mySubkeyName.c_str(), "DeviceInstanceID", REG_SZ, newDeviceInstanceId.c_str(), (DWORD)newDeviceInstanceId.length()); - // Set EnableDHCP to 0 by default on new devices - tmp = 0; - RegSetKeyValueA(nwAdapters,_mySubkeyName.c_str(),"EnableDHCP",REG_DWORD,(LPCVOID)&tmp,sizeof(tmp)); - } - RegCloseKey(nwAdapters); - } else { - RegCloseKey(nwAdapters); - throw std::runtime_error("unable to find or create tap adapter"); - } + // Set EnableDHCP to 0 by default on new devices + tmp = 0; + RegSetKeyValueA(nwAdapters, _mySubkeyName.c_str(), "EnableDHCP", REG_DWORD, (LPCVOID)&tmp, sizeof(tmp)); + } + RegCloseKey(nwAdapters); + } + else { + RegCloseKey(nwAdapters); + throw std::runtime_error("unable to find or create tap adapter"); + } - { - char nobraces[128]; // strip braces from GUID before converting it, because Windows - const char *nbtmp1 = _netCfgInstanceId.c_str(); - char *nbtmp2 = nobraces; - while (*nbtmp1) { - if ((*nbtmp1 != '{')&&(*nbtmp1 != '}')) - *nbtmp2++ = *nbtmp1; - ++nbtmp1; - } - *nbtmp2 = (char)0; - if (UuidFromStringA((RPC_CSTR)nobraces,&_deviceGuid) != RPC_S_OK) - throw std::runtime_error("unable to convert instance ID GUID to native GUID (invalid NetCfgInstanceId in registry?)"); - } + { + char nobraces[128]; // strip braces from GUID before converting it, because Windows + const char* nbtmp1 = _netCfgInstanceId.c_str(); + char* nbtmp2 = nobraces; + while (*nbtmp1) { + if ((*nbtmp1 != '{') && (*nbtmp1 != '}')) + *nbtmp2++ = *nbtmp1; + ++nbtmp1; + } + *nbtmp2 = (char)0; + if (UuidFromStringA((RPC_CSTR)nobraces, &_deviceGuid) != RPC_S_OK) + throw std::runtime_error("unable to convert instance ID GUID to native GUID (invalid NetCfgInstanceId in registry?)"); + } - // Get the LUID, which is one of like four fucking ways to refer to a network device in Windows - if (ConvertInterfaceGuidToLuid(&_deviceGuid,&_deviceLuid) != NO_ERROR) - throw std::runtime_error("unable to convert device interface GUID to LUID"); + // Get the LUID, which is one of like four fucking ways to refer to a network device in Windows + if (ConvertInterfaceGuidToLuid(&_deviceGuid, &_deviceLuid) != NO_ERROR) + throw std::runtime_error("unable to convert device interface GUID to LUID"); - //_initialized = true; + //_initialized = true; - if (friendlyName) - setFriendlyName(friendlyName); + if (friendlyName) + setFriendlyName(friendlyName); - _injectSemaphore = CreateSemaphore(NULL,0,1,NULL); - _thread = Thread::start(this); + _injectSemaphore = CreateSemaphore(NULL, 0, 1, NULL); + _thread = Thread::start(this); } WindowsEthernetTap::~WindowsEthernetTap() { - WinDNSHelper::removeDNS(_nwid); - _run = false; - ReleaseSemaphore(_injectSemaphore,1,NULL); - Thread::join(_thread); - CloseHandle(_injectSemaphore); - setPersistentTapDeviceState(_deviceInstanceId.c_str(),false); + WinDNSHelper::removeDNS(_nwid); + _run = false; + ReleaseSemaphore(_injectSemaphore, 1, NULL); + Thread::join(_thread); + CloseHandle(_injectSemaphore); + setPersistentTapDeviceState(_deviceInstanceId.c_str(), false); } void WindowsEthernetTap::setEnabled(bool en) { - _enabled = en; + _enabled = en; } bool WindowsEthernetTap::enabled() const { - return _enabled; + return _enabled; } -bool WindowsEthernetTap::addIp(const InetAddress &ip) +bool WindowsEthernetTap::addIp(const InetAddress& ip) { - if (!ip.netmaskBits()) // sanity check... netmask of 0.0.0.0 is WUT? - return false; + if (! ip.netmaskBits()) // sanity check... netmask of 0.0.0.0 is WUT? + return false; - Mutex::Lock _l(_assignedIps_m); - if (std::find(_assignedIps.begin(),_assignedIps.end(),ip) != _assignedIps.end()) - return true; - _assignedIps.push_back(ip); - _syncIps(); - return true; + Mutex::Lock _l(_assignedIps_m); + if (std::find(_assignedIps.begin(), _assignedIps.end(), ip) != _assignedIps.end()) + return true; + _assignedIps.push_back(ip); + _syncIps(); + return true; } -bool WindowsEthernetTap::removeIp(const InetAddress &ip) +bool WindowsEthernetTap::removeIp(const InetAddress& ip) { if (ip.isV6()) return true; - { - Mutex::Lock _l(_assignedIps_m); - std::vector::iterator aip(std::find(_assignedIps.begin(),_assignedIps.end(),ip)); - if (aip != _assignedIps.end()) - _assignedIps.erase(aip); - } + { + Mutex::Lock _l(_assignedIps_m); + std::vector::iterator aip(std::find(_assignedIps.begin(), _assignedIps.end(), ip)); + if (aip != _assignedIps.end()) + _assignedIps.erase(aip); + } - if (!_initialized) - return false; + if (! _initialized) + return false; - try { - MIB_UNICASTIPADDRESS_TABLE *ipt = (MIB_UNICASTIPADDRESS_TABLE *)0; - if (GetUnicastIpAddressTable(AF_UNSPEC,&ipt) == NO_ERROR) { - if ((ipt)&&(ipt->NumEntries > 0)) { - for(DWORD i=0;i<(DWORD)ipt->NumEntries;++i) { - if (ipt->Table[i].InterfaceLuid.Value == _deviceLuid.Value) { - InetAddress addr; - switch(ipt->Table[i].Address.si_family) { - case AF_INET: - addr.set(&(ipt->Table[i].Address.Ipv4.sin_addr.S_un.S_addr),4,ipt->Table[i].OnLinkPrefixLength); - break; - case AF_INET6: - addr.set(ipt->Table[i].Address.Ipv6.sin6_addr.u.Byte,16,ipt->Table[i].OnLinkPrefixLength); - if (addr.ipScope() == InetAddress::IP_SCOPE_LINK_LOCAL) - continue; // can't remove link-local IPv6 addresses - break; - } - if (addr == ip) { - DeleteUnicastIpAddressEntry(&(ipt->Table[i])); - FreeMibTable(ipt); + try { + MIB_UNICASTIPADDRESS_TABLE* ipt = (MIB_UNICASTIPADDRESS_TABLE*)0; + if (GetUnicastIpAddressTable(AF_UNSPEC, &ipt) == NO_ERROR) { + if ((ipt) && (ipt->NumEntries > 0)) { + for (DWORD i = 0; i < (DWORD)ipt->NumEntries; ++i) { + if (ipt->Table[i].InterfaceLuid.Value == _deviceLuid.Value) { + InetAddress addr; + switch (ipt->Table[i].Address.si_family) { + case AF_INET: + addr.set(&(ipt->Table[i].Address.Ipv4.sin_addr.S_un.S_addr), 4, ipt->Table[i].OnLinkPrefixLength); + break; + case AF_INET6: + addr.set(ipt->Table[i].Address.Ipv6.sin6_addr.u.Byte, 16, ipt->Table[i].OnLinkPrefixLength); + if (addr.ipScope() == InetAddress::IP_SCOPE_LINK_LOCAL) + continue; // can't remove link-local IPv6 addresses + break; + } + if (addr == ip) { + DeleteUnicastIpAddressEntry(&(ipt->Table[i])); + FreeMibTable(ipt); - if (ip.isV4()) { - std::vector regIps(_getRegistryIPv4Value("IPAddress")); - std::vector regSubnetMasks(_getRegistryIPv4Value("SubnetMask")); - char ipbuf[64]; - std::string ipstr(ip.toIpString(ipbuf)); - for (std::vector::iterator rip(regIps.begin()), rm(regSubnetMasks.begin()); ((rip != regIps.end()) && (rm != regSubnetMasks.end())); ++rip, ++rm) { - if (*rip == ipstr) { - regIps.erase(rip); - regSubnetMasks.erase(rm); - _setRegistryIPv4Value("IPAddress", regIps); - _setRegistryIPv4Value("SubnetMask", regSubnetMasks); - break; - } - } - } + if (ip.isV4()) { + std::vector regIps(_getRegistryIPv4Value("IPAddress")); + std::vector regSubnetMasks(_getRegistryIPv4Value("SubnetMask")); + char ipbuf[64]; + std::string ipstr(ip.toIpString(ipbuf)); + for (std::vector::iterator rip(regIps.begin()), rm(regSubnetMasks.begin()); ((rip != regIps.end()) && (rm != regSubnetMasks.end())); ++rip, ++rm) { + if (*rip == ipstr) { + regIps.erase(rip); + regSubnetMasks.erase(rm); + _setRegistryIPv4Value("IPAddress", regIps); + _setRegistryIPv4Value("SubnetMask", regSubnetMasks); + break; + } + } + } - return true; - } - } - } - } - FreeMibTable((PVOID)ipt); - } - } catch ( ... ) {} - return false; + return true; + } + } + } + } + FreeMibTable((PVOID)ipt); + } + } + catch (...) { + } + return false; } std::vector WindowsEthernetTap::ips() const { - static const InetAddress linkLocalLoopback("fe80::1/64"); // what is this and why does Windows assign it? - std::vector addrs; + static const InetAddress linkLocalLoopback("fe80::1/64"); // what is this and why does Windows assign it? + std::vector addrs; - if (!_initialized) - return addrs; + if (! _initialized) + return addrs; - uint64_t now = OSUtils::now(); + uint64_t now = OSUtils::now(); - if ((now - _lastIfAddrsUpdate) <= GETIFADDRS_CACHE_TIME) { - return _ifaddrs; - } + if ((now - _lastIfAddrsUpdate) <= GETIFADDRS_CACHE_TIME) { + return _ifaddrs; + } - _lastIfAddrsUpdate = now; + _lastIfAddrsUpdate = now; - try { - MIB_UNICASTIPADDRESS_TABLE *ipt = (MIB_UNICASTIPADDRESS_TABLE *)0; - if (GetUnicastIpAddressTable(AF_UNSPEC,&ipt) == NO_ERROR) { - if ((ipt)&&(ipt->NumEntries > 0)) { - for(DWORD i=0;i<(DWORD)ipt->NumEntries;++i) { - if (ipt->Table[i].InterfaceLuid.Value == _deviceLuid.Value) { - switch(ipt->Table[i].Address.si_family) { - case AF_INET: { - InetAddress ip(&(ipt->Table[i].Address.Ipv4.sin_addr.S_un.S_addr),4,ipt->Table[i].OnLinkPrefixLength); - if (ip != InetAddress::LO4) - addrs.push_back(ip); - } break; - case AF_INET6: { - InetAddress ip(ipt->Table[i].Address.Ipv6.sin6_addr.u.Byte,16,ipt->Table[i].OnLinkPrefixLength); - if ((ip != linkLocalLoopback)&&(ip != InetAddress::LO6)) - addrs.push_back(ip); - } break; - } - } - } - } - FreeMibTable(ipt); - } - } catch ( ... ) {} // sanity check, shouldn't happen unless out of memory + try { + MIB_UNICASTIPADDRESS_TABLE* ipt = (MIB_UNICASTIPADDRESS_TABLE*)0; + if (GetUnicastIpAddressTable(AF_UNSPEC, &ipt) == NO_ERROR) { + if ((ipt) && (ipt->NumEntries > 0)) { + for (DWORD i = 0; i < (DWORD)ipt->NumEntries; ++i) { + if (ipt->Table[i].InterfaceLuid.Value == _deviceLuid.Value) { + switch (ipt->Table[i].Address.si_family) { + case AF_INET: { + InetAddress ip(&(ipt->Table[i].Address.Ipv4.sin_addr.S_un.S_addr), 4, ipt->Table[i].OnLinkPrefixLength); + if (ip != InetAddress::LO4) + addrs.push_back(ip); + } break; + case AF_INET6: { + InetAddress ip(ipt->Table[i].Address.Ipv6.sin6_addr.u.Byte, 16, ipt->Table[i].OnLinkPrefixLength); + if ((ip != linkLocalLoopback) && (ip != InetAddress::LO6)) + addrs.push_back(ip); + } break; + } + } + } + } + FreeMibTable(ipt); + } + } + catch (...) { + } // sanity check, shouldn't happen unless out of memory - std::sort(addrs.begin(),addrs.end()); - addrs.erase(std::unique(addrs.begin(),addrs.end()),addrs.end()); + std::sort(addrs.begin(), addrs.end()); + addrs.erase(std::unique(addrs.begin(), addrs.end()), addrs.end()); - _ifaddrs = addrs; + _ifaddrs = addrs; - return addrs; + return addrs; } -void WindowsEthernetTap::put(const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len) +void WindowsEthernetTap::put(const MAC& from, const MAC& to, unsigned int etherType, const void* data, unsigned int len) { - if ((!_initialized)||(!_enabled)||(_tap == INVALID_HANDLE_VALUE)||(len > _mtu)) - return; + if ((! _initialized) || (! _enabled) || (_tap == INVALID_HANDLE_VALUE) || (len > _mtu)) + return; - Mutex::Lock _l(_injectPending_m); - _injectPending.emplace(); - _injectPending.back().len = len + 14; - char *const d = _injectPending.back().data; - to.copyTo(d,6); - from.copyTo(d + 6,6); - d[12] = (char)((etherType >> 8) & 0xff); - d[13] = (char)(etherType & 0xff); - memcpy(d + 14,data,len); + Mutex::Lock _l(_injectPending_m); + _injectPending.emplace(); + _injectPending.back().len = len + 14; + char* const d = _injectPending.back().data; + to.copyTo(d, 6); + from.copyTo(d + 6, 6); + d[12] = (char)((etherType >> 8) & 0xff); + d[13] = (char)(etherType & 0xff); + memcpy(d + 14, data, len); - ReleaseSemaphore(_injectSemaphore,1,NULL); + ReleaseSemaphore(_injectSemaphore, 1, NULL); } std::string WindowsEthernetTap::deviceName() const { - char tmp[1024]; - if (ConvertInterfaceLuidToNameA(&_deviceLuid,tmp,sizeof(tmp)) != NO_ERROR) - return std::string("[ConvertInterfaceLuidToName() failed]"); - return std::string(tmp); + char tmp[1024]; + if (ConvertInterfaceLuidToNameA(&_deviceLuid, tmp, sizeof(tmp)) != NO_ERROR) + return std::string("[ConvertInterfaceLuidToName() failed]"); + return std::string(tmp); } -void WindowsEthernetTap::setFriendlyName(const char *dn) +void WindowsEthernetTap::setFriendlyName(const char* dn) { - if (!_initialized) - return; + if (! _initialized) + return; - HKEY ifp; - if (RegOpenKeyExA(HKEY_LOCAL_MACHINE,(std::string("SYSTEM\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}\\") + _netCfgInstanceId).c_str(),0,KEY_READ|KEY_WRITE,&ifp) == ERROR_SUCCESS) { - RegSetKeyValueA(ifp,"Connection","Name",REG_SZ,(LPCVOID)dn,(DWORD)(strlen(dn)+1)); - RegCloseKey(ifp); - } + HKEY ifp; + if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, (std::string("SYSTEM\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}\\") + _netCfgInstanceId).c_str(), 0, KEY_READ | KEY_WRITE, &ifp) == ERROR_SUCCESS) { + RegSetKeyValueA(ifp, "Connection", "Name", REG_SZ, (LPCVOID)dn, (DWORD)(strlen(dn) + 1)); + RegCloseKey(ifp); + } - HRESULT hr = S_OK; + HRESULT hr = S_OK; - INetSharingManager *nsm; - hr = CoCreateInstance(__uuidof(NetSharingManager), NULL, CLSCTX_ALL, __uuidof(INetSharingManager), (void**)&nsm); - if (hr != S_OK) return; + INetSharingManager* nsm; + hr = CoCreateInstance(__uuidof(NetSharingManager), NULL, CLSCTX_ALL, __uuidof(INetSharingManager), (void**)&nsm); + if (hr != S_OK) + return; - bool found = false; - INetSharingEveryConnectionCollection *nsecc = nullptr; - hr = nsm->get_EnumEveryConnection(&nsecc); - if (!nsecc) { - fprintf(stderr, "Failed to get NSM connections"); - return; - } + bool found = false; + INetSharingEveryConnectionCollection* nsecc = nullptr; + hr = nsm->get_EnumEveryConnection(&nsecc); + if (! nsecc) { + fprintf(stderr, "Failed to get NSM connections"); + return; + } - IEnumVARIANT *ev = nullptr; - IUnknown *unk = nullptr; - hr = nsecc->get__NewEnum(&unk); - if (unk) { - hr = unk->QueryInterface(__uuidof(IEnumVARIANT), (void**)&ev); - unk->Release(); - } - if (ev) { - VARIANT v; - VariantInit(&v); + IEnumVARIANT* ev = nullptr; + IUnknown* unk = nullptr; + hr = nsecc->get__NewEnum(&unk); + if (unk) { + hr = unk->QueryInterface(__uuidof(IEnumVARIANT), (void**)&ev); + unk->Release(); + } + if (ev) { + VARIANT v; + VariantInit(&v); - while ((S_OK == ev->Next(1, &v, NULL)) && found == FALSE) { - if (V_VT(&v) == VT_UNKNOWN) { - INetConnection *nc = nullptr; - V_UNKNOWN(&v)->QueryInterface(__uuidof(INetConnection), (void**)&nc); - if (nc) { - NETCON_PROPERTIES *ncp = nullptr; - nc->GetProperties(&ncp); + while ((S_OK == ev->Next(1, &v, NULL)) && found == FALSE) { + if (V_VT(&v) == VT_UNKNOWN) { + INetConnection* nc = nullptr; + V_UNKNOWN(&v)->QueryInterface(__uuidof(INetConnection), (void**)&nc); + if (nc) { + NETCON_PROPERTIES* ncp = nullptr; + nc->GetProperties(&ncp); - if (ncp != nullptr) { - GUID curId = ncp->guidId; - if (curId == _deviceGuid) { - wchar_t wtext[255]; - mbstowcs(wtext, dn, strlen(dn)+1); - nc->Rename(wtext); - found = true; - } - } - nc->Release(); - } - } - VariantClear(&v); - } - ev->Release(); - } - nsecc->Release(); + if (ncp != nullptr) { + GUID curId = ncp->guidId; + if (curId == _deviceGuid) { + wchar_t wtext[255]; + mbstowcs(wtext, dn, strlen(dn) + 1); + nc->Rename(wtext); + found = true; + } + } + nc->Release(); + } + } + VariantClear(&v); + } + ev->Release(); + } + nsecc->Release(); - _friendlyName_m.lock(); - _friendlyName = dn; - _friendlyName_m.unlock(); + _friendlyName_m.lock(); + _friendlyName = dn; + _friendlyName_m.unlock(); } std::string WindowsEthernetTap::friendlyName() const { - Mutex::Lock l(_friendlyName_m); - return _friendlyName; + Mutex::Lock l(_friendlyName_m); + return _friendlyName; } -void WindowsEthernetTap::scanMulticastGroups(std::vector &added,std::vector &removed) +void WindowsEthernetTap::scanMulticastGroups(std::vector& added, std::vector& removed) { - if (!_initialized) - return; - HANDLE t = _tap; - if (t == INVALID_HANDLE_VALUE) - return; + if (! _initialized) + return; + HANDLE t = _tap; + if (t == INVALID_HANDLE_VALUE) + return; - std::vector newGroups; + std::vector newGroups; - // The ZT1 tap driver supports an IOCTL to get multicast memberships at the L2 - // level... something Windows does not seem to expose ordinarily. This lets - // pretty much anything work... IPv4, IPv6, IPX, oldskool Netbios, who knows... - unsigned char mcastbuf[TAP_WIN_IOCTL_GET_MULTICAST_MEMBERSHIPS_OUTPUT_BUF_SIZE]; - DWORD bytesReturned = 0; - if (DeviceIoControl(t,TAP_WIN_IOCTL_GET_MULTICAST_MEMBERSHIPS,(LPVOID)mcastbuf,sizeof(mcastbuf),(LPVOID)mcastbuf,sizeof(mcastbuf),&bytesReturned,NULL)) { - if ((bytesReturned > 0)&&(bytesReturned <= TAP_WIN_IOCTL_GET_MULTICAST_MEMBERSHIPS_OUTPUT_BUF_SIZE)) { // sanity check - MAC mac; - DWORD i = 0; - while ((i + 6) <= bytesReturned) { - mac.setTo(mcastbuf + i,6); - i += 6; - if ((mac.isMulticast())&&(!mac.isBroadcast())) { - // exclude the nulls that may be returned or any other junk Windows puts in there - newGroups.push_back(MulticastGroup(mac,0)); - } - } - } - } + // The ZT1 tap driver supports an IOCTL to get multicast memberships at the L2 + // level... something Windows does not seem to expose ordinarily. This lets + // pretty much anything work... IPv4, IPv6, IPX, oldskool Netbios, who knows... + unsigned char mcastbuf[TAP_WIN_IOCTL_GET_MULTICAST_MEMBERSHIPS_OUTPUT_BUF_SIZE]; + DWORD bytesReturned = 0; + if (DeviceIoControl(t, TAP_WIN_IOCTL_GET_MULTICAST_MEMBERSHIPS, (LPVOID)mcastbuf, sizeof(mcastbuf), (LPVOID)mcastbuf, sizeof(mcastbuf), &bytesReturned, NULL)) { + if ((bytesReturned > 0) && (bytesReturned <= TAP_WIN_IOCTL_GET_MULTICAST_MEMBERSHIPS_OUTPUT_BUF_SIZE)) { // sanity check + MAC mac; + DWORD i = 0; + while ((i + 6) <= bytesReturned) { + mac.setTo(mcastbuf + i, 6); + i += 6; + if ((mac.isMulticast()) && (! mac.isBroadcast())) { + // exclude the nulls that may be returned or any other junk Windows puts in there + newGroups.push_back(MulticastGroup(mac, 0)); + } + } + } + } - std::vector allIps(ips()); - for(std::vector::iterator ip(allIps.begin());ip!=allIps.end();++ip) - newGroups.push_back(MulticastGroup::deriveMulticastGroupForAddressResolution(*ip)); + std::vector allIps(ips()); + for (std::vector::iterator ip(allIps.begin()); ip != allIps.end(); ++ip) + newGroups.push_back(MulticastGroup::deriveMulticastGroupForAddressResolution(*ip)); - std::sort(newGroups.begin(),newGroups.end()); - newGroups.erase(std::unique(newGroups.begin(),newGroups.end()),newGroups.end()); + std::sort(newGroups.begin(), newGroups.end()); + newGroups.erase(std::unique(newGroups.begin(), newGroups.end()), newGroups.end()); - for(std::vector::iterator m(newGroups.begin());m!=newGroups.end();++m) { - if (!std::binary_search(_multicastGroups.begin(),_multicastGroups.end(),*m)) - added.push_back(*m); - } - for(std::vector::iterator m(_multicastGroups.begin());m!=_multicastGroups.end();++m) { - if (!std::binary_search(newGroups.begin(),newGroups.end(),*m)) - removed.push_back(*m); - } + for (std::vector::iterator m(newGroups.begin()); m != newGroups.end(); ++m) { + if (! std::binary_search(_multicastGroups.begin(), _multicastGroups.end(), *m)) + added.push_back(*m); + } + for (std::vector::iterator m(_multicastGroups.begin()); m != _multicastGroups.end(); ++m) { + if (! std::binary_search(newGroups.begin(), newGroups.end(), *m)) + removed.push_back(*m); + } - _multicastGroups.swap(newGroups); + _multicastGroups.swap(newGroups); } void WindowsEthernetTap::setMtu(unsigned int mtu) { - if (mtu != _mtu) { - _mtu = mtu; - HKEY nwAdapters; - if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002BE10318}", 0, KEY_READ | KEY_WRITE, &nwAdapters) == ERROR_SUCCESS) { - char tmps[64]; - unsigned int tmpsl = OSUtils::ztsnprintf(tmps, sizeof(tmps), "%d", mtu); - RegSetKeyValueA(nwAdapters, _mySubkeyName.c_str(), "MTU", REG_SZ, tmps, tmpsl); - RegCloseKey(nwAdapters); - } - } + if (mtu != _mtu) { + _mtu = mtu; + HKEY nwAdapters; + if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002BE10318}", 0, KEY_READ | KEY_WRITE, &nwAdapters) == ERROR_SUCCESS) { + char tmps[64]; + unsigned int tmpsl = OSUtils::ztsnprintf(tmps, sizeof(tmps), "%d", mtu); + RegSetKeyValueA(nwAdapters, _mySubkeyName.c_str(), "MTU", REG_SZ, tmps, tmpsl); + RegCloseKey(nwAdapters); + } + } } NET_IFINDEX WindowsEthernetTap::interfaceIndex() const { - NET_IFINDEX idx = -1; - if (ConvertInterfaceLuidToIndex(&_deviceLuid,&idx) == NO_ERROR) - return idx; - return -1; + NET_IFINDEX idx = -1; + if (ConvertInterfaceLuidToIndex(&_deviceLuid, &idx) == NO_ERROR) + return idx; + return -1; } -void WindowsEthernetTap::threadMain() - throw() +void WindowsEthernetTap::threadMain() throw() { - HRESULT hres = CoInitializeEx(0, COINIT_MULTITHREADED); - if (FAILED(hres)) { - fprintf(stderr, "WinEthernetTap: COM initialization failed"); - return; - } + HRESULT hres = CoInitializeEx(0, COINIT_MULTITHREADED); + if (FAILED(hres)) { + fprintf(stderr, "WinEthernetTap: COM initialization failed"); + return; + } - char tapReadBuf[ZT_MAX_MTU + 32]; - char tapPath[128]; - HANDLE wait4[3]; - OVERLAPPED tapOvlRead,tapOvlWrite; + char tapReadBuf[ZT_MAX_MTU + 32]; + char tapPath[128]; + HANDLE wait4[3]; + OVERLAPPED tapOvlRead, tapOvlWrite; - OSUtils::ztsnprintf(tapPath,sizeof(tapPath),"\\\\.\\Global\\%s.tap",_netCfgInstanceId.c_str()); + OSUtils::ztsnprintf(tapPath, sizeof(tapPath), "\\\\.\\Global\\%s.tap", _netCfgInstanceId.c_str()); - try { - while (_run) { - // Because Windows - Sleep(250); - setPersistentTapDeviceState(_deviceInstanceId.c_str(),false); - Sleep(250); - setPersistentTapDeviceState(_deviceInstanceId.c_str(),true); - Sleep(250); - setPersistentTapDeviceState(_deviceInstanceId.c_str(),false); - Sleep(250); - setPersistentTapDeviceState(_deviceInstanceId.c_str(),true); - Sleep(250); + try { + while (_run) { + // Because Windows + Sleep(250); + setPersistentTapDeviceState(_deviceInstanceId.c_str(), false); + Sleep(250); + setPersistentTapDeviceState(_deviceInstanceId.c_str(), true); + Sleep(250); + setPersistentTapDeviceState(_deviceInstanceId.c_str(), false); + Sleep(250); + setPersistentTapDeviceState(_deviceInstanceId.c_str(), true); + Sleep(250); - _tap = CreateFileA(tapPath,GENERIC_READ|GENERIC_WRITE,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_SYSTEM|FILE_FLAG_OVERLAPPED,NULL); - if (_tap == INVALID_HANDLE_VALUE) { - Sleep(250); - continue; - } + _tap = CreateFileA(tapPath, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED, NULL); + if (_tap == INVALID_HANDLE_VALUE) { + Sleep(250); + continue; + } - { - uint32_t tmpi = 1; - DWORD bytesReturned = 0; - DeviceIoControl(_tap,TAP_WIN_IOCTL_SET_MEDIA_STATUS,&tmpi,sizeof(tmpi),&tmpi,sizeof(tmpi),&bytesReturned,NULL); - } + { + uint32_t tmpi = 1; + DWORD bytesReturned = 0; + DeviceIoControl(_tap, TAP_WIN_IOCTL_SET_MEDIA_STATUS, &tmpi, sizeof(tmpi), &tmpi, sizeof(tmpi), &bytesReturned, NULL); + } #ifdef ZT_WINDOWS_CREATE_FAKE_DEFAULT_ROUTE - { - /* This inserts a fake default route and a fake ARP entry, forcing - * Windows to detect this as a "real" network and apply proper - * firewall rules. - * - * This hack is completely stupid, but Windows made me do it - * by being broken and insane. - * - * Background: Windows tries to detect its network location by - * matching it to the ARP address of the default route. Networks - * without default routes are "unidentified networks" and cannot - * have their firewall classification changed by the user (easily). - * - * Yes, you read that right. - * - * The common workaround is to set *NdisDeviceType to 1, which - * totally disables all Windows firewall functionality. This is - * the answer you'll find on most forums for things like OpenVPN. - * - * Yes, you read that right. - * - * The default route workaround is also known, but for this to - * work there must be a known default IP that resolves to a known - * ARP address. This works for an OpenVPN tunnel, but not here - * because this isn't a tunnel. It's a mesh. There is no "other - * end," or any other known always on IP. - * - * So let's make a fake one and shove it in there along with its - * fake static ARP entry. Also makes it instant-on and static. - * - * We'll have to see what DHCP does with this. In the future we - * probably will not want to do this on DHCP-enabled networks, so - * when we enable DHCP we will go in and yank this wacko hacko from - * the routing table before doing so. - * - * Like Jesse Pinkman would say: "YEEEEAAH BITCH!" */ - const uint32_t fakeIp = htonl(0x19fffffe); // 25.255.255.254 -- unrouted IPv4 block - for(int i=0;i<8;++i) { - MIB_IPNET_ROW2 ipnr; - memset(&ipnr,0,sizeof(ipnr)); - ipnr.Address.si_family = AF_INET; - ipnr.Address.Ipv4.sin_addr.s_addr = fakeIp; - ipnr.InterfaceLuid.Value = _deviceLuid.Value; - ipnr.PhysicalAddress[0] = _mac[0] ^ 0x10; // just make something up that's consistent and not part of this net - ipnr.PhysicalAddress[1] = 0x00; - ipnr.PhysicalAddress[2] = (UCHAR)((_deviceGuid.Data1 >> 24) & 0xff); - ipnr.PhysicalAddress[3] = (UCHAR)((_deviceGuid.Data1 >> 16) & 0xff); - ipnr.PhysicalAddress[4] = (UCHAR)((_deviceGuid.Data1 >> 8) & 0xff); - ipnr.PhysicalAddress[5] = (UCHAR)(_deviceGuid.Data1 & 0xff); - ipnr.PhysicalAddressLength = 6; - ipnr.State = NlnsPermanent; - ipnr.IsRouter = 1; - ipnr.IsUnreachable = 0; - ipnr.ReachabilityTime.LastReachable = 0x0fffffff; - ipnr.ReachabilityTime.LastUnreachable = 1; - DWORD result = CreateIpNetEntry2(&ipnr); - if (result != NO_ERROR) - Sleep(250); - else break; - } - for(int i=0;i<8;++i) { - MIB_IPFORWARD_ROW2 nr; - memset(&nr,0,sizeof(nr)); - InitializeIpForwardEntry(&nr); - nr.InterfaceLuid.Value = _deviceLuid.Value; - nr.DestinationPrefix.Prefix.si_family = AF_INET; // rest is left as 0.0.0.0/0 - nr.NextHop.si_family = AF_INET; - nr.NextHop.Ipv4.sin_addr.s_addr = fakeIp; - nr.Metric = 9999; // do not use as real default route - nr.Protocol = MIB_IPPROTO_NETMGMT; - DWORD result = CreateIpForwardEntry2(&nr); - if (result != NO_ERROR) - Sleep(250); - else break; - } - } + { + /* This inserts a fake default route and a fake ARP entry, forcing + * Windows to detect this as a "real" network and apply proper + * firewall rules. + * + * This hack is completely stupid, but Windows made me do it + * by being broken and insane. + * + * Background: Windows tries to detect its network location by + * matching it to the ARP address of the default route. Networks + * without default routes are "unidentified networks" and cannot + * have their firewall classification changed by the user (easily). + * + * Yes, you read that right. + * + * The common workaround is to set *NdisDeviceType to 1, which + * totally disables all Windows firewall functionality. This is + * the answer you'll find on most forums for things like OpenVPN. + * + * Yes, you read that right. + * + * The default route workaround is also known, but for this to + * work there must be a known default IP that resolves to a known + * ARP address. This works for an OpenVPN tunnel, but not here + * because this isn't a tunnel. It's a mesh. There is no "other + * end," or any other known always on IP. + * + * So let's make a fake one and shove it in there along with its + * fake static ARP entry. Also makes it instant-on and static. + * + * We'll have to see what DHCP does with this. In the future we + * probably will not want to do this on DHCP-enabled networks, so + * when we enable DHCP we will go in and yank this wacko hacko from + * the routing table before doing so. + * + * Like Jesse Pinkman would say: "YEEEEAAH BITCH!" */ + const uint32_t fakeIp = htonl(0x19fffffe); // 25.255.255.254 -- unrouted IPv4 block + for (int i = 0; i < 8; ++i) { + MIB_IPNET_ROW2 ipnr; + memset(&ipnr, 0, sizeof(ipnr)); + ipnr.Address.si_family = AF_INET; + ipnr.Address.Ipv4.sin_addr.s_addr = fakeIp; + ipnr.InterfaceLuid.Value = _deviceLuid.Value; + ipnr.PhysicalAddress[0] = _mac[0] ^ 0x10; // just make something up that's consistent and not part of this net + ipnr.PhysicalAddress[1] = 0x00; + ipnr.PhysicalAddress[2] = (UCHAR)((_deviceGuid.Data1 >> 24) & 0xff); + ipnr.PhysicalAddress[3] = (UCHAR)((_deviceGuid.Data1 >> 16) & 0xff); + ipnr.PhysicalAddress[4] = (UCHAR)((_deviceGuid.Data1 >> 8) & 0xff); + ipnr.PhysicalAddress[5] = (UCHAR)(_deviceGuid.Data1 & 0xff); + ipnr.PhysicalAddressLength = 6; + ipnr.State = NlnsPermanent; + ipnr.IsRouter = 1; + ipnr.IsUnreachable = 0; + ipnr.ReachabilityTime.LastReachable = 0x0fffffff; + ipnr.ReachabilityTime.LastUnreachable = 1; + DWORD result = CreateIpNetEntry2(&ipnr); + if (result != NO_ERROR) + Sleep(250); + else + break; + } + for (int i = 0; i < 8; ++i) { + MIB_IPFORWARD_ROW2 nr; + memset(&nr, 0, sizeof(nr)); + InitializeIpForwardEntry(&nr); + nr.InterfaceLuid.Value = _deviceLuid.Value; + nr.DestinationPrefix.Prefix.si_family = AF_INET; // rest is left as 0.0.0.0/0 + nr.NextHop.si_family = AF_INET; + nr.NextHop.Ipv4.sin_addr.s_addr = fakeIp; + nr.Metric = 9999; // do not use as real default route + nr.Protocol = MIB_IPPROTO_NETMGMT; + DWORD result = CreateIpForwardEntry2(&nr); + if (result != NO_ERROR) + Sleep(250); + else + break; + } + } #endif - // Assign or re-assign any should-be-assigned IPs in case we have restarted - { - Mutex::Lock _l(_assignedIps_m); - _syncIps(); - } + // Assign or re-assign any should-be-assigned IPs in case we have restarted + { + Mutex::Lock _l(_assignedIps_m); + _syncIps(); + } - memset(&tapOvlRead,0,sizeof(tapOvlRead)); - tapOvlRead.hEvent = CreateEvent(NULL,TRUE,FALSE,NULL); - memset(&tapOvlWrite,0,sizeof(tapOvlWrite)); - tapOvlWrite.hEvent = CreateEvent(NULL,TRUE,FALSE,NULL); + memset(&tapOvlRead, 0, sizeof(tapOvlRead)); + tapOvlRead.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + memset(&tapOvlWrite, 0, sizeof(tapOvlWrite)); + tapOvlWrite.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); - wait4[0] = _injectSemaphore; - wait4[1] = tapOvlRead.hEvent; - wait4[2] = tapOvlWrite.hEvent; // only included if writeInProgress is true + wait4[0] = _injectSemaphore; + wait4[1] = tapOvlRead.hEvent; + wait4[2] = tapOvlWrite.hEvent; // only included if writeInProgress is true - ReadFile(_tap,tapReadBuf,sizeof(tapReadBuf),NULL,&tapOvlRead); - bool writeInProgress = false; - ULONGLONG timeOfLastBorkCheck = GetTickCount64(); - _initialized = true; - unsigned int oldmtu = _mtu; + ReadFile(_tap, tapReadBuf, sizeof(tapReadBuf), NULL, &tapOvlRead); + bool writeInProgress = false; + ULONGLONG timeOfLastBorkCheck = GetTickCount64(); + _initialized = true; + unsigned int oldmtu = _mtu; - setFriendlyName(_friendlyName.c_str()); + setFriendlyName(_friendlyName.c_str()); - while (_run) { - DWORD waitResult = WaitForMultipleObjectsEx(writeInProgress ? 3 : 2,wait4,FALSE,2500,TRUE); - if (!_run) break; // will also break outer while(_run) since _run is false + while (_run) { + DWORD waitResult = WaitForMultipleObjectsEx(writeInProgress ? 3 : 2, wait4, FALSE, 2500, TRUE); + if (! _run) + break; // will also break outer while(_run) since _run is false - // Check for changes in MTU and break to restart tap device to reconfigure in this case - if (_mtu != oldmtu) - break; + // Check for changes in MTU and break to restart tap device to reconfigure in this case + if (_mtu != oldmtu) + break; - // Check for issues with adapter and close/reopen if any are detected. This - // check fixes a while boatload of Windows adapter 'coma' issues after - // sleep/wake and when adapters are added/removed. Basically if the tap - // device is borked, whack it. - { - ULONGLONG tc = GetTickCount64(); - if ((tc - timeOfLastBorkCheck) >= 2500) { - timeOfLastBorkCheck = tc; - char aabuf[16384]; - ULONG aalen = sizeof(aabuf); - if (GetAdaptersAddresses(AF_UNSPEC,GAA_FLAG_SKIP_UNICAST|GAA_FLAG_SKIP_ANYCAST|GAA_FLAG_SKIP_MULTICAST|GAA_FLAG_SKIP_DNS_SERVER|GAA_FLAG_SKIP_FRIENDLY_NAME,(void *)0,reinterpret_cast(aabuf),&aalen) == NO_ERROR) { - bool isBorked = false; + // Check for issues with adapter and close/reopen if any are detected. This + // check fixes a while boatload of Windows adapter 'coma' issues after + // sleep/wake and when adapters are added/removed. Basically if the tap + // device is borked, whack it. + { + ULONGLONG tc = GetTickCount64(); + if ((tc - timeOfLastBorkCheck) >= 2500) { + timeOfLastBorkCheck = tc; + char aabuf[16384]; + ULONG aalen = sizeof(aabuf); + if (GetAdaptersAddresses( + AF_UNSPEC, + GAA_FLAG_SKIP_UNICAST | GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER | GAA_FLAG_SKIP_FRIENDLY_NAME, + (void*)0, + reinterpret_cast(aabuf), + &aalen) + == NO_ERROR) { + bool isBorked = false; - PIP_ADAPTER_ADDRESSES aa = reinterpret_cast(aabuf); - while (aa) { - if (_deviceLuid.Value == aa->Luid.Value) { - isBorked = (aa->OperStatus != IfOperStatusUp); - break; - } - aa = aa->Next; - } + PIP_ADAPTER_ADDRESSES aa = reinterpret_cast(aabuf); + while (aa) { + if (_deviceLuid.Value == aa->Luid.Value) { + isBorked = (aa->OperStatus != IfOperStatusUp); + break; + } + aa = aa->Next; + } - if (isBorked) { - // Close and reopen tap device if there's an issue (outer loop) - break; - } - } - } - } + if (isBorked) { + // Close and reopen tap device if there's an issue (outer loop) + break; + } + } + } + } - if ((waitResult == WAIT_TIMEOUT)||(waitResult == WAIT_FAILED)) { - Sleep(250); // guard against spinning under some conditions - continue; - } + if ((waitResult == WAIT_TIMEOUT) || (waitResult == WAIT_FAILED)) { + Sleep(250); // guard against spinning under some conditions + continue; + } - if (HasOverlappedIoCompleted(&tapOvlRead)) { - DWORD bytesRead = 0; - if (GetOverlappedResult(_tap,&tapOvlRead,&bytesRead,FALSE)) { - if ((bytesRead > 14)&&(_enabled)) { - MAC to(tapReadBuf,6); - MAC from(tapReadBuf + 6,6); - unsigned int etherType = ((((unsigned int)tapReadBuf[12]) & 0xff) << 8) | (((unsigned int)tapReadBuf[13]) & 0xff); - try { - _handler(_arg,(void *)0,_nwid,from,to,etherType,0,tapReadBuf + 14,bytesRead - 14); - } catch ( ... ) {} // handlers should not throw - } - } - ReadFile(_tap,tapReadBuf,ZT_MAX_MTU + 32,NULL,&tapOvlRead); - } + if (HasOverlappedIoCompleted(&tapOvlRead)) { + DWORD bytesRead = 0; + if (GetOverlappedResult(_tap, &tapOvlRead, &bytesRead, FALSE)) { + if ((bytesRead > 14) && (_enabled)) { + MAC to(tapReadBuf, 6); + MAC from(tapReadBuf + 6, 6); + unsigned int etherType = ((((unsigned int)tapReadBuf[12]) & 0xff) << 8) | (((unsigned int)tapReadBuf[13]) & 0xff); + try { + _handler(_arg, (void*)0, _nwid, from, to, etherType, 0, tapReadBuf + 14, bytesRead - 14); + } + catch (...) { + } // handlers should not throw + } + } + ReadFile(_tap, tapReadBuf, ZT_MAX_MTU + 32, NULL, &tapOvlRead); + } - if (writeInProgress) { - if (HasOverlappedIoCompleted(&tapOvlWrite)) { - writeInProgress = false; - _injectPending_m.lock(); - _injectPending.pop(); - } else continue; // still writing, so skip code below and wait - } else _injectPending_m.lock(); + if (writeInProgress) { + if (HasOverlappedIoCompleted(&tapOvlWrite)) { + writeInProgress = false; + _injectPending_m.lock(); + _injectPending.pop(); + } + else + continue; // still writing, so skip code below and wait + } + else + _injectPending_m.lock(); - if (!_injectPending.empty()) { - WriteFile(_tap,_injectPending.front().data,_injectPending.front().len,NULL,&tapOvlWrite); - writeInProgress = true; - } + if (! _injectPending.empty()) { + WriteFile(_tap, _injectPending.front().data, _injectPending.front().len, NULL, &tapOvlWrite); + writeInProgress = true; + } - _injectPending_m.unlock(); - } + _injectPending_m.unlock(); + } - CancelIo(_tap); + CancelIo(_tap); - CloseHandle(tapOvlRead.hEvent); - CloseHandle(tapOvlWrite.hEvent); - CloseHandle(_tap); - _tap = INVALID_HANDLE_VALUE; + CloseHandle(tapOvlRead.hEvent); + CloseHandle(tapOvlWrite.hEvent); + CloseHandle(_tap); + _tap = INVALID_HANDLE_VALUE; - // We will restart and re-open the tap unless _run == false - } - } catch ( ... ) {} // catch unexpected exceptions -- this should not happen but would prevent program crash or other weird issues since threads should not throw - CoUninitialize(); + // We will restart and re-open the tap unless _run == false + } + } + catch (...) { + } // catch unexpected exceptions -- this should not happen but would prevent program crash or other weird issues since threads should not throw + CoUninitialize(); } NET_IFINDEX WindowsEthernetTap::_getDeviceIndex() { - MIB_IF_TABLE2 *ift = (MIB_IF_TABLE2 *)0; + MIB_IF_TABLE2* ift = (MIB_IF_TABLE2*)0; - if (GetIfTable2Ex(MibIfTableRaw,&ift) != NO_ERROR) - throw std::runtime_error("GetIfTable2Ex() failed"); + if (GetIfTable2Ex(MibIfTableRaw, &ift) != NO_ERROR) + throw std::runtime_error("GetIfTable2Ex() failed"); - if (ift->NumEntries > 0) { - for(ULONG i=0;iNumEntries;++i) { - if (ift->Table[i].InterfaceLuid.Value == _deviceLuid.Value) { - NET_IFINDEX idx = ift->Table[i].InterfaceIndex; - FreeMibTable(ift); - return idx; - } - } - } + if (ift->NumEntries > 0) { + for (ULONG i = 0; i < ift->NumEntries; ++i) { + if (ift->Table[i].InterfaceLuid.Value == _deviceLuid.Value) { + NET_IFINDEX idx = ift->Table[i].InterfaceIndex; + FreeMibTable(ift); + return idx; + } + } + } - FreeMibTable(&ift); + FreeMibTable(&ift); - throw std::runtime_error("interface not found"); + throw std::runtime_error("interface not found"); } -std::vector WindowsEthernetTap::_getRegistryIPv4Value(const char *regKey) +std::vector WindowsEthernetTap::_getRegistryIPv4Value(const char* regKey) { - std::vector value; - HKEY tcpIpInterfaces; - if (RegOpenKeyExA(HKEY_LOCAL_MACHINE,"SYSTEM\\CurrentControlSet\\services\\Tcpip\\Parameters\\Interfaces",0,KEY_READ|KEY_WRITE,&tcpIpInterfaces) == ERROR_SUCCESS) { - char buf[16384]; - DWORD len = sizeof(buf); - DWORD kt = REG_MULTI_SZ; - if (RegGetValueA(tcpIpInterfaces,_netCfgInstanceId.c_str(),regKey,0,&kt,&buf,&len) == ERROR_SUCCESS) { - switch(kt) { - case REG_SZ: - if (len > 0) - value.push_back(std::string(buf)); - break; - case REG_MULTI_SZ: { - for(DWORD k=0,s=0;k value; + HKEY tcpIpInterfaces; + if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\services\\Tcpip\\Parameters\\Interfaces", 0, KEY_READ | KEY_WRITE, &tcpIpInterfaces) == ERROR_SUCCESS) { + char buf[16384]; + DWORD len = sizeof(buf); + DWORD kt = REG_MULTI_SZ; + if (RegGetValueA(tcpIpInterfaces, _netCfgInstanceId.c_str(), regKey, 0, &kt, &buf, &len) == ERROR_SUCCESS) { + switch (kt) { + case REG_SZ: + if (len > 0) + value.push_back(std::string(buf)); + break; + case REG_MULTI_SZ: { + for (DWORD k = 0, s = 0; k < len; ++k) { + if (! buf[k]) { + if (s < k) { + value.push_back(std::string(buf + s)); + s = k + 1; + } + else + break; + } + } + } break; + } + } + RegCloseKey(tcpIpInterfaces); + } + return value; } -void WindowsEthernetTap::_setRegistryIPv4Value(const char *regKey,const std::vector &value) +void WindowsEthernetTap::_setRegistryIPv4Value(const char* regKey, const std::vector& value) { - std::string regMulti; - for(std::vector::const_iterator s(value.begin());s!=value.end();++s) { - regMulti.append(*s); - regMulti.push_back((char)0); - } - HKEY tcpIpInterfaces; - if (RegOpenKeyExA(HKEY_LOCAL_MACHINE,"SYSTEM\\CurrentControlSet\\services\\Tcpip\\Parameters\\Interfaces",0,KEY_READ|KEY_WRITE,&tcpIpInterfaces) == ERROR_SUCCESS) { - if (regMulti.length() > 0) { - regMulti.push_back((char)0); - RegSetKeyValueA(tcpIpInterfaces,_netCfgInstanceId.c_str(),regKey,REG_MULTI_SZ,regMulti.data(),(DWORD)regMulti.length()); - } else { - RegDeleteKeyValueA(tcpIpInterfaces,_netCfgInstanceId.c_str(),regKey); - } - RegCloseKey(tcpIpInterfaces); - } + std::string regMulti; + for (std::vector::const_iterator s(value.begin()); s != value.end(); ++s) { + regMulti.append(*s); + regMulti.push_back((char)0); + } + HKEY tcpIpInterfaces; + if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\services\\Tcpip\\Parameters\\Interfaces", 0, KEY_READ | KEY_WRITE, &tcpIpInterfaces) == ERROR_SUCCESS) { + if (regMulti.length() > 0) { + regMulti.push_back((char)0); + RegSetKeyValueA(tcpIpInterfaces, _netCfgInstanceId.c_str(), regKey, REG_MULTI_SZ, regMulti.data(), (DWORD)regMulti.length()); + } + else { + RegDeleteKeyValueA(tcpIpInterfaces, _netCfgInstanceId.c_str(), regKey); + } + RegCloseKey(tcpIpInterfaces); + } } void WindowsEthernetTap::_syncIps() { - // assumes _assignedIps_m is locked + // assumes _assignedIps_m is locked - if (!_initialized) - return; + if (! _initialized) + return; - std::vector haveIps(ips()); + std::vector haveIps(ips()); - for(std::vector::const_iterator aip(_assignedIps.begin());aip!=_assignedIps.end();++aip) { - if (std::find(haveIps.begin(),haveIps.end(),*aip) == haveIps.end()) { - MIB_UNICASTIPADDRESS_ROW ipr; + for (std::vector::const_iterator aip(_assignedIps.begin()); aip != _assignedIps.end(); ++aip) { + if (std::find(haveIps.begin(), haveIps.end(), *aip) == haveIps.end()) { + MIB_UNICASTIPADDRESS_ROW ipr; - InitializeUnicastIpAddressEntry(&ipr); - if (aip->isV4()) { - ipr.Address.Ipv4.sin_family = AF_INET; - ipr.Address.Ipv4.sin_addr.S_un.S_addr = *((const uint32_t *)aip->rawIpData()); - ipr.OnLinkPrefixLength = aip->netmaskBits(); - if (ipr.OnLinkPrefixLength >= 32) - continue; - } else if (aip->isV6()) { - ipr.Address.Ipv6.sin6_family = AF_INET6; - memcpy(ipr.Address.Ipv6.sin6_addr.u.Byte,aip->rawIpData(),16); - ipr.OnLinkPrefixLength = aip->netmaskBits(); - if (ipr.OnLinkPrefixLength >= 128) - continue; - } else continue; + InitializeUnicastIpAddressEntry(&ipr); + if (aip->isV4()) { + ipr.Address.Ipv4.sin_family = AF_INET; + ipr.Address.Ipv4.sin_addr.S_un.S_addr = *((const uint32_t*)aip->rawIpData()); + ipr.OnLinkPrefixLength = aip->netmaskBits(); + if (ipr.OnLinkPrefixLength >= 32) + continue; + } + else if (aip->isV6()) { + ipr.Address.Ipv6.sin6_family = AF_INET6; + memcpy(ipr.Address.Ipv6.sin6_addr.u.Byte, aip->rawIpData(), 16); + ipr.OnLinkPrefixLength = aip->netmaskBits(); + if (ipr.OnLinkPrefixLength >= 128) + continue; + } + else + continue; - ipr.PrefixOrigin = IpPrefixOriginManual; - ipr.SuffixOrigin = IpSuffixOriginManual; - ipr.ValidLifetime = 0xffffffff; - ipr.PreferredLifetime = 0xffffffff; + ipr.PrefixOrigin = IpPrefixOriginManual; + ipr.SuffixOrigin = IpSuffixOriginManual; + ipr.ValidLifetime = 0xffffffff; + ipr.PreferredLifetime = 0xffffffff; - ipr.InterfaceLuid = _deviceLuid; - ipr.InterfaceIndex = _getDeviceIndex(); + ipr.InterfaceLuid = _deviceLuid; + ipr.InterfaceIndex = _getDeviceIndex(); - CreateUnicastIpAddressEntry(&ipr); - } + CreateUnicastIpAddressEntry(&ipr); + } - if (aip->isV4()) { - char ipbuf[64]; - std::string ipStr(aip->toIpString(ipbuf)); - std::vector regIps(_getRegistryIPv4Value("IPAddress")); - if (std::find(regIps.begin(), regIps.end(), ipStr) == regIps.end()) { - std::vector regSubnetMasks(_getRegistryIPv4Value("SubnetMask")); - regIps.push_back(ipStr); - regSubnetMasks.push_back(aip->netmask().toIpString(ipbuf)); - _setRegistryIPv4Value("IPAddress", regIps); - _setRegistryIPv4Value("SubnetMask", regSubnetMasks); - } - } - } + if (aip->isV4()) { + char ipbuf[64]; + std::string ipStr(aip->toIpString(ipbuf)); + std::vector regIps(_getRegistryIPv4Value("IPAddress")); + if (std::find(regIps.begin(), regIps.end(), ipStr) == regIps.end()) { + std::vector regSubnetMasks(_getRegistryIPv4Value("SubnetMask")); + regIps.push_back(ipStr); + regSubnetMasks.push_back(aip->netmask().toIpString(ipbuf)); + _setRegistryIPv4Value("IPAddress", regIps); + _setRegistryIPv4Value("SubnetMask", regSubnetMasks); + } + } + } } void WindowsEthernetTap::setDns(const char* domain, const std::vector& servers) { - WinDNSHelper::setDNS(_nwid, domain, servers); + WinDNSHelper::setDNS(_nwid, domain, servers); } -} // namespace ZeroTier +} // namespace ZeroTier diff --git a/osdep/WindowsEthernetTap.hpp b/osdep/WindowsEthernetTap.hpp index 13721d65..a0e2817d 100644 --- a/osdep/WindowsEthernetTap.hpp +++ b/osdep/WindowsEthernetTap.hpp @@ -14,149 +14,156 @@ #ifndef ZT_WINDOWSETHERNETTAP_HPP #define ZT_WINDOWSETHERNETTAP_HPP -#include -#include - -#include - -#include -#include -#include - #include "../node/Constants.hpp" -#include "../node/Mutex.hpp" -#include "../node/MulticastGroup.hpp" #include "../node/InetAddress.hpp" +#include "../node/MulticastGroup.hpp" +#include "../node/Mutex.hpp" #include "../osdep/Thread.hpp" #include "EthernetTap.hpp" +#include +#include +#include +#include +#include +#include + namespace ZeroTier { -class WindowsEthernetTap : public EthernetTap -{ -public: - /** - * Installs a new instance of the ZT tap driver - * - * @param pathToInf Path to zttap driver .inf file - * @param deviceInstanceId Buffer to fill with device instance ID on success (and if SetupDiGetDeviceInstanceIdA succeeds, which it should) - * @return Empty string on success, otherwise an error message - */ - static std::string addNewPersistentTapDevice(const char *pathToInf,std::string &deviceInstanceId); +class WindowsEthernetTap : public EthernetTap { + public: + /** + * Installs a new instance of the ZT tap driver + * + * @param pathToInf Path to zttap driver .inf file + * @param deviceInstanceId Buffer to fill with device instance ID on success (and if SetupDiGetDeviceInstanceIdA succeeds, which it should) + * @return Empty string on success, otherwise an error message + */ + static std::string addNewPersistentTapDevice(const char* pathToInf, std::string& deviceInstanceId); - /** - * Uninstalls all persistent tap devices that have legacy drivers - * - * @return Empty string on success, otherwise an error message - */ - static std::string destroyAllLegacyPersistentTapDevices(); + /** + * Uninstalls all persistent tap devices that have legacy drivers + * + * @return Empty string on success, otherwise an error message + */ + static std::string destroyAllLegacyPersistentTapDevices(); - /** - * Uninstalls all persistent tap devices on the system - * - * @return Empty string on success, otherwise an error message - */ - static std::string destroyAllPersistentTapDevices(); + /** + * Uninstalls all persistent tap devices on the system + * + * @return Empty string on success, otherwise an error message + */ + static std::string destroyAllPersistentTapDevices(); - /** - * Uninstalls a specific persistent tap device by instance ID - * - * @param instanceId Device instance ID - * @return Empty string on success, otherwise an error message - */ - static std::string deletePersistentTapDevice(const char *instanceId); + /** + * Uninstalls a specific persistent tap device by instance ID + * + * @param instanceId Device instance ID + * @return Empty string on success, otherwise an error message + */ + static std::string deletePersistentTapDevice(const char* instanceId); - /** - * Disable a persistent tap device by instance ID - * - * @param instanceId Device instance ID - * @param enabled Enable device? - * @return True if device was found and disabled - */ - static bool setPersistentTapDeviceState(const char *instanceId,bool enabled); + /** + * Disable a persistent tap device by instance ID + * + * @param instanceId Device instance ID + * @param enabled Enable device? + * @return True if device was found and disabled + */ + static bool setPersistentTapDeviceState(const char* instanceId, bool enabled); - WindowsEthernetTap( - const char *hp, - const MAC &mac, - unsigned int mtu, - unsigned int metric, - uint64_t nwid, - const char *friendlyName, - void (*handler)(void *,void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int), - void *arg); + WindowsEthernetTap( + const char* hp, + const MAC& mac, + unsigned int mtu, + unsigned int metric, + uint64_t nwid, + const char* friendlyName, + void (*handler)(void*, void*, uint64_t, const MAC&, const MAC&, unsigned int, unsigned int, const void*, unsigned int), + void* arg); - virtual ~WindowsEthernetTap(); + virtual ~WindowsEthernetTap(); - virtual void setEnabled(bool en); - virtual bool enabled() const; - virtual bool addIp(const InetAddress &ip); - virtual bool removeIp(const InetAddress &ip); - virtual std::vector ips() const; - virtual void put(const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len); - virtual std::string deviceName() const; - virtual void setFriendlyName(const char *friendlyName); - virtual std::string friendlyName() const; - virtual void scanMulticastGroups(std::vector &added,std::vector &removed); - virtual void setMtu(unsigned int mtu); - virtual void setDns(const char* domain, const std::vector &servers); + virtual void setEnabled(bool en); + virtual bool enabled() const; + virtual bool addIp(const InetAddress& ip); + virtual bool removeIp(const InetAddress& ip); + virtual std::vector ips() const; + virtual void put(const MAC& from, const MAC& to, unsigned int etherType, const void* data, unsigned int len); + virtual std::string deviceName() const; + virtual void setFriendlyName(const char* friendlyName); + virtual std::string friendlyName() const; + virtual void scanMulticastGroups(std::vector& added, std::vector& removed); + virtual void setMtu(unsigned int mtu); + virtual void setDns(const char* domain, const std::vector& servers); - inline const NET_LUID &luid() const { return _deviceLuid; } - inline const GUID &guid() const { return _deviceGuid; } - inline const std::string &instanceId() const { return _deviceInstanceId; } - NET_IFINDEX interfaceIndex() const; + inline const NET_LUID& luid() const + { + return _deviceLuid; + } + inline const GUID& guid() const + { + return _deviceGuid; + } + inline const std::string& instanceId() const + { + return _deviceInstanceId; + } + NET_IFINDEX interfaceIndex() const; - void threadMain() - throw(); + void threadMain() throw(); - bool isInitialized() const { return _initialized; }; + bool isInitialized() const + { + return _initialized; + }; -private: - NET_IFINDEX _getDeviceIndex(); // throws on failure - std::vector _getRegistryIPv4Value(const char *regKey); - void _setRegistryIPv4Value(const char *regKey,const std::vector &value); - void _syncIps(); + private: + NET_IFINDEX _getDeviceIndex(); // throws on failure + std::vector _getRegistryIPv4Value(const char* regKey); + void _setRegistryIPv4Value(const char* regKey, const std::vector& value); + void _syncIps(); - void (*_handler)(void *,void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int); - void *_arg; - MAC _mac; - uint64_t _nwid; - volatile unsigned int _mtu; - Thread _thread; + void (*_handler)(void*, void*, uint64_t, const MAC&, const MAC&, unsigned int, unsigned int, const void*, unsigned int); + void* _arg; + MAC _mac; + uint64_t _nwid; + volatile unsigned int _mtu; + Thread _thread; - volatile HANDLE _tap; - HANDLE _injectSemaphore; + volatile HANDLE _tap; + HANDLE _injectSemaphore; - GUID _deviceGuid; - NET_LUID _deviceLuid; - std::string _netCfgInstanceId; - std::string _deviceInstanceId; - std::string _mySubkeyName; - std::string _friendlyName; - Mutex _friendlyName_m; + GUID _deviceGuid; + NET_LUID _deviceLuid; + std::string _netCfgInstanceId; + std::string _deviceInstanceId; + std::string _mySubkeyName; + std::string _friendlyName; + Mutex _friendlyName_m; - std::vector _assignedIps; // IPs assigned with addIp - Mutex _assignedIps_m; + std::vector _assignedIps; // IPs assigned with addIp + Mutex _assignedIps_m; - std::vector _multicastGroups; + std::vector _multicastGroups; - struct _InjectPending - { - unsigned int len; - char data[ZT_MAX_MTU + 32]; - }; - std::queue<_InjectPending> _injectPending; - Mutex _injectPending_m; + struct _InjectPending { + unsigned int len; + char data[ZT_MAX_MTU + 32]; + }; + std::queue<_InjectPending> _injectPending; + Mutex _injectPending_m; - std::string _pathToHelpers; + std::string _pathToHelpers; - volatile bool _run; - volatile bool _initialized; - volatile bool _enabled; + volatile bool _run; + volatile bool _initialized; + volatile bool _enabled; - mutable std::vector _ifaddrs; - mutable uint64_t _lastIfAddrsUpdate; + mutable std::vector _ifaddrs; + mutable uint64_t _lastIfAddrsUpdate; }; -} // namespace ZeroTier +} // namespace ZeroTier #endif diff --git a/rustybits/Cargo.lock b/rustybits/Cargo.lock index 8ad2b56c..69d034d7 100644 --- a/rustybits/Cargo.lock +++ b/rustybits/Cargo.lock @@ -76,9 +76,9 @@ checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1" [[package]] name = "anyhow" -version = "1.0.87" +version = "1.0.88" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10f00e1f6e58a40e807377c75c6a7f97bf9044fab57816f2414e6f5f4499d7b8" +checksum = "4e1496f8fb1fbf272686b8d37f523dab3e4a7443300055e74cdaa449f3114356" [[package]] name = "async-stream" @@ -1628,9 +1628,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.19.0" +version = "1.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +checksum = "33ea5043e58958ee56f3e15a90aee535795cd7dfd319846288d93c5b57d85cbe" [[package]] name = "openidconnect" @@ -2137,9 +2137,9 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.5.3" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a908a6e00f1fdd0dfd9c0eb08ce85126f6d8bbda50017e74bc4a4b7d4a926a4" +checksum = "0884ad60e090bf1345b93da0a5de8923c93884cd03f40dfcfddd3b4bee661853" dependencies = [ "bitflags 2.6.0", ] @@ -2325,9 +2325,9 @@ source = "git+https://github.com/temporalio/sdk-core?branch=master#a8150d5c7c3fc [[package]] name = "rustix" -version = "0.38.36" +version = "0.38.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f55e80d50763938498dd5ebb18647174e0c76dc38c5505294bb224624f30f36" +checksum = "8acb788b847c24f28525660c4d7758620a7210875711f79e7f663cc152726811" dependencies = [ "bitflags 2.6.0", "errno", @@ -3336,9 +3336,9 @@ dependencies = [ [[package]] name = "unicode-segmentation" -version = "1.11.0" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" +checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" [[package]] name = "unicode-width" diff --git a/selftest.cpp b/selftest.cpp index 0a18caa7..058d9c5f 100644 --- a/selftest.cpp +++ b/selftest.cpp @@ -36,7 +36,7 @@ #include "node/Peer.hpp" #include "node/Dictionary.hpp" #include "node/SHA512.hpp" -#include "node/C25519.hpp" +#include "node/ECC.hpp" #include "node/Poly1305.hpp" #include "node/CertificateOfMembership.hpp" #include "node/Node.hpp" @@ -361,13 +361,13 @@ static int testCrypto() std::cout << "[crypto] Testing C25519 and Ed25519 against test vectors... "; std::cout.flush(); for(int k=0;kp2 should equal p2<>p1 if (memcmp(buf1,buf2,64)) { std::cout << "FAIL (1)" << std::endl; @@ -414,45 +414,45 @@ static int testCrypto() std::cout << "PASS" << std::endl; std::cout << "[crypto] Benchmarking C25519 ECC key agreement... "; std::cout.flush(); - C25519::Pair bp[8]; + ECC::Pair bp[8]; for(int k=0;k<8;++k) - bp[k] = C25519::generate(); + bp[k] = ECC::generate(); uint64_t st = OSUtils::now(); for(unsigned int k=0;k<50;++k) { - C25519::agree(bp[~k & 7],bp[k & 7].pub,buf1,64); + ECC::agree(bp[~k & 7],bp[k & 7].pub,buf1,64); } uint64_t et = OSUtils::now(); std::cout << ((double)(et - st) / 50.0) << "ms per agreement." << std::endl; std::cout << "[crypto] Testing Ed25519 ECC signatures... "; std::cout.flush(); - C25519::Pair didntSign = C25519::generate(); + ECC::Pair didntSign = ECC::generate(); for(unsigned int i=0;i<10;++i) { - C25519::Pair p1 = C25519::generate(); + ECC::Pair p1 = ECC::generate(); for(unsigned int k=0;k 0) ? "," : ""),(unsigned int)p1.pub.data[i]); diff --git a/service/OneService.cpp b/service/OneService.cpp index d9f63334..7f5485ba 100644 --- a/service/OneService.cpp +++ b/service/OneService.cpp @@ -11,51 +11,48 @@ */ /****/ +#include +#include #include +#include +#include +#include +#include #include #include #include -#include #include -#include -#include -#include -#include #include -#include -#include +#include #ifdef __FreeBSD__ -#include #include +#include #endif -#include "../version.h" #include "../include/ZeroTierOne.h" - +#include "../node/Bond.hpp" #include "../node/Constants.hpp" -#include "../node/Mutex.hpp" -#include "../node/Node.hpp" -#include "../node/Utils.hpp" +#include "../node/Identity.hpp" #include "../node/InetAddress.hpp" #include "../node/MAC.hpp" -#include "../node/Identity.hpp" -#include "../node/World.hpp" -#include "../node/Salsa20.hpp" +#include "../node/Mutex.hpp" +#include "../node/Node.hpp" +#include "../node/PacketMultiplexer.hpp" +#include "../node/Peer.hpp" #include "../node/Poly1305.hpp" #include "../node/SHA512.hpp" -#include "../node/Bond.hpp" -#include "../node/Peer.hpp" -#include "../node/PacketMultiplexer.hpp" - -#include "../osdep/Phy.hpp" -#include "../osdep/OSUtils.hpp" -#include "../osdep/Http.hpp" -#include "../osdep/PortMapper.hpp" +#include "../node/Salsa20.hpp" +#include "../node/Utils.hpp" +#include "../node/World.hpp" #include "../osdep/Binder.hpp" -#include "../osdep/ManagedRoute.hpp" #include "../osdep/BlockingQueue.hpp" - +#include "../osdep/Http.hpp" +#include "../osdep/ManagedRoute.hpp" +#include "../osdep/OSUtils.hpp" +#include "../osdep/Phy.hpp" +#include "../osdep/PortMapper.hpp" +#include "../version.h" #include "OneService.hpp" #include "SoftwareUpdater.hpp" @@ -66,20 +63,20 @@ #endif #ifdef __WINDOWS__ -#include -#include -#include -#include #include -//#include +#include +#include +#include +#include +// #include #define stat _stat #else -#include +#include #include #include +#include #include #include -#include #endif #ifdef __APPLE__ @@ -103,8 +100,8 @@ extern "C" { } #endif -#include #include +#include using json = nlohmann::json; @@ -122,7 +119,7 @@ using json = nlohmann::json; // Sanity limits for HTTP #define ZT_MAX_HTTP_MESSAGE_SIZE (1024 * 1024 * 64) -#define ZT_MAX_HTTP_CONNECTIONS 65536 +#define ZT_MAX_HTTP_CONNECTIONS 65536 // Interface metric for ZeroTier taps -- this ensures that if we are on WiFi and also // bridged via ZeroTier to the same LAN traffic will (if the OS is sane) prefer WiFi. @@ -152,14 +149,13 @@ using json = nlohmann::json; #define ZT_TCP_ACTIVITY_TIMEOUT 60000 #if ZT_VAULT_SUPPORT -size_t curlResponseWrite(void *ptr, size_t size, size_t nmemb, std::string *data) +size_t curlResponseWrite(void* ptr, size_t size, size_t nmemb, std::string* data) { - data->append((char*)ptr, size * nmemb); - return size * nmemb; + data->append((char*)ptr, size * nmemb); + return size * nmemb; } #endif - namespace ZeroTier { std::string ssoResponseTemplate = R"""( @@ -206,276 +202,283 @@ std::string ssoResponseTemplate = R"""( )"""; -bool bearerTokenValid(const std::string authHeader, const std::string &checkToken) { - std::vector tokens = OSUtils::split(authHeader.c_str(), " ", NULL, NULL); - if (tokens.size() != 2) { - return false; - } +bool bearerTokenValid(const std::string authHeader, const std::string& checkToken) +{ + std::vector tokens = OSUtils::split(authHeader.c_str(), " ", NULL, NULL); + if (tokens.size() != 2) { + return false; + } - std::string bearer = tokens[0]; - std::string token = tokens[1]; - std::transform(bearer.begin(), bearer.end(), bearer.begin(), [](unsigned char c){return std::tolower(c);}); - if (bearer != "bearer") { - return false; - } + std::string bearer = tokens[0]; + std::string token = tokens[1]; + std::transform(bearer.begin(), bearer.end(), bearer.begin(), [](unsigned char c) { return std::tolower(c); }); + if (bearer != "bearer") { + return false; + } - if (token != checkToken) { - return false; - } + if (token != checkToken) { + return false; + } - return true; + return true; } -#if ZT_DEBUG==1 -std::string dump_headers(const httplib::Headers &headers) { - std::string s; - char buf[BUFSIZ]; +#if ZT_DEBUG == 1 +std::string dump_headers(const httplib::Headers& headers) +{ + std::string s; + char buf[BUFSIZ]; - for (auto it = headers.begin(); it != headers.end(); ++it) { - const auto &x = *it; - snprintf(buf, sizeof(buf), "%s: %s\n", x.first.c_str(), x.second.c_str()); + for (auto it = headers.begin(); it != headers.end(); ++it) { + const auto& x = *it; + snprintf(buf, sizeof(buf), "%s: %s\n", x.first.c_str(), x.second.c_str()); + s += buf; + } + + return s; +} + +std::string http_log(const httplib::Request& req, const httplib::Response& res) +{ + std::string s; + char buf[BUFSIZ]; + + s += "================================\n"; + + snprintf(buf, sizeof(buf), "%s %s %s", req.method.c_str(), req.version.c_str(), req.path.c_str()); s += buf; - } - return s; -} + std::string query; + for (auto it = req.params.begin(); it != req.params.end(); ++it) { + const auto& x = *it; + snprintf(buf, sizeof(buf), "%c%s=%s", (it == req.params.begin()) ? '?' : '&', x.first.c_str(), x.second.c_str()); + query += buf; + } + snprintf(buf, sizeof(buf), "%s\n", query.c_str()); + s += buf; -std::string http_log(const httplib::Request &req, const httplib::Response &res) { - std::string s; - char buf[BUFSIZ]; + s += dump_headers(req.headers); - s += "================================\n"; + s += "--------------------------------\n"; - snprintf(buf, sizeof(buf), "%s %s %s", req.method.c_str(), - req.version.c_str(), req.path.c_str()); - s += buf; + snprintf(buf, sizeof(buf), "%d %s\n", res.status, res.version.c_str()); + s += buf; + s += dump_headers(res.headers); + s += "\n"; - std::string query; - for (auto it = req.params.begin(); it != req.params.end(); ++it) { - const auto &x = *it; - snprintf(buf, sizeof(buf), "%c%s=%s", - (it == req.params.begin()) ? '?' : '&', x.first.c_str(), - x.second.c_str()); - query += buf; - } - snprintf(buf, sizeof(buf), "%s\n", query.c_str()); - s += buf; + if (! res.body.empty()) { + s += res.body; + } - s += dump_headers(req.headers); + s += "\n"; - s += "--------------------------------\n"; - - snprintf(buf, sizeof(buf), "%d %s\n", res.status, res.version.c_str()); - s += buf; - s += dump_headers(res.headers); - s += "\n"; - - if (!res.body.empty()) { s += res.body; } - - s += "\n"; - - return s; + return s; } #endif // Configured networks -class NetworkState -{ -public: - NetworkState() - : _webPort(9993) - , _tap((EthernetTap *)0) +class NetworkState { + public: + NetworkState() + : _webPort(9993) + , _tap((EthernetTap*)0) #if ZT_SSO_ENABLED - , _idc(nullptr) + , _idc(nullptr) #endif - { - // Real defaults are in network 'up' code in network event handler - _settings.allowManaged = true; - _settings.allowGlobal = false; - _settings.allowDefault = false; - _settings.allowDNS = false; - memset(&_config, 0, sizeof(ZT_VirtualNetworkConfig)); - } + { + // Real defaults are in network 'up' code in network event handler + _settings.allowManaged = true; + _settings.allowGlobal = false; + _settings.allowDefault = false; + _settings.allowDNS = false; + memset(&_config, 0, sizeof(ZT_VirtualNetworkConfig)); + } - ~NetworkState() - { - this->_managedRoutes.clear(); - this->_tap.reset(); + ~NetworkState() + { + this->_managedRoutes.clear(); + this->_tap.reset(); #if ZT_SSO_ENABLED - if (_idc) { - zeroidc::zeroidc_stop(_idc); - zeroidc::zeroidc_delete(_idc); - _idc = nullptr; - } + if (_idc) { + zeroidc::zeroidc_stop(_idc); + zeroidc::zeroidc_delete(_idc); + _idc = nullptr; + } #endif - } + } - void setWebPort(unsigned int port) { - _webPort = port; - } + void setWebPort(unsigned int port) + { + _webPort = port; + } - void setTap(std::shared_ptr tap) { - this->_tap = tap; - } + void setTap(std::shared_ptr tap) + { + this->_tap = tap; + } - std::shared_ptr tap() const { - return _tap; - } + std::shared_ptr tap() const + { + return _tap; + } - OneService::NetworkSettings settings() const { - return _settings; - } + OneService::NetworkSettings settings() const + { + return _settings; + } - void setSettings(const OneService::NetworkSettings &settings) { - _settings = settings; - } + void setSettings(const OneService::NetworkSettings& settings) + { + _settings = settings; + } - void setAllowManaged(bool allow) { - _settings.allowManaged = allow; - } + void setAllowManaged(bool allow) + { + _settings.allowManaged = allow; + } - bool allowManaged() const { - return _settings.allowManaged; - } + bool allowManaged() const + { + return _settings.allowManaged; + } - void setAllowGlobal(bool allow) { - _settings.allowGlobal = allow; - } + void setAllowGlobal(bool allow) + { + _settings.allowGlobal = allow; + } - bool allowGlobal() const { - return _settings.allowGlobal; - } + bool allowGlobal() const + { + return _settings.allowGlobal; + } - void setAllowDefault(bool allow) { - _settings.allowDefault = allow; - } + void setAllowDefault(bool allow) + { + _settings.allowDefault = allow; + } - bool allowDefault() const { - return _settings.allowDefault; - } + bool allowDefault() const + { + return _settings.allowDefault; + } - void setAllowDNS(bool allow) { - _settings.allowDNS = allow; - } + void setAllowDNS(bool allow) + { + _settings.allowDNS = allow; + } - bool allowDNS() const { - return _settings.allowDNS; - } + bool allowDNS() const + { + return _settings.allowDNS; + } - std::vector allowManagedWhitelist() const { - return _settings.allowManagedWhitelist; - } + std::vector allowManagedWhitelist() const + { + return _settings.allowManagedWhitelist; + } - void addToAllowManagedWhiteList(const InetAddress& addr) { - _settings.allowManagedWhitelist.push_back(addr); - } + void addToAllowManagedWhiteList(const InetAddress& addr) + { + _settings.allowManagedWhitelist.push_back(addr); + } - const ZT_VirtualNetworkConfig& config() { - return _config; - } + const ZT_VirtualNetworkConfig& config() + { + return _config; + } - void setConfig(const ZT_VirtualNetworkConfig *nwc) { - memcpy(&_config, nwc, sizeof(ZT_VirtualNetworkConfig)); + void setConfig(const ZT_VirtualNetworkConfig* nwc) + { + memcpy(&_config, nwc, sizeof(ZT_VirtualNetworkConfig)); - if (_config.ssoEnabled && _config.ssoVersion == 1) { + if (_config.ssoEnabled && _config.ssoVersion == 1) { #if ZT_SSO_ENABLED - if (_idc == nullptr) - { - assert(_config.issuerURL != nullptr); - assert(_config.ssoClientID != nullptr); - assert(_config.centralAuthURL != nullptr); - assert(_config.ssoProvider != nullptr); + if (_idc == nullptr) { + assert(_config.issuerURL != nullptr); + assert(_config.ssoClientID != nullptr); + assert(_config.centralAuthURL != nullptr); + assert(_config.ssoProvider != nullptr); - _idc = zeroidc::zeroidc_new( - _config.issuerURL, - _config.ssoClientID, - _config.centralAuthURL, - _config.ssoProvider, - _webPort - ); + _idc = zeroidc::zeroidc_new(_config.issuerURL, _config.ssoClientID, _config.centralAuthURL, _config.ssoProvider, _webPort); - if (_idc == nullptr) { - fprintf(stderr, "idc is null\n"); - return; - } - } + if (_idc == nullptr) { + fprintf(stderr, "idc is null\n"); + return; + } + } - zeroidc::zeroidc_set_nonce_and_csrf( - _idc, - _config.ssoState, - _config.ssoNonce - ); + zeroidc::zeroidc_set_nonce_and_csrf(_idc, _config.ssoState, _config.ssoNonce); - char* url = zeroidc::zeroidc_get_auth_url(_idc); - memcpy(_config.authenticationURL, url, strlen(url)); - _config.authenticationURL[strlen(url)] = 0; - zeroidc::free_cstr(url); + char* url = zeroidc::zeroidc_get_auth_url(_idc); + memcpy(_config.authenticationURL, url, strlen(url)); + _config.authenticationURL[strlen(url)] = 0; + zeroidc::free_cstr(url); - if (zeroidc::zeroidc_is_running(_idc) && nwc->status == ZT_NETWORK_STATUS_AUTHENTICATION_REQUIRED) { - zeroidc::zeroidc_kick_refresh_thread(_idc); - } + if (zeroidc::zeroidc_is_running(_idc) && nwc->status == ZT_NETWORK_STATUS_AUTHENTICATION_REQUIRED) { + zeroidc::zeroidc_kick_refresh_thread(_idc); + } #endif - } - } + } + } - std::vector& managedIps() { - return _managedIps; - } + std::vector& managedIps() + { + return _managedIps; + } - void setManagedIps(const std::vector &managedIps) { - _managedIps = managedIps; - } + void setManagedIps(const std::vector& managedIps) + { + _managedIps = managedIps; + } - std::map< InetAddress, SharedPtr >& managedRoutes() { - return _managedRoutes; - } + std::map >& managedRoutes() + { + return _managedRoutes; + } - - char* doTokenExchange(const char *code) { - char *ret = nullptr; + char* doTokenExchange(const char* code) + { + char* ret = nullptr; #if ZT_SSO_ENABLED - if (_idc == nullptr) { - fprintf(stderr, "ainfo or idc null\n"); - return ret; - } + if (_idc == nullptr) { + fprintf(stderr, "ainfo or idc null\n"); + return ret; + } - ret = zeroidc::zeroidc_token_exchange(_idc, code); - zeroidc::zeroidc_set_nonce_and_csrf( - _idc, - _config.ssoState, - _config.ssoNonce - ); + ret = zeroidc::zeroidc_token_exchange(_idc, code); + zeroidc::zeroidc_set_nonce_and_csrf(_idc, _config.ssoState, _config.ssoNonce); - char* url = zeroidc::zeroidc_get_auth_url(_idc); - memcpy(_config.authenticationURL, url, strlen(url)); - _config.authenticationURL[strlen(url)] = 0; - zeroidc::free_cstr(url); + char* url = zeroidc::zeroidc_get_auth_url(_idc); + memcpy(_config.authenticationURL, url, strlen(url)); + _config.authenticationURL[strlen(url)] = 0; + zeroidc::free_cstr(url); #endif - return ret; - } + return ret; + } - uint64_t getExpiryTime() { + uint64_t getExpiryTime() + { #if ZT_SSO_ENABLED - if (_idc == nullptr) { - fprintf(stderr, "idc is null\n"); - return 0; - } - return zeroidc::zeroidc_get_exp_time(_idc); + if (_idc == nullptr) { + fprintf(stderr, "idc is null\n"); + return 0; + } + return zeroidc::zeroidc_get_exp_time(_idc); #else - return 0; + return 0; #endif - } + } -private: - unsigned int _webPort; - std::shared_ptr _tap; - ZT_VirtualNetworkConfig _config; // memcpy() of raw config from core - std::vector _managedIps; - std::map< InetAddress, SharedPtr > _managedRoutes; - OneService::NetworkSettings _settings; + private: + unsigned int _webPort; + std::shared_ptr _tap; + ZT_VirtualNetworkConfig _config; // memcpy() of raw config from core + std::vector _managedIps; + std::map > _managedRoutes; + OneService::NetworkSettings _settings; #if ZT_SSO_ENABLED - zeroidc::ZeroIDC *_idc; + zeroidc::ZeroIDC* _idc; #endif }; @@ -484,1701 +487,1740 @@ namespace { static const InetAddress NULL_INET_ADDR; // Fake TLS hello for TCP tunnel outgoing connections (TUNNELED mode) -static const char ZT_TCP_TUNNEL_HELLO[9] = { 0x17,0x03,0x03,0x00,0x04,(char)ZEROTIER_ONE_VERSION_MAJOR,(char)ZEROTIER_ONE_VERSION_MINOR,(char)((ZEROTIER_ONE_VERSION_REVISION >> 8) & 0xff),(char)(ZEROTIER_ONE_VERSION_REVISION & 0xff) }; +static const char ZT_TCP_TUNNEL_HELLO[9] = { + 0x17, 0x03, 0x03, 0x00, 0x04, (char)ZEROTIER_ONE_VERSION_MAJOR, (char)ZEROTIER_ONE_VERSION_MINOR, (char)((ZEROTIER_ONE_VERSION_REVISION >> 8) & 0xff), (char)(ZEROTIER_ONE_VERSION_REVISION & 0xff) +}; -static std::string _trimString(const std::string &s) +static std::string _trimString(const std::string& s) { - unsigned long end = (unsigned long)s.length(); - while (end) { - char c = s[end - 1]; - if ((c == ' ')||(c == '\r')||(c == '\n')||(!c)||(c == '\t')) - --end; - else break; - } - unsigned long start = 0; - while (start < end) { - char c = s[start]; - if ((c == ' ')||(c == '\r')||(c == '\n')||(!c)||(c == '\t')) - ++start; - else break; - } - return s.substr(start,end - start); + unsigned long end = (unsigned long)s.length(); + while (end) { + char c = s[end - 1]; + if ((c == ' ') || (c == '\r') || (c == '\n') || (! c) || (c == '\t')) + --end; + else + break; + } + unsigned long start = 0; + while (start < end) { + char c = s[start]; + if ((c == ' ') || (c == '\r') || (c == '\n') || (! c) || (c == '\t')) + ++start; + else + break; + } + return s.substr(start, end - start); } -static void _networkToJson(nlohmann::json &nj,NetworkState &ns) +static void _networkToJson(nlohmann::json& nj, NetworkState& ns) { - char tmp[256]; + char tmp[256]; - const char *nstatus = "",*ntype = ""; - switch(ns.config().status) { - case ZT_NETWORK_STATUS_REQUESTING_CONFIGURATION: nstatus = "REQUESTING_CONFIGURATION"; break; - case ZT_NETWORK_STATUS_OK: nstatus = "OK"; break; - case ZT_NETWORK_STATUS_ACCESS_DENIED: nstatus = "ACCESS_DENIED"; break; - case ZT_NETWORK_STATUS_NOT_FOUND: nstatus = "NOT_FOUND"; break; - case ZT_NETWORK_STATUS_PORT_ERROR: nstatus = "PORT_ERROR"; break; - case ZT_NETWORK_STATUS_CLIENT_TOO_OLD: nstatus = "CLIENT_TOO_OLD"; break; - case ZT_NETWORK_STATUS_AUTHENTICATION_REQUIRED: nstatus = "AUTHENTICATION_REQUIRED"; break; - } - switch(ns.config().type) { - case ZT_NETWORK_TYPE_PRIVATE: ntype = "PRIVATE"; break; - case ZT_NETWORK_TYPE_PUBLIC: ntype = "PUBLIC"; break; - } + const char *nstatus = "", *ntype = ""; + switch (ns.config().status) { + case ZT_NETWORK_STATUS_REQUESTING_CONFIGURATION: + nstatus = "REQUESTING_CONFIGURATION"; + break; + case ZT_NETWORK_STATUS_OK: + nstatus = "OK"; + break; + case ZT_NETWORK_STATUS_ACCESS_DENIED: + nstatus = "ACCESS_DENIED"; + break; + case ZT_NETWORK_STATUS_NOT_FOUND: + nstatus = "NOT_FOUND"; + break; + case ZT_NETWORK_STATUS_PORT_ERROR: + nstatus = "PORT_ERROR"; + break; + case ZT_NETWORK_STATUS_CLIENT_TOO_OLD: + nstatus = "CLIENT_TOO_OLD"; + break; + case ZT_NETWORK_STATUS_AUTHENTICATION_REQUIRED: + nstatus = "AUTHENTICATION_REQUIRED"; + break; + } + switch (ns.config().type) { + case ZT_NETWORK_TYPE_PRIVATE: + ntype = "PRIVATE"; + break; + case ZT_NETWORK_TYPE_PUBLIC: + ntype = "PUBLIC"; + break; + } - OSUtils::ztsnprintf(tmp,sizeof(tmp),"%.16llx",ns.config().nwid); - nj["id"] = tmp; - nj["nwid"] = tmp; - OSUtils::ztsnprintf(tmp,sizeof(tmp),"%.2x:%.2x:%.2x:%.2x:%.2x:%.2x",(unsigned int)((ns.config().mac >> 40) & 0xff),(unsigned int)((ns.config().mac >> 32) & 0xff),(unsigned int)((ns.config().mac >> 24) & 0xff),(unsigned int)((ns.config().mac >> 16) & 0xff),(unsigned int)((ns.config().mac >> 8) & 0xff),(unsigned int)(ns.config().mac & 0xff)); - nj["mac"] = tmp; - nj["name"] = ns.config().name; - nj["status"] = nstatus; - nj["type"] = ntype; - nj["mtu"] = ns.config().mtu; - nj["dhcp"] = (bool)(ns.config().dhcp != 0); - nj["bridge"] = (bool)(ns.config().bridge != 0); - nj["broadcastEnabled"] = (bool)(ns.config().broadcastEnabled != 0); - nj["portError"] = ns.config().portError; - nj["netconfRevision"] = ns.config().netconfRevision; - nj["portDeviceName"] = ns.tap()->deviceName(); + OSUtils::ztsnprintf(tmp, sizeof(tmp), "%.16llx", ns.config().nwid); + nj["id"] = tmp; + nj["nwid"] = tmp; + OSUtils::ztsnprintf( + tmp, + sizeof(tmp), + "%.2x:%.2x:%.2x:%.2x:%.2x:%.2x", + (unsigned int)((ns.config().mac >> 40) & 0xff), + (unsigned int)((ns.config().mac >> 32) & 0xff), + (unsigned int)((ns.config().mac >> 24) & 0xff), + (unsigned int)((ns.config().mac >> 16) & 0xff), + (unsigned int)((ns.config().mac >> 8) & 0xff), + (unsigned int)(ns.config().mac & 0xff)); + nj["mac"] = tmp; + nj["name"] = ns.config().name; + nj["status"] = nstatus; + nj["type"] = ntype; + nj["mtu"] = ns.config().mtu; + nj["dhcp"] = (bool)(ns.config().dhcp != 0); + nj["bridge"] = (bool)(ns.config().bridge != 0); + nj["broadcastEnabled"] = (bool)(ns.config().broadcastEnabled != 0); + nj["portError"] = ns.config().portError; + nj["netconfRevision"] = ns.config().netconfRevision; + nj["portDeviceName"] = ns.tap()->deviceName(); - OneService::NetworkSettings localSettings = ns.settings(); + OneService::NetworkSettings localSettings = ns.settings(); - nj["allowManaged"] = localSettings.allowManaged; - nj["allowGlobal"] = localSettings.allowGlobal; - nj["allowDefault"] = localSettings.allowDefault; - nj["allowDNS"] = localSettings.allowDNS; + nj["allowManaged"] = localSettings.allowManaged; + nj["allowGlobal"] = localSettings.allowGlobal; + nj["allowDefault"] = localSettings.allowDefault; + nj["allowDNS"] = localSettings.allowDNS; - nlohmann::json aa = nlohmann::json::array(); - for(unsigned int i=0;i(&(ns.config().assignedAddresses[i]))->toString(tmp)); - } - nj["assignedAddresses"] = aa; + nlohmann::json aa = nlohmann::json::array(); + for (unsigned int i = 0; i < ns.config().assignedAddressCount; ++i) { + aa.push_back(reinterpret_cast(&(ns.config().assignedAddresses[i]))->toString(tmp)); + } + nj["assignedAddresses"] = aa; - nlohmann::json ra = nlohmann::json::array(); - for(unsigned int i=0;i(&(ns.config().routes[i].target))->toString(tmp); - if (ns.config().routes[i].via.ss_family == ns.config().routes[i].target.ss_family) - rj["via"] = reinterpret_cast(&(ns.config().routes[i].via))->toIpString(tmp); - else rj["via"] = nlohmann::json(); - rj["flags"] = (int)ns.config().routes[i].flags; - rj["metric"] = (int)ns.config().routes[i].metric; - ra.push_back(rj); - } - nj["routes"] = ra; + nlohmann::json ra = nlohmann::json::array(); + for (unsigned int i = 0; i < ns.config().routeCount; ++i) { + nlohmann::json rj; + rj["target"] = reinterpret_cast(&(ns.config().routes[i].target))->toString(tmp); + if (ns.config().routes[i].via.ss_family == ns.config().routes[i].target.ss_family) + rj["via"] = reinterpret_cast(&(ns.config().routes[i].via))->toIpString(tmp); + else + rj["via"] = nlohmann::json(); + rj["flags"] = (int)ns.config().routes[i].flags; + rj["metric"] = (int)ns.config().routes[i].metric; + ra.push_back(rj); + } + nj["routes"] = ra; - nlohmann::json mca = nlohmann::json::array(); - for(unsigned int i=0;i &bond, bool isTunneled) +static void _peerToJson(nlohmann::json& pj, const ZT_Peer* peer, SharedPtr& bond, bool isTunneled) { - char tmp[256]; + char tmp[256]; - const char *prole = ""; - switch(peer->role) { - case ZT_PEER_ROLE_LEAF: prole = "LEAF"; break; - case ZT_PEER_ROLE_MOON: prole = "MOON"; break; - case ZT_PEER_ROLE_PLANET: prole = "PLANET"; break; - } + const char* prole = ""; + switch (peer->role) { + case ZT_PEER_ROLE_LEAF: + prole = "LEAF"; + break; + case ZT_PEER_ROLE_MOON: + prole = "MOON"; + break; + case ZT_PEER_ROLE_PLANET: + prole = "PLANET"; + break; + } - OSUtils::ztsnprintf(tmp,sizeof(tmp),"%.10llx",peer->address); - pj["address"] = tmp; - pj["versionMajor"] = peer->versionMajor; - pj["versionMinor"] = peer->versionMinor; - pj["versionRev"] = peer->versionRev; - OSUtils::ztsnprintf(tmp,sizeof(tmp),"%d.%d.%d",peer->versionMajor,peer->versionMinor,peer->versionRev); - pj["version"] = tmp; - pj["latency"] = peer->latency; - pj["role"] = prole; - pj["isBonded"] = peer->isBonded; - pj["tunneled"] = isTunneled; - if (bond && peer->isBonded) { - pj["bondingPolicyCode"] = peer->bondingPolicy; - pj["bondingPolicyStr"] = Bond::getPolicyStrByCode(peer->bondingPolicy); - pj["numAliveLinks"] = peer->numAliveLinks; - pj["numTotalLinks"] = peer->numTotalLinks; - pj["failoverInterval"] = bond->getFailoverInterval(); - pj["downDelay"] = bond->getDownDelay(); - pj["upDelay"] = bond->getUpDelay(); - pj["packetsPerLink"] = bond->getPacketsPerLink(); - } + OSUtils::ztsnprintf(tmp, sizeof(tmp), "%.10llx", peer->address); + pj["address"] = tmp; + pj["versionMajor"] = peer->versionMajor; + pj["versionMinor"] = peer->versionMinor; + pj["versionRev"] = peer->versionRev; + OSUtils::ztsnprintf(tmp, sizeof(tmp), "%d.%d.%d", peer->versionMajor, peer->versionMinor, peer->versionRev); + pj["version"] = tmp; + pj["latency"] = peer->latency; + pj["role"] = prole; + pj["isBonded"] = peer->isBonded; + pj["tunneled"] = isTunneled; + if (bond && peer->isBonded) { + pj["bondingPolicyCode"] = peer->bondingPolicy; + pj["bondingPolicyStr"] = Bond::getPolicyStrByCode(peer->bondingPolicy); + pj["numAliveLinks"] = peer->numAliveLinks; + pj["numTotalLinks"] = peer->numTotalLinks; + pj["failoverInterval"] = bond->getFailoverInterval(); + pj["downDelay"] = bond->getDownDelay(); + pj["upDelay"] = bond->getUpDelay(); + pj["packetsPerLink"] = bond->getPacketsPerLink(); + } - nlohmann::json pa = nlohmann::json::array(); - for(unsigned int i=0;ipathCount;++i) { - int64_t lastSend = peer->paths[i].lastSend; - int64_t lastReceive = peer->paths[i].lastReceive; - nlohmann::json j; - j["address"] = reinterpret_cast(&(peer->paths[i].address))->toString(tmp); - j["lastSend"] = (lastSend < 0) ? 0 : lastSend; - j["lastReceive"] = (lastReceive < 0) ? 0 : lastReceive; - j["trustedPathId"] = peer->paths[i].trustedPathId; - j["active"] = (bool)(peer->paths[i].expired == 0); - j["expired"] = (bool)(peer->paths[i].expired != 0); - j["preferred"] = (bool)(peer->paths[i].preferred != 0); - j["localSocket"] = peer->paths[i].localSocket; - j["localPort"] = peer->paths[i].localPort; - if (bond && peer->isBonded) { - uint64_t now = OSUtils::now(); - j["ifname"] = std::string(peer->paths[i].ifname); - j["latencyMean"] = peer->paths[i].latencyMean; - j["latencyVariance"] = peer->paths[i].latencyVariance; - j["packetLossRatio"] = peer->paths[i].packetLossRatio; - j["packetErrorRatio"] = peer->paths[i].packetErrorRatio; - j["assignedFlowCount"] = peer->paths[i].assignedFlowCount; - j["lastInAge"] = (now - lastReceive); - j["lastOutAge"] = (now - lastSend); - j["bonded"] = peer->paths[i].bonded; - j["eligible"] = peer->paths[i].eligible; - j["givenLinkSpeed"] = peer->paths[i].linkSpeed; - j["relativeQuality"] = peer->paths[i].relativeQuality; - } - pa.push_back(j); - } - pj["paths"] = pa; + nlohmann::json pa = nlohmann::json::array(); + for (unsigned int i = 0; i < peer->pathCount; ++i) { + int64_t lastSend = peer->paths[i].lastSend; + int64_t lastReceive = peer->paths[i].lastReceive; + nlohmann::json j; + j["address"] = reinterpret_cast(&(peer->paths[i].address))->toString(tmp); + j["lastSend"] = (lastSend < 0) ? 0 : lastSend; + j["lastReceive"] = (lastReceive < 0) ? 0 : lastReceive; + j["trustedPathId"] = peer->paths[i].trustedPathId; + j["active"] = (bool)(peer->paths[i].expired == 0); + j["expired"] = (bool)(peer->paths[i].expired != 0); + j["preferred"] = (bool)(peer->paths[i].preferred != 0); + j["localSocket"] = peer->paths[i].localSocket; + j["localPort"] = peer->paths[i].localPort; + if (bond && peer->isBonded) { + uint64_t now = OSUtils::now(); + j["ifname"] = std::string(peer->paths[i].ifname); + j["latencyMean"] = peer->paths[i].latencyMean; + j["latencyVariance"] = peer->paths[i].latencyVariance; + j["packetLossRatio"] = peer->paths[i].packetLossRatio; + j["packetErrorRatio"] = peer->paths[i].packetErrorRatio; + j["assignedFlowCount"] = peer->paths[i].assignedFlowCount; + j["lastInAge"] = (now - lastReceive); + j["lastOutAge"] = (now - lastSend); + j["bonded"] = peer->paths[i].bonded; + j["eligible"] = peer->paths[i].eligible; + j["givenLinkSpeed"] = peer->paths[i].linkSpeed; + j["relativeQuality"] = peer->paths[i].relativeQuality; + } + pa.push_back(j); + } + pj["paths"] = pa; } -static void _moonToJson(nlohmann::json &mj,const World &world) +static void _moonToJson(nlohmann::json& mj, const World& world) { - char tmp[4096]; - OSUtils::ztsnprintf(tmp,sizeof(tmp),"%.16llx",world.id()); - mj["id"] = tmp; - mj["timestamp"] = world.timestamp(); - mj["signature"] = Utils::hex(world.signature().data,ZT_C25519_SIGNATURE_LEN,tmp); - mj["updatesMustBeSignedBy"] = Utils::hex(world.updatesMustBeSignedBy().data,ZT_C25519_PUBLIC_KEY_LEN,tmp); - nlohmann::json ra = nlohmann::json::array(); - for(std::vector::const_iterator r(world.roots().begin());r!=world.roots().end();++r) { - nlohmann::json rj; - rj["identity"] = r->identity.toString(false,tmp); - nlohmann::json eps = nlohmann::json::array(); - for(std::vector::const_iterator a(r->stableEndpoints.begin());a!=r->stableEndpoints.end();++a) - eps.push_back(a->toString(tmp)); - rj["stableEndpoints"] = eps; - ra.push_back(rj); - } - mj["roots"] = ra; - mj["waiting"] = false; + char tmp[4096]; + OSUtils::ztsnprintf(tmp, sizeof(tmp), "%.16llx", world.id()); + mj["id"] = tmp; + mj["timestamp"] = world.timestamp(); + mj["signature"] = Utils::hex(world.signature().data, ZT_ECC_SIGNATURE_LEN, tmp); + mj["updatesMustBeSignedBy"] = Utils::hex(world.updatesMustBeSignedBy().data, ZT_ECC_PUBLIC_KEY_SET_LEN, tmp); + nlohmann::json ra = nlohmann::json::array(); + for (std::vector::const_iterator r(world.roots().begin()); r != world.roots().end(); ++r) { + nlohmann::json rj; + rj["identity"] = r->identity.toString(false, tmp); + nlohmann::json eps = nlohmann::json::array(); + for (std::vector::const_iterator a(r->stableEndpoints.begin()); a != r->stableEndpoints.end(); ++a) + eps.push_back(a->toString(tmp)); + rj["stableEndpoints"] = eps; + ra.push_back(rj); + } + mj["roots"] = ra; + mj["waiting"] = false; } class OneServiceImpl; -static int SnodeVirtualNetworkConfigFunction(ZT_Node *node,void *uptr,void *tptr,uint64_t nwid,void **nuptr,enum ZT_VirtualNetworkConfigOperation op,const ZT_VirtualNetworkConfig *nwconf); -static void SnodeEventCallback(ZT_Node *node,void *uptr,void *tptr,enum ZT_Event event,const void *metaData); -static void SnodeStatePutFunction(ZT_Node *node,void *uptr,void *tptr,enum ZT_StateObjectType type,const uint64_t id[2],const void *data,int len); -static int SnodeStateGetFunction(ZT_Node *node,void *uptr,void *tptr,enum ZT_StateObjectType type,const uint64_t id[2],void *data,unsigned int maxlen); -static int SnodeWirePacketSendFunction(ZT_Node *node,void *uptr,void *tptr,int64_t localSocket,const struct sockaddr_storage *addr,const void *data,unsigned int len,unsigned int ttl); -static void SnodeVirtualNetworkFrameFunction(ZT_Node *node,void *uptr,void *tptr,uint64_t nwid,void **nuptr,uint64_t sourceMac,uint64_t destMac,unsigned int etherType,unsigned int vlanId,const void *data,unsigned int len); -static int SnodePathCheckFunction(ZT_Node *node,void *uptr,void *tptr,uint64_t ztaddr,int64_t localSocket,const struct sockaddr_storage *remoteAddr); -static int SnodePathLookupFunction(ZT_Node *node,void *uptr,void *tptr,uint64_t ztaddr,int family,struct sockaddr_storage *result); -static void StapFrameHandler(void *uptr,void *tptr,uint64_t nwid,const MAC &from,const MAC &to,unsigned int etherType,unsigned int vlanId,const void *data,unsigned int len); +static int SnodeVirtualNetworkConfigFunction(ZT_Node* node, void* uptr, void* tptr, uint64_t nwid, void** nuptr, enum ZT_VirtualNetworkConfigOperation op, const ZT_VirtualNetworkConfig* nwconf); +static void SnodeEventCallback(ZT_Node* node, void* uptr, void* tptr, enum ZT_Event event, const void* metaData); +static void SnodeStatePutFunction(ZT_Node* node, void* uptr, void* tptr, enum ZT_StateObjectType type, const uint64_t id[2], const void* data, int len); +static int SnodeStateGetFunction(ZT_Node* node, void* uptr, void* tptr, enum ZT_StateObjectType type, const uint64_t id[2], void* data, unsigned int maxlen); +static int SnodeWirePacketSendFunction(ZT_Node* node, void* uptr, void* tptr, int64_t localSocket, const struct sockaddr_storage* addr, const void* data, unsigned int len, unsigned int ttl); +static void SnodeVirtualNetworkFrameFunction(ZT_Node* node, void* uptr, void* tptr, uint64_t nwid, void** nuptr, uint64_t sourceMac, uint64_t destMac, unsigned int etherType, unsigned int vlanId, const void* data, unsigned int len); +static int SnodePathCheckFunction(ZT_Node* node, void* uptr, void* tptr, uint64_t ztaddr, int64_t localSocket, const struct sockaddr_storage* remoteAddr); +static int SnodePathLookupFunction(ZT_Node* node, void* uptr, void* tptr, uint64_t ztaddr, int family, struct sockaddr_storage* result); +static void StapFrameHandler(void* uptr, void* tptr, uint64_t nwid, const MAC& from, const MAC& to, unsigned int etherType, unsigned int vlanId, const void* data, unsigned int len); -static int ShttpOnMessageBegin(http_parser *parser); -static int ShttpOnUrl(http_parser *parser,const char *ptr,size_t length); +static int ShttpOnMessageBegin(http_parser* parser); +static int ShttpOnUrl(http_parser* parser, const char* ptr, size_t length); #if (HTTP_PARSER_VERSION_MAJOR >= 2) && (HTTP_PARSER_VERSION_MINOR >= 2) -static int ShttpOnStatus(http_parser *parser,const char *ptr,size_t length); +static int ShttpOnStatus(http_parser* parser, const char* ptr, size_t length); #else -static int ShttpOnStatus(http_parser *parser); +static int ShttpOnStatus(http_parser* parser); #endif -static int ShttpOnHeaderField(http_parser *parser,const char *ptr,size_t length); -static int ShttpOnValue(http_parser *parser,const char *ptr,size_t length); -static int ShttpOnHeadersComplete(http_parser *parser); -static int ShttpOnBody(http_parser *parser,const char *ptr,size_t length); -static int ShttpOnMessageComplete(http_parser *parser); +static int ShttpOnHeaderField(http_parser* parser, const char* ptr, size_t length); +static int ShttpOnValue(http_parser* parser, const char* ptr, size_t length); +static int ShttpOnHeadersComplete(http_parser* parser); +static int ShttpOnBody(http_parser* parser, const char* ptr, size_t length); +static int ShttpOnMessageComplete(http_parser* parser); #if (HTTP_PARSER_VERSION_MAJOR >= 2) && (HTTP_PARSER_VERSION_MINOR >= 1) -static const struct http_parser_settings HTTP_PARSER_SETTINGS = { - ShttpOnMessageBegin, - ShttpOnUrl, - ShttpOnStatus, - ShttpOnHeaderField, - ShttpOnValue, - ShttpOnHeadersComplete, - ShttpOnBody, - ShttpOnMessageComplete -}; +static const struct http_parser_settings HTTP_PARSER_SETTINGS = { ShttpOnMessageBegin, ShttpOnUrl, ShttpOnStatus, ShttpOnHeaderField, ShttpOnValue, ShttpOnHeadersComplete, ShttpOnBody, ShttpOnMessageComplete }; #else -static const struct http_parser_settings HTTP_PARSER_SETTINGS = { - ShttpOnMessageBegin, - ShttpOnUrl, - ShttpOnHeaderField, - ShttpOnValue, - ShttpOnHeadersComplete, - ShttpOnBody, - ShttpOnMessageComplete -}; +static const struct http_parser_settings HTTP_PARSER_SETTINGS = { ShttpOnMessageBegin, ShttpOnUrl, ShttpOnHeaderField, ShttpOnValue, ShttpOnHeadersComplete, ShttpOnBody, ShttpOnMessageComplete }; #endif /** * A TCP connection and related state and buffers */ -struct TcpConnection -{ - enum { - TCP_UNCATEGORIZED_INCOMING, // uncategorized incoming connection - TCP_HTTP_INCOMING, - TCP_HTTP_OUTGOING, - TCP_TUNNEL_OUTGOING // TUNNELED mode proxy outbound connection - } type; +struct TcpConnection { + enum { + TCP_UNCATEGORIZED_INCOMING, // uncategorized incoming connection + TCP_HTTP_INCOMING, + TCP_HTTP_OUTGOING, + TCP_TUNNEL_OUTGOING // TUNNELED mode proxy outbound connection + } type; - OneServiceImpl *parent; - PhySocket *sock; - InetAddress remoteAddr; - uint64_t lastReceive; + OneServiceImpl* parent; + PhySocket* sock; + InetAddress remoteAddr; + uint64_t lastReceive; - // Used for inbound HTTP connections - http_parser parser; - unsigned long messageSize; - std::string currentHeaderField; - std::string currentHeaderValue; - std::string url; - std::string status; - std::map< std::string,std::string > headers; + // Used for inbound HTTP connections + http_parser parser; + unsigned long messageSize; + std::string currentHeaderField; + std::string currentHeaderValue; + std::string url; + std::string status; + std::map headers; - std::string readq; - std::string writeq; - Mutex writeq_m; + std::string readq; + std::string writeq; + Mutex writeq_m; }; -struct PacketRecord -{ - uint64_t now; - int64_t sock; - struct sockaddr_storage from; - unsigned int size; - uint8_t data[ZT_MAX_MTU]; +struct PacketRecord { + uint64_t now; + int64_t sock; + struct sockaddr_storage from; + unsigned int size; + uint8_t data[ZT_MAX_MTU]; }; -class OneServiceImpl : public OneService -{ -public: - // begin member variables -------------------------------------------------- +class OneServiceImpl : public OneService { + public: + // begin member variables -------------------------------------------------- - const std::string _homePath; - std::string _authToken; - std::string _metricsToken; - std::string _controllerDbPath; - const std::string _networksPath; - const std::string _moonsPath; + const std::string _homePath; + std::string _authToken; + std::string _metricsToken; + std::string _controllerDbPath; + const std::string _networksPath; + const std::string _moonsPath; - EmbeddedNetworkController *_controller; - Phy _phy; - Node *_node; - SoftwareUpdater *_updater; - bool _updateAutoApply; + EmbeddedNetworkController* _controller; + Phy _phy; + Node* _node; + SoftwareUpdater* _updater; + bool _updateAutoApply; - httplib::Server _controlPlane; - httplib::Server _controlPlaneV6; - std::thread _serverThread; - std::thread _serverThreadV6; - bool _serverThreadRunning; - bool _serverThreadRunningV6; + httplib::Server _controlPlane; + httplib::Server _controlPlaneV6; + std::thread _serverThread; + std::thread _serverThreadV6; + bool _serverThreadRunning; + bool _serverThreadRunningV6; - BlockingQueue _rxPacketQueue; - std::vector _rxPacketVector; - std::vector _rxPacketThreads; - Mutex _rxPacketVector_m,_rxPacketThreads_m; - bool _multicoreEnabled; - bool _cpuPinningEnabled; - unsigned int _concurrency; + BlockingQueue _rxPacketQueue; + std::vector _rxPacketVector; + std::vector _rxPacketThreads; + Mutex _rxPacketVector_m, _rxPacketThreads_m; + bool _multicoreEnabled; + bool _cpuPinningEnabled; + unsigned int _concurrency; - bool _allowTcpFallbackRelay; - bool _forceTcpRelay; - bool _allowSecondaryPort; - bool _enableWebServer; + bool _allowTcpFallbackRelay; + bool _forceTcpRelay; + bool _allowSecondaryPort; + bool _enableWebServer; - unsigned int _primaryPort; - unsigned int _secondaryPort; - unsigned int _tertiaryPort; - volatile unsigned int _udpPortPickerCounter; + unsigned int _primaryPort; + unsigned int _secondaryPort; + unsigned int _tertiaryPort; + volatile unsigned int _udpPortPickerCounter; - // Local configuration and memo-ized information from it - json _localConfig; - Hashtable< uint64_t,std::vector > _v4Hints; - Hashtable< uint64_t,std::vector > _v6Hints; - Hashtable< uint64_t,std::vector > _v4Blacklists; - Hashtable< uint64_t,std::vector > _v6Blacklists; - std::vector< InetAddress > _globalV4Blacklist; - std::vector< InetAddress > _globalV6Blacklist; - std::vector< InetAddress > _allowManagementFrom; - std::vector< std::string > _interfacePrefixBlacklist; - Mutex _localConfig_m; + // Local configuration and memo-ized information from it + json _localConfig; + Hashtable > _v4Hints; + Hashtable > _v6Hints; + Hashtable > _v4Blacklists; + Hashtable > _v6Blacklists; + std::vector _globalV4Blacklist; + std::vector _globalV6Blacklist; + std::vector _allowManagementFrom; + std::vector _interfacePrefixBlacklist; + Mutex _localConfig_m; - std::vector explicitBind; + std::vector explicitBind; - /* - * To attempt to handle NAT/gateway craziness we use three local UDP ports: - * - * [0] is the normal/default port, usually 9993 - * [1] is a port derived from our ZeroTier address - * [2] is a port computed from the normal/default for use with uPnP/NAT-PMP mappings - * - * [2] exists because on some gateways trying to do regular NAT-t interferes - * destructively with uPnP port mapping behavior in very weird buggy ways. - * It's only used if uPnP/NAT-PMP is enabled in this build. - */ - unsigned int _ports[3]; - Binder _binder; + /* + * To attempt to handle NAT/gateway craziness we use three local UDP ports: + * + * [0] is the normal/default port, usually 9993 + * [1] is a port derived from our ZeroTier address + * [2] is a port computed from the normal/default for use with uPnP/NAT-PMP mappings + * + * [2] exists because on some gateways trying to do regular NAT-t interferes + * destructively with uPnP port mapping behavior in very weird buggy ways. + * It's only used if uPnP/NAT-PMP is enabled in this build. + */ + unsigned int _ports[3]; + Binder _binder; - // Time we last received a packet from a global address - uint64_t _lastDirectReceiveFromGlobal; + // Time we last received a packet from a global address + uint64_t _lastDirectReceiveFromGlobal; #ifdef ZT_TCP_FALLBACK_RELAY - InetAddress _fallbackRelayAddress; - uint64_t _lastSendToGlobalV4; + InetAddress _fallbackRelayAddress; + uint64_t _lastSendToGlobalV4; #endif - // Last potential sleep/wake event - uint64_t _lastRestart; + // Last potential sleep/wake event + uint64_t _lastRestart; - // Deadline for the next background task service function - volatile int64_t _nextBackgroundTaskDeadline; + // Deadline for the next background task service function + volatile int64_t _nextBackgroundTaskDeadline; - std::map _nets; - Mutex _nets_m; + std::map _nets; + Mutex _nets_m; - // Active TCP/IP connections - std::vector< TcpConnection * > _tcpConnections; - Mutex _tcpConnections_m; - TcpConnection *_tcpFallbackTunnel; + // Active TCP/IP connections + std::vector _tcpConnections; + Mutex _tcpConnections_m; + TcpConnection* _tcpFallbackTunnel; - // Termination status information - ReasonForTermination _termReason; - std::string _fatalErrorMessage; - Mutex _termReason_m; + // Termination status information + ReasonForTermination _termReason; + std::string _fatalErrorMessage; + Mutex _termReason_m; - // uPnP/NAT-PMP port mapper if enabled - bool _portMappingEnabled; // local.conf settings + // uPnP/NAT-PMP port mapper if enabled + bool _portMappingEnabled; // local.conf settings #ifdef ZT_USE_MINIUPNPC - PortMapper *_portMapper; + PortMapper* _portMapper; #endif - // HashiCorp Vault Settings + // HashiCorp Vault Settings #if ZT_VAULT_SUPPORT - bool _vaultEnabled; - std::string _vaultURL; - std::string _vaultToken; - std::string _vaultPath; // defaults to cubbyhole/zerotier/identity.secret for per-access key storage + bool _vaultEnabled; + std::string _vaultURL; + std::string _vaultToken; + std::string _vaultPath; // defaults to cubbyhole/zerotier/identity.secret for per-access key storage #endif - // Set to false to force service to stop - volatile bool _run; - Mutex _run_m; + // Set to false to force service to stop + volatile bool _run; + Mutex _run_m; - RedisConfig *_rc; - std::string _ssoRedirectURL; + RedisConfig* _rc; + std::string _ssoRedirectURL; - // end member variables ---------------------------------------------------- + // end member variables ---------------------------------------------------- - OneServiceImpl(const char *hp,unsigned int port) : - _homePath((hp) ? hp : ".") - ,_controllerDbPath(_homePath + ZT_PATH_SEPARATOR_S "controller.d") - ,_networksPath(_homePath + ZT_PATH_SEPARATOR_S "networks.d") - ,_moonsPath(_homePath + ZT_PATH_SEPARATOR_S "moons.d") - ,_controller((EmbeddedNetworkController *)0) - ,_phy(this,false,true) - ,_node((Node *)0) - ,_updater((SoftwareUpdater *)0) - ,_updateAutoApply(false) - ,_controlPlane() - ,_controlPlaneV6() - ,_serverThread() - ,_serverThreadV6() - ,_serverThreadRunning(false) - ,_serverThreadRunningV6(false) - ,_forceTcpRelay(false) - ,_primaryPort(port) - ,_udpPortPickerCounter(0) - ,_lastDirectReceiveFromGlobal(0) + OneServiceImpl(const char* hp, unsigned int port) + : _homePath((hp) ? hp : ".") + , _controllerDbPath(_homePath + ZT_PATH_SEPARATOR_S "controller.d") + , _networksPath(_homePath + ZT_PATH_SEPARATOR_S "networks.d") + , _moonsPath(_homePath + ZT_PATH_SEPARATOR_S "moons.d") + , _controller((EmbeddedNetworkController*)0) + , _phy(this, false, true) + , _node((Node*)0) + , _updater((SoftwareUpdater*)0) + , _updateAutoApply(false) + , _controlPlane() + , _controlPlaneV6() + , _serverThread() + , _serverThreadV6() + , _serverThreadRunning(false) + , _serverThreadRunningV6(false) + , _forceTcpRelay(false) + , _primaryPort(port) + , _udpPortPickerCounter(0) + , _lastDirectReceiveFromGlobal(0) #ifdef ZT_TCP_FALLBACK_RELAY - , _fallbackRelayAddress(ZT_TCP_FALLBACK_RELAY) - ,_lastSendToGlobalV4(0) + , _fallbackRelayAddress(ZT_TCP_FALLBACK_RELAY) + , _lastSendToGlobalV4(0) #endif - ,_lastRestart(0) - ,_nextBackgroundTaskDeadline(0) - ,_tcpFallbackTunnel((TcpConnection *)0) - ,_termReason(ONE_STILL_RUNNING) - ,_portMappingEnabled(true) + , _lastRestart(0) + , _nextBackgroundTaskDeadline(0) + , _tcpFallbackTunnel((TcpConnection*)0) + , _termReason(ONE_STILL_RUNNING) + , _portMappingEnabled(true) #ifdef ZT_USE_MINIUPNPC - ,_portMapper((PortMapper *)0) + , _portMapper((PortMapper*)0) #endif #ifdef ZT_VAULT_SUPPORT - ,_vaultEnabled(false) - ,_vaultURL() - ,_vaultToken() - ,_vaultPath("cubbyhole/zerotier") + , _vaultEnabled(false) + , _vaultURL() + , _vaultToken() + , _vaultPath("cubbyhole/zerotier") #endif - ,_run(true) - ,_rc(NULL) - ,_ssoRedirectURL() - { - _ports[0] = 0; - _ports[1] = 0; - _ports[2] = 0; + , _run(true) + , _rc(NULL) + , _ssoRedirectURL() + { + _ports[0] = 0; + _ports[1] = 0; + _ports[2] = 0; - prometheus::simpleapi::saver.set_registry(prometheus::simpleapi::registry_ptr); - prometheus::simpleapi::saver.set_delay(std::chrono::seconds(5)); - prometheus::simpleapi::saver.set_out_file(_homePath + ZT_PATH_SEPARATOR + "metrics.prom"); + prometheus::simpleapi::saver.set_registry(prometheus::simpleapi::registry_ptr); + prometheus::simpleapi::saver.set_delay(std::chrono::seconds(5)); + prometheus::simpleapi::saver.set_out_file(_homePath + ZT_PATH_SEPARATOR + "metrics.prom"); #if ZT_VAULT_SUPPORT - curl_global_init(CURL_GLOBAL_DEFAULT); + curl_global_init(CURL_GLOBAL_DEFAULT); #endif - } + } - virtual ~OneServiceImpl() - { + virtual ~OneServiceImpl() + { #ifdef __WINDOWS__ - WinFWHelper::removeICMPRules(); + WinFWHelper::removeICMPRules(); #endif - _rxPacketQueue.stop(); - _rxPacketThreads_m.lock(); - for(auto t=_rxPacketThreads.begin();t!=_rxPacketThreads.end();++t) { - t->join(); - } - _rxPacketThreads_m.unlock(); - _binder.closeAll(_phy); + _rxPacketQueue.stop(); + _rxPacketThreads_m.lock(); + for (auto t = _rxPacketThreads.begin(); t != _rxPacketThreads.end(); ++t) { + t->join(); + } + _rxPacketThreads_m.unlock(); + _binder.closeAll(_phy); #if ZT_VAULT_SUPPORT - curl_global_cleanup(); + curl_global_cleanup(); #endif - _controlPlane.stop(); - if (_serverThreadRunning) { - _serverThread.join(); - } - _controlPlaneV6.stop(); - if (_serverThreadRunningV6) { - _serverThreadV6.join(); - } - _rxPacketVector_m.lock(); - while (!_rxPacketVector.empty()) { - delete _rxPacketVector.back(); - _rxPacketVector.pop_back(); - } - _rxPacketVector_m.unlock(); - + _controlPlane.stop(); + if (_serverThreadRunning) { + _serverThread.join(); + } + _controlPlaneV6.stop(); + if (_serverThreadRunningV6) { + _serverThreadV6.join(); + } + _rxPacketVector_m.lock(); + while (! _rxPacketVector.empty()) { + delete _rxPacketVector.back(); + _rxPacketVector.pop_back(); + } + _rxPacketVector_m.unlock(); #ifdef ZT_USE_MINIUPNPC - delete _portMapper; + delete _portMapper; #endif - delete _controller; - delete _rc; - } + delete _controller; + delete _rc; + } - void setUpMultithreading() - { + void setUpMultithreading() + { #if defined(__APPLE__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__WINDOWS__) - return; + return; #endif - _node->initMultithreading(_concurrency, _cpuPinningEnabled); - bool pinning = _cpuPinningEnabled; - } + _node->initMultithreading(_concurrency, _cpuPinningEnabled); + bool pinning = _cpuPinningEnabled; + } - virtual ReasonForTermination run() - { - try { - { - const std::string authTokenPath(_homePath + ZT_PATH_SEPARATOR_S "authtoken.secret"); - if (!OSUtils::readFile(authTokenPath.c_str(),_authToken)) { - unsigned char foo[24]; - Utils::getSecureRandom(foo,sizeof(foo)); - _authToken = ""; - for(unsigned int i=0;iaddress(),_ports[2]); - _portMapper = new PortMapper(_ports[2],uniqueName); - } - } + if (_ports[2]) { + char uniqueName[64]; + OSUtils::ztsnprintf(uniqueName, sizeof(uniqueName), "ZeroTier/%.10llx@%u", _node->address(), _ports[2]); + _portMapper = new PortMapper(_ports[2], uniqueName); + } + } #endif - // Delete legacy iddb.d if present (cleanup) - OSUtils::rmDashRf((_homePath + ZT_PATH_SEPARATOR_S "iddb.d").c_str()); + // Delete legacy iddb.d if present (cleanup) + OSUtils::rmDashRf((_homePath + ZT_PATH_SEPARATOR_S "iddb.d").c_str()); - // Network controller is now enabled by default for desktop and server - _controller = new EmbeddedNetworkController(_node,_homePath.c_str(),_controllerDbPath.c_str(),_ports[0], _rc); - if (!_ssoRedirectURL.empty()) { - _controller->setSSORedirectURL(_ssoRedirectURL); - } - _node->setNetconfMaster((void *)_controller); + // Network controller is now enabled by default for desktop and server + _controller = new EmbeddedNetworkController(_node, _homePath.c_str(), _controllerDbPath.c_str(), _ports[0], _rc); + if (! _ssoRedirectURL.empty()) { + _controller->setSSORedirectURL(_ssoRedirectURL); + } + _node->setNetconfMaster((void*)_controller); - startHTTPControlPlane(); + startHTTPControlPlane(); - // Join existing networks in networks.d - { - std::vector networksDotD(OSUtils::listDirectory((_homePath + ZT_PATH_SEPARATOR_S "networks.d").c_str())); - for(std::vector::iterator f(networksDotD.begin());f!=networksDotD.end();++f) { - std::size_t dot = f->find_last_of('.'); - if ((dot == 16)&&(f->substr(16) == ".conf")) - _node->join(Utils::hexStrToU64(f->substr(0,dot).c_str()),(void *)0,(void *)0); - } - } + // Join existing networks in networks.d + { + std::vector networksDotD(OSUtils::listDirectory((_homePath + ZT_PATH_SEPARATOR_S "networks.d").c_str())); + for (std::vector::iterator f(networksDotD.begin()); f != networksDotD.end(); ++f) { + std::size_t dot = f->find_last_of('.'); + if ((dot == 16) && (f->substr(16) == ".conf")) + _node->join(Utils::hexStrToU64(f->substr(0, dot).c_str()), (void*)0, (void*)0); + } + } - // Orbit existing moons in moons.d - { - std::vector moonsDotD(OSUtils::listDirectory((_homePath + ZT_PATH_SEPARATOR_S "moons.d").c_str())); - for(std::vector::iterator f(moonsDotD.begin());f!=moonsDotD.end();++f) { - std::size_t dot = f->find_last_of('.'); - if ((dot == 16)&&(f->substr(16) == ".moon")) - _node->orbit((void *)0,Utils::hexStrToU64(f->substr(0,dot).c_str()),0); - } - } + // Orbit existing moons in moons.d + { + std::vector moonsDotD(OSUtils::listDirectory((_homePath + ZT_PATH_SEPARATOR_S "moons.d").c_str())); + for (std::vector::iterator f(moonsDotD.begin()); f != moonsDotD.end(); ++f) { + std::size_t dot = f->find_last_of('.'); + if ((dot == 16) && (f->substr(16) == ".moon")) + _node->orbit((void*)0, Utils::hexStrToU64(f->substr(0, dot).c_str()), 0); + } + } - // Main I/O loop - _nextBackgroundTaskDeadline = 0; - int64_t clockShouldBe = OSUtils::now(); - _lastRestart = clockShouldBe; - int64_t lastTapMulticastGroupCheck = 0; - int64_t lastBindRefresh = 0; - int64_t lastUpdateCheck = clockShouldBe; - int64_t lastCleanedPeersDb = 0; - int64_t lastLocalConfFileCheck = OSUtils::now(); - int64_t lastOnline = lastLocalConfFileCheck; - for(;;) { - _run_m.lock(); - if (!_run) { - _run_m.unlock(); - _termReason_m.lock(); - _termReason = ONE_NORMAL_TERMINATION; - _termReason_m.unlock(); - break; - } else { - _run_m.unlock(); - } + // Main I/O loop + _nextBackgroundTaskDeadline = 0; + int64_t clockShouldBe = OSUtils::now(); + _lastRestart = clockShouldBe; + int64_t lastTapMulticastGroupCheck = 0; + int64_t lastBindRefresh = 0; + int64_t lastUpdateCheck = clockShouldBe; + int64_t lastCleanedPeersDb = 0; + int64_t lastLocalConfFileCheck = OSUtils::now(); + int64_t lastOnline = lastLocalConfFileCheck; + for (;;) { + _run_m.lock(); + if (! _run) { + _run_m.unlock(); + _termReason_m.lock(); + _termReason = ONE_NORMAL_TERMINATION; + _termReason_m.unlock(); + break; + } + else { + _run_m.unlock(); + } - const int64_t now = OSUtils::now(); + const int64_t now = OSUtils::now(); - // Attempt to detect sleep/wake events by detecting delay overruns - bool restarted = false; - if ((now > clockShouldBe)&&((now - clockShouldBe) > 10000)) { - _lastRestart = now; - restarted = true; - } + // Attempt to detect sleep/wake events by detecting delay overruns + bool restarted = false; + if ((now > clockShouldBe) && ((now - clockShouldBe) > 10000)) { + _lastRestart = now; + restarted = true; + } - // Check for updates (if enabled) - if ((_updater)&&((now - lastUpdateCheck) > 10000)) { - lastUpdateCheck = now; - if (_updater->check(now) && _updateAutoApply) - _updater->apply(); - } + // Check for updates (if enabled) + if ((_updater) && ((now - lastUpdateCheck) > 10000)) { + lastUpdateCheck = now; + if (_updater->check(now) && _updateAutoApply) + _updater->apply(); + } - // Reload local.conf if anything changed recently - if ((now - lastLocalConfFileCheck) >= ZT_LOCAL_CONF_FILE_CHECK_INTERVAL) { - lastLocalConfFileCheck = now; - struct stat result; - if(stat((_homePath + ZT_PATH_SEPARATOR_S "local.conf").c_str(), &result)==0) { - int64_t mod_time = result.st_mtime * 1000; - if ((now - mod_time) <= ZT_LOCAL_CONF_FILE_CHECK_INTERVAL) { - readLocalSettings(); - applyLocalConfig(); - } - } - } + // Reload local.conf if anything changed recently + if ((now - lastLocalConfFileCheck) >= ZT_LOCAL_CONF_FILE_CHECK_INTERVAL) { + lastLocalConfFileCheck = now; + struct stat result; + if (stat((_homePath + ZT_PATH_SEPARATOR_S "local.conf").c_str(), &result) == 0) { + int64_t mod_time = result.st_mtime * 1000; + if ((now - mod_time) <= ZT_LOCAL_CONF_FILE_CHECK_INTERVAL) { + readLocalSettings(); + applyLocalConfig(); + } + } + } - // Refresh bindings in case device's interfaces have changed, and also sync routes to update any shadow routes (e.g. shadow default) - if (((now - lastBindRefresh) >= (_node->bondController()->inUse() ? ZT_BINDER_REFRESH_PERIOD / 4 : ZT_BINDER_REFRESH_PERIOD))||restarted) { - // If secondary port is not configured to a constant value and we've been offline for a while, - // bind a new secondary port. This is a workaround for a "coma" issue caused by buggy NATs that stop - // working on one port after a while. - if (_secondaryPort == 0) { - if (_node->online()) { - lastOnline = now; - } - else if (now - lastOnline > (ZT_PEER_PING_PERIOD * 2) || restarted) { - lastOnline = now; // don't keep changing the port before we have a chance to connect - _ports[1] = _getRandomPort(); + // Refresh bindings in case device's interfaces have changed, and also sync routes to update any shadow routes (e.g. shadow default) + if (((now - lastBindRefresh) >= (_node->bondController()->inUse() ? ZT_BINDER_REFRESH_PERIOD / 4 : ZT_BINDER_REFRESH_PERIOD)) || restarted) { + // If secondary port is not configured to a constant value and we've been offline for a while, + // bind a new secondary port. This is a workaround for a "coma" issue caused by buggy NATs that stop + // working on one port after a while. + if (_secondaryPort == 0) { + if (_node->online()) { + lastOnline = now; + } + else if (now - lastOnline > (ZT_PEER_PING_PERIOD * 2) || restarted) { + lastOnline = now; // don't keep changing the port before we have a chance to connect + _ports[1] = _getRandomPort(); -#if ZT_DEBUG==1 - fprintf(stderr, "Randomized secondary port. Now it's %d\n", _ports[1]); +#if ZT_DEBUG == 1 + fprintf(stderr, "Randomized secondary port. Now it's %d\n", _ports[1]); #endif - } - } + } + } - unsigned int p[3]; - unsigned int pc = 0; - for(int i=0;i<3;++i) { - if (_ports[i]) - p[pc++] = _ports[i]; - } - if (!_forceTcpRelay) { - // Only bother binding UDP ports if we aren't forcing TCP-relay mode - _binder.refresh(_phy,p,pc,explicitBind,*this); - } + unsigned int p[3]; + unsigned int pc = 0; + for (int i = 0; i < 3; ++i) { + if (_ports[i]) + p[pc++] = _ports[i]; + } + if (! _forceTcpRelay) { + // Only bother binding UDP ports if we aren't forcing TCP-relay mode + _binder.refresh(_phy, p, pc, explicitBind, *this); + } - lastBindRefresh = now; + lastBindRefresh = now; - // Sync information about physical network interfaces - _node->clearLocalInterfaceAddresses(); + // Sync information about physical network interfaces + _node->clearLocalInterfaceAddresses(); #ifdef ZT_USE_MINIUPNPC - if (_portMapper) { - std::vector mappedAddresses(_portMapper->get()); - for(std::vector::const_iterator ext(mappedAddresses.begin());ext!=mappedAddresses.end();++ext) - _node->addLocalInterfaceAddress(reinterpret_cast(&(*ext))); - } + if (_portMapper) { + std::vector mappedAddresses(_portMapper->get()); + for (std::vector::const_iterator ext(mappedAddresses.begin()); ext != mappedAddresses.end(); ++ext) + _node->addLocalInterfaceAddress(reinterpret_cast(&(*ext))); + } #endif - std::vector boundAddrs(_binder.allBoundLocalInterfaceAddresses()); - for(std::vector::const_iterator i(boundAddrs.begin());i!=boundAddrs.end();++i) { - _node->addLocalInterfaceAddress(reinterpret_cast(&(*i))); - } + std::vector boundAddrs(_binder.allBoundLocalInterfaceAddresses()); + for (std::vector::const_iterator i(boundAddrs.begin()); i != boundAddrs.end(); ++i) { + _node->addLocalInterfaceAddress(reinterpret_cast(&(*i))); + } - { - Mutex::Lock _l(_nets_m); - for(std::map::iterator n(_nets.begin());n!=_nets.end();++n) { - if (n->second.tap()) - syncManagedStuff(n->second,false,true,false); - } - } - } + { + Mutex::Lock _l(_nets_m); + for (std::map::iterator n(_nets.begin()); n != _nets.end(); ++n) { + if (n->second.tap()) + syncManagedStuff(n->second, false, true, false); + } + } + } - // Run background task processor in core if it's time to do so - int64_t dl = _nextBackgroundTaskDeadline; - if (dl <= now) { - _node->processBackgroundTasks((void *)0,now,&_nextBackgroundTaskDeadline); - dl = _nextBackgroundTaskDeadline; - } + // Run background task processor in core if it's time to do so + int64_t dl = _nextBackgroundTaskDeadline; + if (dl <= now) { + _node->processBackgroundTasks((void*)0, now, &_nextBackgroundTaskDeadline); + dl = _nextBackgroundTaskDeadline; + } - // Close TCP fallback tunnel if we have direct UDP - if (!_forceTcpRelay && (_tcpFallbackTunnel) && ((now - _lastDirectReceiveFromGlobal) < (ZT_TCP_FALLBACK_AFTER / 2))) { - _phy.close(_tcpFallbackTunnel->sock); - } + // Close TCP fallback tunnel if we have direct UDP + if (! _forceTcpRelay && (_tcpFallbackTunnel) && ((now - _lastDirectReceiveFromGlobal) < (ZT_TCP_FALLBACK_AFTER / 2))) { + _phy.close(_tcpFallbackTunnel->sock); + } - // Sync multicast group memberships - if ((now - lastTapMulticastGroupCheck) >= ZT_TAP_CHECK_MULTICAST_INTERVAL) { - lastTapMulticastGroupCheck = now; - std::vector< std::pair< uint64_t,std::pair< std::vector,std::vector > > > mgChanges; - { - Mutex::Lock _l(_nets_m); - mgChanges.reserve(_nets.size() + 1); - for(std::map::const_iterator n(_nets.begin());n!=_nets.end();++n) { - if (n->second.tap()) { - mgChanges.push_back(std::pair< uint64_t,std::pair< std::vector,std::vector > >(n->first,std::pair< std::vector,std::vector >())); - n->second.tap()->scanMulticastGroups(mgChanges.back().second.first,mgChanges.back().second.second); - } - } - } - for(std::vector< std::pair< uint64_t,std::pair< std::vector,std::vector > > >::iterator c(mgChanges.begin());c!=mgChanges.end();++c) { - for(std::vector::iterator m(c->second.first.begin());m!=c->second.first.end();++m) - _node->multicastSubscribe((void *)0,c->first,m->mac().toInt(),m->adi()); - for(std::vector::iterator m(c->second.second.begin());m!=c->second.second.end();++m) - _node->multicastUnsubscribe(c->first,m->mac().toInt(),m->adi()); - } - } + // Sync multicast group memberships + if ((now - lastTapMulticastGroupCheck) >= ZT_TAP_CHECK_MULTICAST_INTERVAL) { + lastTapMulticastGroupCheck = now; + std::vector, std::vector > > > mgChanges; + { + Mutex::Lock _l(_nets_m); + mgChanges.reserve(_nets.size() + 1); + for (std::map::const_iterator n(_nets.begin()); n != _nets.end(); ++n) { + if (n->second.tap()) { + mgChanges.push_back(std::pair, std::vector > >(n->first, std::pair, std::vector >())); + n->second.tap()->scanMulticastGroups(mgChanges.back().second.first, mgChanges.back().second.second); + } + } + } + for (std::vector, std::vector > > >::iterator c(mgChanges.begin()); c != mgChanges.end(); ++c) { + for (std::vector::iterator m(c->second.first.begin()); m != c->second.first.end(); ++m) + _node->multicastSubscribe((void*)0, c->first, m->mac().toInt(), m->adi()); + for (std::vector::iterator m(c->second.second.begin()); m != c->second.second.end(); ++m) + _node->multicastUnsubscribe(c->first, m->mac().toInt(), m->adi()); + } + } - // Clean peers.d periodically - if ((now - lastCleanedPeersDb) >= 3600000) { - lastCleanedPeersDb = now; - OSUtils::cleanDirectory((_homePath + ZT_PATH_SEPARATOR_S "peers.d").c_str(),now - 2592000000LL); // delete older than 30 days - } + // Clean peers.d periodically + if ((now - lastCleanedPeersDb) >= 3600000) { + lastCleanedPeersDb = now; + OSUtils::cleanDirectory((_homePath + ZT_PATH_SEPARATOR_S "peers.d").c_str(), now - 2592000000LL); // delete older than 30 days + } - const unsigned long delay = (dl > now) ? (unsigned long)(dl - now) : 500; - clockShouldBe = now + (int64_t)delay; - _phy.poll(delay); + const unsigned long delay = (dl > now) ? (unsigned long)(dl - now) : 500; + clockShouldBe = now + (int64_t)delay; + _phy.poll(delay); + } + } + catch (std::exception& e) { + Mutex::Lock _l(_termReason_m); + _termReason = ONE_UNRECOVERABLE_ERROR; + _fatalErrorMessage = std::string("unexpected exception in main thread: ") + e.what(); + } + catch (int e) { + Mutex::Lock _l(_termReason_m); + _termReason = ONE_UNRECOVERABLE_ERROR; + switch (e) { + case ZT_EXCEPTION_OUT_OF_BOUNDS: { + _fatalErrorMessage = "out of bounds exception"; + break; + } + case ZT_EXCEPTION_OUT_OF_MEMORY: { + _fatalErrorMessage = "out of memory"; + break; + } + case ZT_EXCEPTION_PRIVATE_KEY_REQUIRED: { + _fatalErrorMessage = "private key required"; + break; + } + case ZT_EXCEPTION_INVALID_ARGUMENT: { + _fatalErrorMessage = "invalid argument"; + break; + } + case ZT_EXCEPTION_INVALID_IDENTITY: { + _fatalErrorMessage = "invalid identity loaded from disk. Please remove identity.public and identity.secret from " + _homePath + " and try again"; + break; + } + case ZT_EXCEPTION_INVALID_SERIALIZED_DATA_INVALID_TYPE: { + _fatalErrorMessage = "invalid serialized data: invalid type"; + break; + } + case ZT_EXCEPTION_INVALID_SERIALIZED_DATA_OVERFLOW: { + _fatalErrorMessage = "invalid serialized data: overflow"; + break; + } + case ZT_EXCEPTION_INVALID_SERIALIZED_DATA_INVALID_CRYPTOGRAPHIC_TOKEN: { + _fatalErrorMessage = "invalid serialized data: invalid cryptographic token"; + break; + } + case ZT_EXCEPTION_INVALID_SERIALIZED_DATA_BAD_ENCODING: { + _fatalErrorMessage = "invalid serialized data: bad encoding"; + break; + } + default: { + _fatalErrorMessage = "unexpected exception code: " + std::to_string(e); + break; + } + } + } + catch (...) { + Mutex::Lock _l(_termReason_m); + _termReason = ONE_UNRECOVERABLE_ERROR; + _fatalErrorMessage = "unexpected exception in main thread: unknown exception"; + } + try { + Mutex::Lock _l(_tcpConnections_m); + while (! _tcpConnections.empty()) + _phy.close((*_tcpConnections.begin())->sock); + } + catch (...) { + } + { + Mutex::Lock _l(_nets_m); + _nets.clear(); + } - } - } catch (std::exception &e) { - Mutex::Lock _l(_termReason_m); - _termReason = ONE_UNRECOVERABLE_ERROR; - _fatalErrorMessage = std::string("unexpected exception in main thread: ")+e.what(); - } catch (int e) { - Mutex::Lock _l(_termReason_m); - _termReason = ONE_UNRECOVERABLE_ERROR; - switch (e) { - case ZT_EXCEPTION_OUT_OF_BOUNDS: { - _fatalErrorMessage = "out of bounds exception"; - break; - } - case ZT_EXCEPTION_OUT_OF_MEMORY: { - _fatalErrorMessage = "out of memory"; - break; - } - case ZT_EXCEPTION_PRIVATE_KEY_REQUIRED: { - _fatalErrorMessage = "private key required"; - break; - } - case ZT_EXCEPTION_INVALID_ARGUMENT: { - _fatalErrorMessage = "invalid argument"; - break; - } - case ZT_EXCEPTION_INVALID_IDENTITY: { - _fatalErrorMessage = "invalid identity loaded from disk. Please remove identity.public and identity.secret from " + _homePath + " and try again"; - break; - } - case ZT_EXCEPTION_INVALID_SERIALIZED_DATA_INVALID_TYPE: { - _fatalErrorMessage = "invalid serialized data: invalid type"; - break; - } - case ZT_EXCEPTION_INVALID_SERIALIZED_DATA_OVERFLOW: { - _fatalErrorMessage = "invalid serialized data: overflow"; - break; - } - case ZT_EXCEPTION_INVALID_SERIALIZED_DATA_INVALID_CRYPTOGRAPHIC_TOKEN: { - _fatalErrorMessage = "invalid serialized data: invalid cryptographic token"; - break; - } - case ZT_EXCEPTION_INVALID_SERIALIZED_DATA_BAD_ENCODING: { - _fatalErrorMessage = "invalid serialized data: bad encoding"; - break; - } - default: { - _fatalErrorMessage = "unexpected exception code: " + std::to_string(e); - break; - } - } - } catch ( ... ) { - Mutex::Lock _l(_termReason_m); - _termReason = ONE_UNRECOVERABLE_ERROR; - _fatalErrorMessage = "unexpected exception in main thread: unknown exception"; - } + delete _updater; + _updater = (SoftwareUpdater*)0; + delete _node; + _node = (Node*)0; - try { - Mutex::Lock _l(_tcpConnections_m); - while (!_tcpConnections.empty()) - _phy.close((*_tcpConnections.begin())->sock); - } catch ( ... ) {} + return _termReason; + } - { - Mutex::Lock _l(_nets_m); - _nets.clear(); - } + void readLocalSettings() + { + // Read local configuration + std::map ppc; - delete _updater; - _updater = (SoftwareUpdater *)0; - delete _node; - _node = (Node *)0; + // LEGACY: support old "trustedpaths" flat file + FILE* trustpaths = fopen((_homePath + ZT_PATH_SEPARATOR_S "trustedpaths").c_str(), "r"); + if (trustpaths) { + fprintf(stderr, "WARNING: 'trustedpaths' flat file format is deprecated in favor of path definitions in local.conf" ZT_EOL_S); + char buf[1024]; + while (fgets(buf, sizeof(buf), trustpaths)) { + int fno = 0; + char* saveptr = (char*)0; + uint64_t trustedPathId = 0; + InetAddress trustedPathNetwork; + for (char* f = Utils::stok(buf, "=\r\n \t", &saveptr); (f); f = Utils::stok((char*)0, "=\r\n \t", &saveptr)) { + if (fno == 0) { + trustedPathId = Utils::hexStrToU64(f); + } + else if (fno == 1) { + trustedPathNetwork = InetAddress(f); + } + else + break; + ++fno; + } + if ((trustedPathId != 0) && ((trustedPathNetwork.ss_family == AF_INET) || (trustedPathNetwork.ss_family == AF_INET6)) && (trustedPathNetwork.netmaskBits() > 0)) { + ppc[trustedPathNetwork].trustedPathId = trustedPathId; + ppc[trustedPathNetwork].mtu = 0; // use default + } + } + fclose(trustpaths); + } - return _termReason; - } + // Read local config file + Mutex::Lock _l2(_localConfig_m); + std::string lcbuf; + if (OSUtils::readFile((_homePath + ZT_PATH_SEPARATOR_S "local.conf").c_str(), lcbuf)) { + if (lcbuf.length() > 0) { + try { + _localConfig = OSUtils::jsonParse(lcbuf); + if (! _localConfig.is_object()) { + fprintf(stderr, "ERROR: unable to parse local.conf (root element is not a JSON object)" ZT_EOL_S); + exit(1); + } + } + catch (...) { + fprintf(stderr, "ERROR: unable to parse local.conf (invalid JSON)" ZT_EOL_S); + exit(1); + } + } + } - void readLocalSettings() - { - // Read local configuration - std::map ppc; + // Make a copy so lookups don't modify in place; + json lc(_localConfig); - // LEGACY: support old "trustedpaths" flat file - FILE *trustpaths = fopen((_homePath + ZT_PATH_SEPARATOR_S "trustedpaths").c_str(),"r"); - if (trustpaths) { - fprintf(stderr,"WARNING: 'trustedpaths' flat file format is deprecated in favor of path definitions in local.conf" ZT_EOL_S); - char buf[1024]; - while (fgets(buf,sizeof(buf),trustpaths)) { - int fno = 0; - char *saveptr = (char *)0; - uint64_t trustedPathId = 0; - InetAddress trustedPathNetwork; - for(char *f=Utils::stok(buf,"=\r\n \t",&saveptr);(f);f=Utils::stok((char *)0,"=\r\n \t",&saveptr)) { - if (fno == 0) { - trustedPathId = Utils::hexStrToU64(f); - } else if (fno == 1) { - trustedPathNetwork = InetAddress(f); - } else break; - ++fno; - } - if ( (trustedPathId != 0) && ((trustedPathNetwork.ss_family == AF_INET)||(trustedPathNetwork.ss_family == AF_INET6)) && (trustedPathNetwork.netmaskBits() > 0) ) { - ppc[trustedPathNetwork].trustedPathId = trustedPathId; - ppc[trustedPathNetwork].mtu = 0; // use default - } - } - fclose(trustpaths); - } + // Get any trusted paths in local.conf (we'll parse the rest of physical[] elsewhere) + json& physical = lc["physical"]; + if (physical.is_object()) { + for (json::iterator phy(physical.begin()); phy != physical.end(); ++phy) { + InetAddress net(OSUtils::jsonString(phy.key(), "").c_str()); + if (net) { + if (phy.value().is_object()) { + uint64_t tpid; + if ((tpid = OSUtils::jsonInt(phy.value()["trustedPathId"], 0ULL)) != 0ULL) { + if ((net.ss_family == AF_INET) || (net.ss_family == AF_INET6)) + ppc[net].trustedPathId = tpid; + } + ppc[net].mtu = (int)OSUtils::jsonInt(phy.value()["mtu"], 0ULL); // 0 means use default + } + } + } + } - // Read local config file - Mutex::Lock _l2(_localConfig_m); - std::string lcbuf; - if (OSUtils::readFile((_homePath + ZT_PATH_SEPARATOR_S "local.conf").c_str(),lcbuf)) { - if (lcbuf.length() > 0) { - try { - _localConfig = OSUtils::jsonParse(lcbuf); - if (!_localConfig.is_object()) { - fprintf(stderr,"ERROR: unable to parse local.conf (root element is not a JSON object)" ZT_EOL_S); - exit(1); - } - } catch ( ... ) { - fprintf(stderr,"ERROR: unable to parse local.conf (invalid JSON)" ZT_EOL_S); - exit(1); - } - } - } + json& settings = lc["settings"]; + if (settings.is_object()) { + // Allow controller DB path to be put somewhere else + const std::string cdbp(OSUtils::jsonString(settings["controllerDbPath"], "")); + if (cdbp.length() > 0) + _controllerDbPath = cdbp; - // Make a copy so lookups don't modify in place; - json lc(_localConfig); - - // Get any trusted paths in local.conf (we'll parse the rest of physical[] elsewhere) - json &physical = lc["physical"]; - if (physical.is_object()) { - for(json::iterator phy(physical.begin());phy!=physical.end();++phy) { - InetAddress net(OSUtils::jsonString(phy.key(),"").c_str()); - if (net) { - if (phy.value().is_object()) { - uint64_t tpid; - if ((tpid = OSUtils::jsonInt(phy.value()["trustedPathId"],0ULL)) != 0ULL) { - if ((net.ss_family == AF_INET)||(net.ss_family == AF_INET6)) - ppc[net].trustedPathId = tpid; - } - ppc[net].mtu = (int)OSUtils::jsonInt(phy.value()["mtu"],0ULL); // 0 means use default - } - } - } - } - - json &settings = lc["settings"]; - if (settings.is_object()) { - // Allow controller DB path to be put somewhere else - const std::string cdbp(OSUtils::jsonString(settings["controllerDbPath"],"")); - if (cdbp.length() > 0) - _controllerDbPath = cdbp; - - _ssoRedirectURL = OSUtils::jsonString(settings["ssoRedirectURL"], ""); + _ssoRedirectURL = OSUtils::jsonString(settings["ssoRedirectURL"], ""); #ifdef ZT_CONTROLLER_USE_LIBPQ - // TODO: Redis config - json &redis = settings["redis"]; - if (redis.is_object() && _rc == NULL) { - _rc = new RedisConfig; - _rc->hostname = OSUtils::jsonString(redis["hostname"],""); - _rc->port = OSUtils::jsonInt(redis["port"],0); - _rc->password = OSUtils::jsonString(redis["password"],""); - _rc->clusterMode = OSUtils::jsonBool(redis["clusterMode"], false); - } + // TODO: Redis config + json& redis = settings["redis"]; + if (redis.is_object() && _rc == NULL) { + _rc = new RedisConfig; + _rc->hostname = OSUtils::jsonString(redis["hostname"], ""); + _rc->port = OSUtils::jsonInt(redis["port"], 0); + _rc->password = OSUtils::jsonString(redis["password"], ""); + _rc->clusterMode = OSUtils::jsonBool(redis["clusterMode"], false); + } #endif - // Bind to wildcard instead of to specific interfaces (disables full tunnel capability) - json &bind = settings["bind"]; - if (bind.is_array()) { - for(unsigned long i=0;i 0) { - InetAddress ip(ips.c_str()); - if ((ip.ss_family == AF_INET)||(ip.ss_family == AF_INET6)) - explicitBind.push_back(ip); - } - } - } - } + // Bind to wildcard instead of to specific interfaces (disables full tunnel capability) + json& bind = settings["bind"]; + if (bind.is_array()) { + for (unsigned long i = 0; i < bind.size(); ++i) { + const std::string ips(OSUtils::jsonString(bind[i], "")); + if (ips.length() > 0) { + InetAddress ip(ips.c_str()); + if ((ip.ss_family == AF_INET) || (ip.ss_family == AF_INET6)) + explicitBind.push_back(ip); + } + } + } + } - // Set trusted paths if there are any - if (!ppc.empty()) { - for(std::map::iterator i(ppc.begin());i!=ppc.end();++i) - _node->setPhysicalPathConfiguration(reinterpret_cast(&(i->first)),&(i->second)); - } - } + // Set trusted paths if there are any + if (! ppc.empty()) { + for (std::map::iterator i(ppc.begin()); i != ppc.end(); ++i) + _node->setPhysicalPathConfiguration(reinterpret_cast(&(i->first)), &(i->second)); + } + } - virtual ReasonForTermination reasonForTermination() const - { - Mutex::Lock _l(_termReason_m); - return _termReason; - } + virtual ReasonForTermination reasonForTermination() const + { + Mutex::Lock _l(_termReason_m); + return _termReason; + } - virtual std::string fatalErrorMessage() const - { - Mutex::Lock _l(_termReason_m); - return _fatalErrorMessage; - } + virtual std::string fatalErrorMessage() const + { + Mutex::Lock _l(_termReason_m); + return _fatalErrorMessage; + } - virtual std::string portDeviceName(uint64_t nwid) const - { - Mutex::Lock _l(_nets_m); - std::map::const_iterator n(_nets.find(nwid)); - if ((n != _nets.end())&&(n->second.tap())) - return n->second.tap()->deviceName(); - else return std::string(); - } + virtual std::string portDeviceName(uint64_t nwid) const + { + Mutex::Lock _l(_nets_m); + std::map::const_iterator n(_nets.find(nwid)); + if ((n != _nets.end()) && (n->second.tap())) + return n->second.tap()->deviceName(); + else + return std::string(); + } #ifdef ZT_SDK - virtual std::string givenHomePath() - { - return _homePath; - } + virtual std::string givenHomePath() + { + return _homePath; + } - void getRoutes(uint64_t nwid, void *routeArray, unsigned int *numRoutes) - { - Mutex::Lock _l(_nets_m); - NetworkState &n = _nets[nwid]; - *numRoutes = *numRoutes < n.config().routeCount ? *numRoutes : n.config().routeCount; - for(unsigned int i=0; i<*numRoutes; i++) { - ZT_VirtualNetworkRoute *vnr = (ZT_VirtualNetworkRoute*)routeArray; - memcpy(&vnr[i], &(n.config().routes[i]), sizeof(ZT_VirtualNetworkRoute)); - } - } + void getRoutes(uint64_t nwid, void* routeArray, unsigned int* numRoutes) + { + Mutex::Lock _l(_nets_m); + NetworkState& n = _nets[nwid]; + *numRoutes = *numRoutes < n.config().routeCount ? *numRoutes : n.config().routeCount; + for (unsigned int i = 0; i < *numRoutes; i++) { + ZT_VirtualNetworkRoute* vnr = (ZT_VirtualNetworkRoute*)routeArray; + memcpy(&vnr[i], &(n.config().routes[i]), sizeof(ZT_VirtualNetworkRoute)); + } + } - virtual Node *getNode() - { - return _node; - } -#endif // ZT_SDK + virtual Node* getNode() + { + return _node; + } +#endif // ZT_SDK - virtual void terminate() - { - _run_m.lock(); + virtual void terminate() + { + _run_m.lock(); - _run = false; - _run_m.unlock(); - _phy.whack(); - } + _run = false; + _run_m.unlock(); + _phy.whack(); + } - virtual bool getNetworkSettings(const uint64_t nwid,NetworkSettings &settings) const - { - Mutex::Lock _l(_nets_m); - std::map::const_iterator n(_nets.find(nwid)); - if (n == _nets.end()) - return false; - settings = n->second.settings(); - return true; - } + virtual bool getNetworkSettings(const uint64_t nwid, NetworkSettings& settings) const + { + Mutex::Lock _l(_nets_m); + std::map::const_iterator n(_nets.find(nwid)); + if (n == _nets.end()) + return false; + settings = n->second.settings(); + return true; + } - virtual bool setNetworkSettings(const uint64_t nwid,const NetworkSettings &settings) - { - char nlcpath[4096]; - OSUtils::ztsnprintf(nlcpath,sizeof(nlcpath),"%s" ZT_PATH_SEPARATOR_S "%.16llx.local.conf",_networksPath.c_str(),nwid); - FILE *out = fopen(nlcpath,"w"); - if (out) { - fprintf(out,"allowManaged=%d\n",(int)settings.allowManaged); - fprintf(out,"allowGlobal=%d\n",(int)settings.allowGlobal); - fprintf(out,"allowDefault=%d\n",(int)settings.allowDefault); - fprintf(out,"allowDNS=%d\n",(int)settings.allowDNS); - fclose(out); - } + virtual bool setNetworkSettings(const uint64_t nwid, const NetworkSettings& settings) + { + char nlcpath[4096]; + OSUtils::ztsnprintf(nlcpath, sizeof(nlcpath), "%s" ZT_PATH_SEPARATOR_S "%.16llx.local.conf", _networksPath.c_str(), nwid); + FILE* out = fopen(nlcpath, "w"); + if (out) { + fprintf(out, "allowManaged=%d\n", (int)settings.allowManaged); + fprintf(out, "allowGlobal=%d\n", (int)settings.allowGlobal); + fprintf(out, "allowDefault=%d\n", (int)settings.allowDefault); + fprintf(out, "allowDNS=%d\n", (int)settings.allowDNS); + fclose(out); + } - - return true; - } + return true; + } // Internal HTTP Control Plane - void startHTTPControlPlane() { - // control plane endpoints - std::string bondShowPath = "/bond/show/([0-9a-fA-F]{10})"; - std::string bondRotatePath = "/bond/rotate/([0-9a-fA-F]{10})"; - std::string setBondMtuPath = "/bond/setmtu/([0-9]{1,6})/([a-zA-Z0-9_]{1,16})/([0-9a-fA-F\\.\\:]{1,39})"; - std::string configPath = "/config"; - std::string configPostPath = "/config/settings"; - std::string healthPath = "/health"; - std::string moonListPath = "/moon"; - std::string moonPath = "/moon/([0-9a-fA-F]{10})"; - std::string networkListPath = "/network"; - std::string networkPath = "/network/([0-9a-fA-F]{16})"; - std::string peerListPath = "/peer"; - std::string peerPath = "/peer/([0-9a-fA-F]{10})"; - std::string statusPath = "/status"; - std::string metricsPath = "/metrics"; + void startHTTPControlPlane() + { + // control plane endpoints + std::string bondShowPath = "/bond/show/([0-9a-fA-F]{10})"; + std::string bondRotatePath = "/bond/rotate/([0-9a-fA-F]{10})"; + std::string setBondMtuPath = "/bond/setmtu/([0-9]{1,6})/([a-zA-Z0-9_]{1,16})/([0-9a-fA-F\\.\\:]{1,39})"; + std::string configPath = "/config"; + std::string configPostPath = "/config/settings"; + std::string healthPath = "/health"; + std::string moonListPath = "/moon"; + std::string moonPath = "/moon/([0-9a-fA-F]{10})"; + std::string networkListPath = "/network"; + std::string networkPath = "/network/([0-9a-fA-F]{16})"; + std::string peerListPath = "/peer"; + std::string peerPath = "/peer/([0-9a-fA-F]{10})"; + std::string statusPath = "/status"; + std::string metricsPath = "/metrics"; std::vector noAuthEndpoints { "/sso", "/health" }; - - auto setContent = [=] (const httplib::Request &req, httplib::Response &res, std::string content) { - if (req.has_param("jsonp")) { - if (content.length() > 0) { - res.set_content(req.get_param_value("jsonp") + "(" + content + ");", "application/javascript"); - } else { - res.set_content(req.get_param_value("jsonp") + "(null);", "application/javascript"); - } - } else { - if (content.length() > 0) { - res.set_content(content, "application/json"); - } else { - res.set_content("{}", "application/json"); - } - } - }; - - // - // static file server for app ui' - // - if (_enableWebServer) { - static std::string appUiPath = "/app"; - static char appUiDir[16384]; - sprintf(appUiDir,"%s%s",_homePath.c_str(),appUiPath.c_str()); - - auto ret = _controlPlane.set_mount_point(appUiPath, appUiDir); - _controlPlaneV6.set_mount_point(appUiPath, appUiDir); - if (!ret) { - fprintf(stderr, "Mounting app directory failed. Creating it. Path: %s - Dir: %s\n", appUiPath.c_str(), appUiDir); - if (!OSUtils::mkdir(appUiDir)) { - fprintf(stderr, "Could not create app directory either. Path: %s - Dir: %s\n", appUiPath.c_str(), appUiDir); - } else { - ret = _controlPlane.set_mount_point(appUiPath, appUiDir); - _controlPlaneV6.set_mount_point(appUiPath, appUiDir); - if (!ret) { - fprintf(stderr, "Really could not create and mount directory. Path: %s - Dir: %s\nWeb apps won't work.\n", appUiPath.c_str(), appUiDir); - } - } - } - - if (ret) { - // fallback to /index.html for paths that don't exist for SPAs - auto indexFallbackGet = [](const httplib::Request &req, httplib::Response &res) { - // fprintf(stderr, "fallback \n"); - - auto match = req.matches[1]; - if (match.matched) { - - // fallback - char indexHtmlPath[16384]; - sprintf(indexHtmlPath,"%s/%s/%s", appUiDir, match.str().c_str(), "index.html"); - // fprintf(stderr, "fallback path %s\n", indexHtmlPath); - - std::string indexHtml; - - if (!OSUtils::readFile(indexHtmlPath, indexHtml)) { - res.status = 500; - return; - } - - res.set_content(indexHtml.c_str(), "text/html"); - } else { - res.status = 500; - return; - } - }; - - auto slashRedirect = [](const httplib::Request &req, httplib::Response &res) { - // fprintf(stderr, "redirect \n"); - - // add .html - std::string htmlFile; - char htmlPath[16384]; - sprintf(htmlPath,"%s%s%s", appUiDir, (req.path).substr(appUiPath.length()).c_str(), ".html"); - // fprintf(stderr, "path: %s\n", htmlPath); - if (OSUtils::readFile(htmlPath, htmlFile)) { - res.set_content(htmlFile.c_str(), "text/html"); - return; - } else { - res.status = 301; - res.set_header("location", req.path + "/"); - } - }; - - // auto missingAssetGet = [&, setContent](const httplib::Request &req, httplib::Response &res) { - // fprintf(stderr, "missing \n"); - // res.status = 404; - // std::string html = "oops"; - // res.set_content(html, "text/plain"); - // res.set_header("Content-Type", "text/plain"); - // return; - // }; - - // auto fix no trailing slash by adding .html or redirecting to path/ - _controlPlane.Get(appUiPath + R"((/[\w|-]+)+$)", slashRedirect); - _controlPlaneV6.Get(appUiPath + R"((/[\w|-]+)+$)", slashRedirect); - - // // 404 missing assets for *.ext paths - // s.Get(appUiPath + R"(/\.\w+$)", missingAssetGet); - // sv6.Get(appUiPath + R"(/\.\w+$)", missingAssetGet); - - // fallback to index.html for unknown paths/files - _controlPlane.Get(appUiPath + R"((/[\w|-]+)(/[\w|-]+)*/$)", indexFallbackGet); - _controlPlaneV6.Get(appUiPath + R"((/[\w|-]+)(/[\w|-]+)*/$)", indexFallbackGet); - - } - } - - auto authCheck = [=] (const httplib::Request &req, httplib::Response &res) { - if (req.path == "/metrics") { - - if (req.has_header("x-zt1-auth")) { - std::string token = req.get_header_value("x-zt1-auth"); - if (token == _metricsToken || token == _authToken) { - return httplib::Server::HandlerResponse::Unhandled; - } - } else if (req.has_param("auth")) { - std::string token = req.get_param_value("auth"); - if (token == _metricsToken || token == _authToken) { - return httplib::Server::HandlerResponse::Unhandled; - } - } else if (req.has_header("authorization")) { - std::string auth = req.get_header_value("authorization"); - if (bearerTokenValid(auth, _metricsToken) || bearerTokenValid(auth, _authToken)) { - return httplib::Server::HandlerResponse::Unhandled; - } - } - - setContent(req, res, "{}"); - res.status = 401; - return httplib::Server::HandlerResponse::Handled; - } else { - std::string r = req.remote_addr; - InetAddress remoteAddr(r.c_str()); - - bool ipAllowed = false; - bool isAuth = false; - // If localhost, allow - if (remoteAddr.ipScope() == InetAddress::IP_SCOPE_LOOPBACK) { - ipAllowed = true; - } - - if (!ipAllowed) { - for (auto i = _allowManagementFrom.begin(); i != _allowManagementFrom.end(); ++i) { - if (i->containsAddress(remoteAddr)) { - ipAllowed = true; - break; - } - } - } - - - if (ipAllowed) { - // auto-pass endpoints in `noAuthEndpoints`. No auth token required - if (std::find(noAuthEndpoints.begin(), noAuthEndpoints.end(), req.path) != noAuthEndpoints.end()) { - isAuth = true; - } - - // Web Apps base path - if (req.path.rfind("/app", 0) == 0) { //starts with /app - isAuth = true; - } - - if (!isAuth) { - // check auth token - if (req.has_header("x-zt1-auth")) { - std::string token = req.get_header_value("x-zt1-auth"); - if (token == _authToken) { - isAuth = true; - } - } else if (req.has_param("auth")) { - std::string token = req.get_param_value("auth"); - if (token == _authToken) { - isAuth = true; - } - } else if (req.has_header("authorization")) { - std::string auth = req.get_header_value("authorization"); - isAuth = bearerTokenValid(auth, _authToken); - } - } - } - - if (ipAllowed && isAuth) { - return httplib::Server::HandlerResponse::Unhandled; - } - setContent(req, res, "{}"); - res.status = 401; - return httplib::Server::HandlerResponse::Handled; - } + auto setContent = [=](const httplib::Request& req, httplib::Response& res, std::string content) { + if (req.has_param("jsonp")) { + if (content.length() > 0) { + res.set_content(req.get_param_value("jsonp") + "(" + content + ");", "application/javascript"); + } + else { + res.set_content(req.get_param_value("jsonp") + "(null);", "application/javascript"); + } + } + else { + if (content.length() > 0) { + res.set_content(content, "application/json"); + } + else { + res.set_content("{}", "application/json"); + } + } }; + // + // static file server for app ui' + // + if (_enableWebServer) { + static std::string appUiPath = "/app"; + static char appUiDir[16384]; + sprintf(appUiDir, "%s%s", _homePath.c_str(), appUiPath.c_str()); - auto bondShow = [&, setContent](const httplib::Request &req, httplib::Response &res) { - if (!_node->bondController()->inUse()) { - setContent(req, res, ""); - res.status = 400; - return; - } + auto ret = _controlPlane.set_mount_point(appUiPath, appUiDir); + _controlPlaneV6.set_mount_point(appUiPath, appUiDir); + if (! ret) { + fprintf(stderr, "Mounting app directory failed. Creating it. Path: %s - Dir: %s\n", appUiPath.c_str(), appUiDir); + if (! OSUtils::mkdir(appUiDir)) { + fprintf(stderr, "Could not create app directory either. Path: %s - Dir: %s\n", appUiPath.c_str(), appUiDir); + } + else { + ret = _controlPlane.set_mount_point(appUiPath, appUiDir); + _controlPlaneV6.set_mount_point(appUiPath, appUiDir); + if (! ret) { + fprintf(stderr, "Really could not create and mount directory. Path: %s - Dir: %s\nWeb apps won't work.\n", appUiPath.c_str(), appUiDir); + } + } + } - ZT_PeerList *pl = _node->peers(); - if (pl) { - bool foundBond = false; - auto id = req.matches[1]; - auto out = json::object(); - uint64_t wantp = Utils::hexStrToU64(id.str().c_str()); - for(unsigned long i=0;ipeerCount;++i) { - if (pl->peers[i].address == wantp) { - SharedPtr bond = _node->bondController()->getBondByPeerId(wantp); - if (bond) { - _peerToJson(out,&(pl->peers[i]),bond,(_tcpFallbackTunnel != (TcpConnection *)0)); - setContent(req, res, out.dump()); - foundBond = true; - } else { - setContent(req, res, ""); - res.status = 400; - } - break; - } - } - if (!foundBond) { - setContent(req, res, ""); - res.status = 400; - } - } - _node->freeQueryResult((void *)pl); - }; - _controlPlane.Get(bondShowPath, bondShow); - _controlPlaneV6.Get(bondShowPath, bondShow); + if (ret) { + // fallback to /index.html for paths that don't exist for SPAs + auto indexFallbackGet = [](const httplib::Request& req, httplib::Response& res) { + // fprintf(stderr, "fallback \n"); - auto bondRotate = [&, setContent](const httplib::Request &req, httplib::Response &res) { - if (!_node->bondController()->inUse()) { - setContent(req, res, ""); - res.status = 400; - return; - } - auto bondID = req.matches[1]; - uint64_t id = Utils::hexStrToU64(bondID.str().c_str()); - SharedPtr bond = _node->bondController()->getBondByPeerId(id); - if (bond) { - if (bond->abForciblyRotateLink()) { - res.status = 200; - } else { - res.status = 400; - } - } else { - fprintf(stderr, "unable to find bond to peer %llx\n", (unsigned long long)id); - res.status = 400; - } - setContent(req, res, "{}"); - }; - _controlPlane.Post(bondRotatePath, bondRotate); - _controlPlane.Put(bondRotatePath, bondRotate); - _controlPlaneV6.Post(bondRotatePath, bondRotate); - _controlPlaneV6.Put(bondRotatePath, bondRotate); + auto match = req.matches[1]; + if (match.matched) { + // fallback + char indexHtmlPath[16384]; + sprintf(indexHtmlPath, "%s/%s/%s", appUiDir, match.str().c_str(), "index.html"); + // fprintf(stderr, "fallback path %s\n", indexHtmlPath); - auto setMtu = [&, setContent](const httplib::Request &req, httplib::Response &res) { - if (!_node->bondController()->inUse()) { - setContent(req, res, "Bonding layer isn't active yet"); - res.status = 400; - return; - } - uint32_t mtu = atoi(req.matches[1].str().c_str()); - if (mtu < 68 || mtu > 65535) { - setContent(req, res, "Specified MTU is not reasonable"); - res.status = 400; - return; - } - res.status = _node->bondController()->setAllMtuByTuple(mtu, req.matches[2].str().c_str(), req.matches[3].str().c_str()) ? 200 : 400; - if (res.status == 400) { - setContent(req, res, "Unable to find specified link"); - return; - } - setContent(req, res, "{}"); - }; - _controlPlane.Post(setBondMtuPath, setMtu); - _controlPlane.Put(setBondMtuPath, setMtu); - _controlPlaneV6.Post(setBondMtuPath, setMtu); - _controlPlaneV6.Put(setBondMtuPath, setMtu); + std::string indexHtml; - auto getConfig = [&, setContent](const httplib::Request &req, httplib::Response &res) { - std::string config; - { - Mutex::Lock lc(_localConfig_m); - config = _localConfig.dump(); - } - if (config == "null") { - config = "{}"; - } - setContent(req, res, config); - }; - _controlPlane.Get(configPath, getConfig); - _controlPlaneV6.Get(configPath, getConfig); + if (! OSUtils::readFile(indexHtmlPath, indexHtml)) { + res.status = 500; + return; + } - auto configPost = [&, setContent](const httplib::Request &req, httplib::Response &res) { - json j(OSUtils::jsonParse(req.body)); - if (j.is_object()) { - Mutex::Lock lcl(_localConfig_m); - json lc(_localConfig); - for(json::const_iterator s(j.begin()); s != j.end(); ++s) { - lc["settings"][s.key()] = s.value(); - } - std::string lcStr = OSUtils::jsonDump(lc, 4); - if (OSUtils::writeFile((_homePath + ZT_PATH_SEPARATOR_S "local.conf").c_str(), lcStr)) { - _localConfig = lc; - } - } - setContent(req, res, "{}"); - }; - _controlPlane.Post(configPostPath, configPost); - _controlPlane.Put(configPostPath, configPost); - _controlPlaneV6.Post(configPostPath, configPost); - _controlPlaneV6.Put(configPostPath, configPost); + res.set_content(indexHtml.c_str(), "text/html"); + } + else { + res.status = 500; + return; + } + }; - auto healthGet = [&, setContent](const httplib::Request &req, httplib::Response &res) { - json out = json::object(); + auto slashRedirect = [](const httplib::Request& req, httplib::Response& res) { + // fprintf(stderr, "redirect \n"); - char tmp[256]; + // add .html + std::string htmlFile; + char htmlPath[16384]; + sprintf(htmlPath, "%s%s%s", appUiDir, (req.path).substr(appUiPath.length()).c_str(), ".html"); + // fprintf(stderr, "path: %s\n", htmlPath); + if (OSUtils::readFile(htmlPath, htmlFile)) { + res.set_content(htmlFile.c_str(), "text/html"); + return; + } + else { + res.status = 301; + res.set_header("location", req.path + "/"); + } + }; - ZT_NodeStatus status; - _node->status(&status); + // auto missingAssetGet = [&, setContent](const httplib::Request &req, httplib::Response &res) { + // fprintf(stderr, "missing \n"); + // res.status = 404; + // std::string html = "oops"; + // res.set_content(html, "text/plain"); + // res.set_header("Content-Type", "text/plain"); + // return; + // }; - out["online"] = (bool)(status.online != 0); - out["versionMajor"] = ZEROTIER_ONE_VERSION_MAJOR; - out["versionMinor"] = ZEROTIER_ONE_VERSION_MINOR; - out["versionRev"] = ZEROTIER_ONE_VERSION_REVISION; - out["versionBuild"] = ZEROTIER_ONE_VERSION_BUILD; - OSUtils::ztsnprintf(tmp,sizeof(tmp),"%d.%d.%d",ZEROTIER_ONE_VERSION_MAJOR,ZEROTIER_ONE_VERSION_MINOR,ZEROTIER_ONE_VERSION_REVISION); - out["version"] = tmp; - out["clock"] = OSUtils::now(); + // auto fix no trailing slash by adding .html or redirecting to path/ + _controlPlane.Get(appUiPath + R"((/[\w|-]+)+$)", slashRedirect); + _controlPlaneV6.Get(appUiPath + R"((/[\w|-]+)+$)", slashRedirect); - setContent(req, res, out.dump()); - }; - _controlPlane.Get(healthPath, healthGet); - _controlPlaneV6.Get(healthPath, healthGet); + // // 404 missing assets for *.ext paths + // s.Get(appUiPath + R"(/\.\w+$)", missingAssetGet); + // sv6.Get(appUiPath + R"(/\.\w+$)", missingAssetGet); - auto moonListGet = [&, setContent](const httplib::Request &req, httplib::Response &res) { - std::vector moons(_node->moons()); + // fallback to index.html for unknown paths/files + _controlPlane.Get(appUiPath + R"((/[\w|-]+)(/[\w|-]+)*/$)", indexFallbackGet); + _controlPlaneV6.Get(appUiPath + R"((/[\w|-]+)(/[\w|-]+)*/$)", indexFallbackGet); + } + } - auto out = json::array(); - for (auto i = moons.begin(); i != moons.end(); ++i) { - json mj; - _moonToJson(mj, *i); - out.push_back(mj); - } - setContent(req, res, out.dump()); - }; - _controlPlane.Get(moonListPath, moonListGet); - _controlPlaneV6.Get(moonListPath, moonListGet); + auto authCheck = [=](const httplib::Request& req, httplib::Response& res) { + if (req.path == "/metrics") { + if (req.has_header("x-zt1-auth")) { + std::string token = req.get_header_value("x-zt1-auth"); + if (token == _metricsToken || token == _authToken) { + return httplib::Server::HandlerResponse::Unhandled; + } + } + else if (req.has_param("auth")) { + std::string token = req.get_param_value("auth"); + if (token == _metricsToken || token == _authToken) { + return httplib::Server::HandlerResponse::Unhandled; + } + } + else if (req.has_header("authorization")) { + std::string auth = req.get_header_value("authorization"); + if (bearerTokenValid(auth, _metricsToken) || bearerTokenValid(auth, _authToken)) { + return httplib::Server::HandlerResponse::Unhandled; + } + } - auto moonGet = [&, setContent](const httplib::Request &req, httplib::Response &res){ - std::vector moons(_node->moons()); - auto input = req.matches[1]; - auto out = json::object(); - const uint64_t id = Utils::hexStrToU64(input.str().c_str()); - for (auto i = moons.begin(); i != moons.end(); ++i) { - if (i->id() == id) { - _moonToJson(out, *i); - break; - } - } - setContent(req, res, out.dump()); - }; - _controlPlane.Get(moonPath, moonGet); - _controlPlaneV6.Get(moonPath, moonGet); + setContent(req, res, "{}"); + res.status = 401; + return httplib::Server::HandlerResponse::Handled; + } + else { + std::string r = req.remote_addr; + InetAddress remoteAddr(r.c_str()); - auto moonPost = [&, setContent](const httplib::Request &req, httplib::Response &res) { - auto input = req.matches[1]; - uint64_t seed = 0; - try { - json j(OSUtils::jsonParse(req.body)); - if (j.is_object()) { - seed = Utils::hexStrToU64(OSUtils::jsonString(j["seed"],"0").c_str()); - } - } catch ( ... ) { - // discard invalid JSON - } + bool ipAllowed = false; + bool isAuth = false; + // If localhost, allow + if (remoteAddr.ipScope() == InetAddress::IP_SCOPE_LOOPBACK) { + ipAllowed = true; + } - std::vector moons(_node->moons()); - const uint64_t id = Utils::hexStrToU64(input.str().c_str()); - bool found = false; - auto out = json::object(); - for(std::vector::const_iterator m(moons.begin());m!=moons.end();++m) { - if (m->id() == id) { - _moonToJson(out,*m); - found = true; - break; - } - } + if (! ipAllowed) { + for (auto i = _allowManagementFrom.begin(); i != _allowManagementFrom.end(); ++i) { + if (i->containsAddress(remoteAddr)) { + ipAllowed = true; + break; + } + } + } - if (!found && seed != 0) { - char tmp[64]; - OSUtils::ztsnprintf(tmp,sizeof(tmp),"%.16llx",id); - out["id"] = tmp; - out["roots"] = json::array(); - out["timestamp"] = 0; - out["signature"] = json(); - out["updatesMustBeSignedBy"] = json(); - out["waiting"] = true; - _node->orbit((void *)0,id,seed); - } - setContent(req, res, out.dump()); - }; - _controlPlane.Post(moonPath, moonPost); - _controlPlane.Put(moonPath, moonPost); - _controlPlaneV6.Post(moonPath, moonPost); - _controlPlaneV6.Put(moonPath, moonPost); + if (ipAllowed) { + // auto-pass endpoints in `noAuthEndpoints`. No auth token required + if (std::find(noAuthEndpoints.begin(), noAuthEndpoints.end(), req.path) != noAuthEndpoints.end()) { + isAuth = true; + } - auto moonDelete = [&, setContent](const httplib::Request &req, httplib::Response &res) { - auto input = req.matches[1]; - uint64_t id = Utils::hexStrToU64(input.str().c_str()); - auto out = json::object(); - _node->deorbit((void*)0,id); - out["result"] = true; - setContent(req, res, out.dump()); - }; - _controlPlane.Delete(moonPath, moonDelete); + // Web Apps base path + if (req.path.rfind("/app", 0) == 0) { // starts with /app + isAuth = true; + } - auto networkListGet = [&, setContent](const httplib::Request &req, httplib::Response &res) { + if (! isAuth) { + // check auth token + if (req.has_header("x-zt1-auth")) { + std::string token = req.get_header_value("x-zt1-auth"); + if (token == _authToken) { + isAuth = true; + } + } + else if (req.has_param("auth")) { + std::string token = req.get_param_value("auth"); + if (token == _authToken) { + isAuth = true; + } + } + else if (req.has_header("authorization")) { + std::string auth = req.get_header_value("authorization"); + isAuth = bearerTokenValid(auth, _authToken); + } + } + } + + if (ipAllowed && isAuth) { + return httplib::Server::HandlerResponse::Unhandled; + } + setContent(req, res, "{}"); + res.status = 401; + return httplib::Server::HandlerResponse::Handled; + } + }; + + auto bondShow = [&, setContent](const httplib::Request& req, httplib::Response& res) { + if (! _node->bondController()->inUse()) { + setContent(req, res, ""); + res.status = 400; + return; + } + + ZT_PeerList* pl = _node->peers(); + if (pl) { + bool foundBond = false; + auto id = req.matches[1]; + auto out = json::object(); + uint64_t wantp = Utils::hexStrToU64(id.str().c_str()); + for (unsigned long i = 0; i < pl->peerCount; ++i) { + if (pl->peers[i].address == wantp) { + SharedPtr bond = _node->bondController()->getBondByPeerId(wantp); + if (bond) { + _peerToJson(out, &(pl->peers[i]), bond, (_tcpFallbackTunnel != (TcpConnection*)0)); + setContent(req, res, out.dump()); + foundBond = true; + } + else { + setContent(req, res, ""); + res.status = 400; + } + break; + } + } + if (! foundBond) { + setContent(req, res, ""); + res.status = 400; + } + } + _node->freeQueryResult((void*)pl); + }; + _controlPlane.Get(bondShowPath, bondShow); + _controlPlaneV6.Get(bondShowPath, bondShow); + + auto bondRotate = [&, setContent](const httplib::Request& req, httplib::Response& res) { + if (! _node->bondController()->inUse()) { + setContent(req, res, ""); + res.status = 400; + return; + } + auto bondID = req.matches[1]; + uint64_t id = Utils::hexStrToU64(bondID.str().c_str()); + SharedPtr bond = _node->bondController()->getBondByPeerId(id); + if (bond) { + if (bond->abForciblyRotateLink()) { + res.status = 200; + } + else { + res.status = 400; + } + } + else { + fprintf(stderr, "unable to find bond to peer %llx\n", (unsigned long long)id); + res.status = 400; + } + setContent(req, res, "{}"); + }; + _controlPlane.Post(bondRotatePath, bondRotate); + _controlPlane.Put(bondRotatePath, bondRotate); + _controlPlaneV6.Post(bondRotatePath, bondRotate); + _controlPlaneV6.Put(bondRotatePath, bondRotate); + + auto setMtu = [&, setContent](const httplib::Request& req, httplib::Response& res) { + if (! _node->bondController()->inUse()) { + setContent(req, res, "Bonding layer isn't active yet"); + res.status = 400; + return; + } + uint32_t mtu = atoi(req.matches[1].str().c_str()); + if (mtu < 68 || mtu > 65535) { + setContent(req, res, "Specified MTU is not reasonable"); + res.status = 400; + return; + } + res.status = _node->bondController()->setAllMtuByTuple(mtu, req.matches[2].str().c_str(), req.matches[3].str().c_str()) ? 200 : 400; + if (res.status == 400) { + setContent(req, res, "Unable to find specified link"); + return; + } + setContent(req, res, "{}"); + }; + _controlPlane.Post(setBondMtuPath, setMtu); + _controlPlane.Put(setBondMtuPath, setMtu); + _controlPlaneV6.Post(setBondMtuPath, setMtu); + _controlPlaneV6.Put(setBondMtuPath, setMtu); + + auto getConfig = [&, setContent](const httplib::Request& req, httplib::Response& res) { + std::string config; + { + Mutex::Lock lc(_localConfig_m); + config = _localConfig.dump(); + } + if (config == "null") { + config = "{}"; + } + setContent(req, res, config); + }; + _controlPlane.Get(configPath, getConfig); + _controlPlaneV6.Get(configPath, getConfig); + + auto configPost = [&, setContent](const httplib::Request& req, httplib::Response& res) { + json j(OSUtils::jsonParse(req.body)); + if (j.is_object()) { + Mutex::Lock lcl(_localConfig_m); + json lc(_localConfig); + for (json::const_iterator s(j.begin()); s != j.end(); ++s) { + lc["settings"][s.key()] = s.value(); + } + std::string lcStr = OSUtils::jsonDump(lc, 4); + if (OSUtils::writeFile((_homePath + ZT_PATH_SEPARATOR_S "local.conf").c_str(), lcStr)) { + _localConfig = lc; + } + } + setContent(req, res, "{}"); + }; + _controlPlane.Post(configPostPath, configPost); + _controlPlane.Put(configPostPath, configPost); + _controlPlaneV6.Post(configPostPath, configPost); + _controlPlaneV6.Put(configPostPath, configPost); + + auto healthGet = [&, setContent](const httplib::Request& req, httplib::Response& res) { + json out = json::object(); + + char tmp[256]; + + ZT_NodeStatus status; + _node->status(&status); + + out["online"] = (bool)(status.online != 0); + out["versionMajor"] = ZEROTIER_ONE_VERSION_MAJOR; + out["versionMinor"] = ZEROTIER_ONE_VERSION_MINOR; + out["versionRev"] = ZEROTIER_ONE_VERSION_REVISION; + out["versionBuild"] = ZEROTIER_ONE_VERSION_BUILD; + OSUtils::ztsnprintf(tmp, sizeof(tmp), "%d.%d.%d", ZEROTIER_ONE_VERSION_MAJOR, ZEROTIER_ONE_VERSION_MINOR, ZEROTIER_ONE_VERSION_REVISION); + out["version"] = tmp; + out["clock"] = OSUtils::now(); + + setContent(req, res, out.dump()); + }; + _controlPlane.Get(healthPath, healthGet); + _controlPlaneV6.Get(healthPath, healthGet); + + auto moonListGet = [&, setContent](const httplib::Request& req, httplib::Response& res) { + std::vector moons(_node->moons()); + + auto out = json::array(); + for (auto i = moons.begin(); i != moons.end(); ++i) { + json mj; + _moonToJson(mj, *i); + out.push_back(mj); + } + setContent(req, res, out.dump()); + }; + _controlPlane.Get(moonListPath, moonListGet); + _controlPlaneV6.Get(moonListPath, moonListGet); + + auto moonGet = [&, setContent](const httplib::Request& req, httplib::Response& res) { + std::vector moons(_node->moons()); + auto input = req.matches[1]; + auto out = json::object(); + const uint64_t id = Utils::hexStrToU64(input.str().c_str()); + for (auto i = moons.begin(); i != moons.end(); ++i) { + if (i->id() == id) { + _moonToJson(out, *i); + break; + } + } + setContent(req, res, out.dump()); + }; + _controlPlane.Get(moonPath, moonGet); + _controlPlaneV6.Get(moonPath, moonGet); + + auto moonPost = [&, setContent](const httplib::Request& req, httplib::Response& res) { + auto input = req.matches[1]; + uint64_t seed = 0; + try { + json j(OSUtils::jsonParse(req.body)); + if (j.is_object()) { + seed = Utils::hexStrToU64(OSUtils::jsonString(j["seed"], "0").c_str()); + } + } + catch (...) { + // discard invalid JSON + } + + std::vector moons(_node->moons()); + const uint64_t id = Utils::hexStrToU64(input.str().c_str()); + bool found = false; + auto out = json::object(); + for (std::vector::const_iterator m(moons.begin()); m != moons.end(); ++m) { + if (m->id() == id) { + _moonToJson(out, *m); + found = true; + break; + } + } + + if (! found && seed != 0) { + char tmp[64]; + OSUtils::ztsnprintf(tmp, sizeof(tmp), "%.16llx", id); + out["id"] = tmp; + out["roots"] = json::array(); + out["timestamp"] = 0; + out["signature"] = json(); + out["updatesMustBeSignedBy"] = json(); + out["waiting"] = true; + _node->orbit((void*)0, id, seed); + } + setContent(req, res, out.dump()); + }; + _controlPlane.Post(moonPath, moonPost); + _controlPlane.Put(moonPath, moonPost); + _controlPlaneV6.Post(moonPath, moonPost); + _controlPlaneV6.Put(moonPath, moonPost); + + auto moonDelete = [&, setContent](const httplib::Request& req, httplib::Response& res) { + auto input = req.matches[1]; + uint64_t id = Utils::hexStrToU64(input.str().c_str()); + auto out = json::object(); + _node->deorbit((void*)0, id); + out["result"] = true; + setContent(req, res, out.dump()); + }; + _controlPlane.Delete(moonPath, moonDelete); + + auto networkListGet = [&, setContent](const httplib::Request& req, httplib::Response& res) { Mutex::Lock _l(_nets_m); auto out = json::array(); for (auto it = _nets.begin(); it != _nets.end(); ++it) { - NetworkState &ns = it->second; + NetworkState& ns = it->second; json nj; _networkToJson(nj, ns); out.push_back(nj); } - setContent(req, res, out.dump()); + setContent(req, res, out.dump()); }; - _controlPlane.Get(networkListPath, networkListGet); - _controlPlaneV6.Get(networkListPath, networkListGet); + _controlPlane.Get(networkListPath, networkListGet); + _controlPlaneV6.Get(networkListPath, networkListGet); - auto networkGet = [&, setContent](const httplib::Request &req, httplib::Response &res) { - Mutex::Lock _l(_nets_m); + auto networkGet = [&, setContent](const httplib::Request& req, httplib::Response& res) { + Mutex::Lock _l(_nets_m); auto input = req.matches[1]; - const uint64_t nwid = Utils::hexStrToU64(input.str().c_str()); - if (_nets.find(nwid) != _nets.end()) { - auto out = json::object(); - NetworkState &ns = _nets[nwid]; - _networkToJson(out, ns); - setContent(req, res, out.dump()); - return; - } - setContent(req, res, ""); - res.status = 404; + const uint64_t nwid = Utils::hexStrToU64(input.str().c_str()); + if (_nets.find(nwid) != _nets.end()) { + auto out = json::object(); + NetworkState& ns = _nets[nwid]; + _networkToJson(out, ns); + setContent(req, res, out.dump()); + return; + } + setContent(req, res, ""); + res.status = 404; }; _controlPlane.Get(networkPath, networkGet); - _controlPlaneV6.Get(networkPath, networkGet); + _controlPlaneV6.Get(networkPath, networkGet); - auto networkPost = [&, setContent](const httplib::Request &req, httplib::Response &res) { - auto input = req.matches[1]; - uint64_t wantnw = Utils::hexStrToU64(input.str().c_str()); - _node->join(wantnw, (void*)0, (void*)0); - auto out = json::object(); - Mutex::Lock l(_nets_m); - bool allowDefault = false; + auto networkPost = [&, setContent](const httplib::Request& req, httplib::Response& res) { + auto input = req.matches[1]; + uint64_t wantnw = Utils::hexStrToU64(input.str().c_str()); + _node->join(wantnw, (void*)0, (void*)0); + auto out = json::object(); + Mutex::Lock l(_nets_m); + bool allowDefault = false; - if (!_nets.empty()) { - NetworkState &ns = _nets[wantnw]; - try { - json j(OSUtils::jsonParse(req.body)); + if (! _nets.empty()) { + NetworkState& ns = _nets[wantnw]; + try { + json j(OSUtils::jsonParse(req.body)); - json &allowManaged = j["allowManaged"]; - if (allowManaged.is_boolean()) { - ns.setAllowManaged((bool)allowManaged); - } - json& allowGlobal = j["allowGlobal"]; - if (allowGlobal.is_boolean()) { - ns.setAllowGlobal((bool)allowGlobal); - } - json& _allowDefault = j["allowDefault"]; - if (_allowDefault.is_boolean()) { - allowDefault = _allowDefault; - ns.setAllowDefault((bool)allowDefault); - } - json& allowDNS = j["allowDNS"]; - if (allowDNS.is_boolean()) { - ns.setAllowDNS((bool)allowDNS); - } - } catch (...) { - // discard invalid JSON - } - setNetworkSettings(wantnw, ns.settings()); - if (ns.tap()) { - syncManagedStuff(ns,true,true,true); - } + json& allowManaged = j["allowManaged"]; + if (allowManaged.is_boolean()) { + ns.setAllowManaged((bool)allowManaged); + } + json& allowGlobal = j["allowGlobal"]; + if (allowGlobal.is_boolean()) { + ns.setAllowGlobal((bool)allowGlobal); + } + json& _allowDefault = j["allowDefault"]; + if (_allowDefault.is_boolean()) { + allowDefault = _allowDefault; + ns.setAllowDefault((bool)allowDefault); + } + json& allowDNS = j["allowDNS"]; + if (allowDNS.is_boolean()) { + ns.setAllowDNS((bool)allowDNS); + } + } + catch (...) { + // discard invalid JSON + } + setNetworkSettings(wantnw, ns.settings()); + if (ns.tap()) { + syncManagedStuff(ns, true, true, true); + } - _networkToJson(out, ns); - } + _networkToJson(out, ns); + } #ifdef __FreeBSD__ - if(!!allowDefault){ - res.status = 400; - setContent(req, res, "Allow Default does not work properly on FreeBSD. See #580"); - } else { - setContent(req, res, out.dump()); - - } + if (! ! allowDefault) { + res.status = 400; + setContent(req, res, "Allow Default does not work properly on FreeBSD. See #580"); + } + else { + setContent(req, res, out.dump()); + } #else - setContent(req, res, out.dump()); + setContent(req, res, out.dump()); #endif - }; - _controlPlane.Post(networkPath, networkPost); - _controlPlane.Put(networkPath, networkPost); - _controlPlaneV6.Post(networkPath, networkPost); - _controlPlaneV6.Put(networkPath, networkPost); + }; + _controlPlane.Post(networkPath, networkPost); + _controlPlane.Put(networkPath, networkPost); + _controlPlaneV6.Post(networkPath, networkPost); + _controlPlaneV6.Put(networkPath, networkPost); - auto networkDelete = [&, setContent](const httplib::Request &req, httplib::Response &res) { - auto input = req.matches[1]; - auto out = json::object(); - ZT_VirtualNetworkList *nws = _node->networks(); - uint64_t wantnw = Utils::hexStrToU64(input.str().c_str()); - for(unsigned long i=0; i < nws->networkCount; ++i) { - if (nws->networks[i].nwid == wantnw) { - _node->leave(wantnw, (void**)0, (void*)0); - out["result"] = true; - } - } - _node->freeQueryResult((void*)nws); - setContent(req, res, out.dump()); - }; - _controlPlane.Delete(networkPath, networkDelete); - _controlPlaneV6.Delete(networkPath, networkDelete); + auto networkDelete = [&, setContent](const httplib::Request& req, httplib::Response& res) { + auto input = req.matches[1]; + auto out = json::object(); + ZT_VirtualNetworkList* nws = _node->networks(); + uint64_t wantnw = Utils::hexStrToU64(input.str().c_str()); + for (unsigned long i = 0; i < nws->networkCount; ++i) { + if (nws->networks[i].nwid == wantnw) { + _node->leave(wantnw, (void**)0, (void*)0); + out["result"] = true; + } + } + _node->freeQueryResult((void*)nws); + setContent(req, res, out.dump()); + }; + _controlPlane.Delete(networkPath, networkDelete); + _controlPlaneV6.Delete(networkPath, networkDelete); - auto peerListGet = [&, setContent](const httplib::Request &req, httplib::Response &res) { - ZT_PeerList *pl = _node->peers(); - auto out = nlohmann::json::array(); + auto peerListGet = [&, setContent](const httplib::Request& req, httplib::Response& res) { + ZT_PeerList* pl = _node->peers(); + auto out = nlohmann::json::array(); - for(unsigned long i=0;ipeerCount;++i) { - nlohmann::json pj; - SharedPtr bond = SharedPtr(); - if (pl->peers[i].isBonded) { - const uint64_t id = pl->peers[i].address; - bond = _node->bondController()->getBondByPeerId(id); - } - _peerToJson(pj,&(pl->peers[i]),bond,(_tcpFallbackTunnel != (TcpConnection *)0)); - out.push_back(pj); - } - _node->freeQueryResult((void*)pl); - setContent(req, res, out.dump()); - }; - _controlPlane.Get(peerListPath, peerListGet); - _controlPlaneV6.Get(peerListPath, peerListGet); + for (unsigned long i = 0; i < pl->peerCount; ++i) { + nlohmann::json pj; + SharedPtr bond = SharedPtr(); + if (pl->peers[i].isBonded) { + const uint64_t id = pl->peers[i].address; + bond = _node->bondController()->getBondByPeerId(id); + } + _peerToJson(pj, &(pl->peers[i]), bond, (_tcpFallbackTunnel != (TcpConnection*)0)); + out.push_back(pj); + } + _node->freeQueryResult((void*)pl); + setContent(req, res, out.dump()); + }; + _controlPlane.Get(peerListPath, peerListGet); + _controlPlaneV6.Get(peerListPath, peerListGet); - auto peerGet = [&, setContent](const httplib::Request &req, httplib::Response &res) { - ZT_PeerList *pl = _node->peers(); + auto peerGet = [&, setContent](const httplib::Request& req, httplib::Response& res) { + ZT_PeerList* pl = _node->peers(); - auto input = req.matches[1]; - uint64_t wantp = Utils::hexStrToU64(input.str().c_str()); - auto out = json::object(); - for(unsigned long i=0;ipeerCount;++i) { - if (pl->peers[i].address == wantp) { - SharedPtr bond = SharedPtr(); - if (pl->peers[i].isBonded) { - bond = _node->bondController()->getBondByPeerId(wantp); - } - _peerToJson(out,&(pl->peers[i]),bond,(_tcpFallbackTunnel != (TcpConnection *)0)); - break; - } - } - _node->freeQueryResult((void*)pl); - setContent(req, res, out.dump()); - }; - _controlPlane.Get(peerPath, peerGet); - _controlPlaneV6.Get(peerPath, peerGet); + auto input = req.matches[1]; + uint64_t wantp = Utils::hexStrToU64(input.str().c_str()); + auto out = json::object(); + for (unsigned long i = 0; i < pl->peerCount; ++i) { + if (pl->peers[i].address == wantp) { + SharedPtr bond = SharedPtr(); + if (pl->peers[i].isBonded) { + bond = _node->bondController()->getBondByPeerId(wantp); + } + _peerToJson(out, &(pl->peers[i]), bond, (_tcpFallbackTunnel != (TcpConnection*)0)); + break; + } + } + _node->freeQueryResult((void*)pl); + setContent(req, res, out.dump()); + }; + _controlPlane.Get(peerPath, peerGet); + _controlPlaneV6.Get(peerPath, peerGet); - auto statusGet = [&, setContent](const httplib::Request &req, httplib::Response &res) { + auto statusGet = [&, setContent](const httplib::Request& req, httplib::Response& res) { ZT_NodeStatus status; _node->status(&status); auto out = json::object(); char tmp[256] = {}; - OSUtils::ztsnprintf(tmp,sizeof(tmp),"%.10llx",status.address); + OSUtils::ztsnprintf(tmp, sizeof(tmp), "%.10llx", status.address); out["address"] = tmp; out["publicIdentity"] = status.publicIdentity; out["online"] = (bool)(status.online != 0); - out["tcpFallbackActive"] = (_tcpFallbackTunnel != (TcpConnection *)0); + out["tcpFallbackActive"] = (_tcpFallbackTunnel != (TcpConnection*)0); out["versionMajor"] = ZEROTIER_ONE_VERSION_MAJOR; out["versionMinor"] = ZEROTIER_ONE_VERSION_MINOR; out["versionRev"] = ZEROTIER_ONE_VERSION_REVISION; out["versionBuild"] = ZEROTIER_ONE_VERSION_BUILD; - OSUtils::ztsnprintf(tmp,sizeof(tmp),"%d.%d.%d",ZEROTIER_ONE_VERSION_MAJOR,ZEROTIER_ONE_VERSION_MINOR,ZEROTIER_ONE_VERSION_REVISION); + OSUtils::ztsnprintf(tmp, sizeof(tmp), "%d.%d.%d", ZEROTIER_ONE_VERSION_MAJOR, ZEROTIER_ONE_VERSION_MINOR, ZEROTIER_ONE_VERSION_REVISION); out["version"] = tmp; out["clock"] = OSUtils::now(); @@ -2186,12 +2228,12 @@ public: Mutex::Lock _l(_localConfig_m); out["config"] = _localConfig; } - json &settings = out["config"]["settings"]; - settings["allowTcpFallbackRelay"] = OSUtils::jsonBool(settings["allowTcpFallbackRelay"],_allowTcpFallbackRelay); - settings["forceTcpRelay"] = OSUtils::jsonBool(settings["forceTcpRelay"],_forceTcpRelay); - settings["primaryPort"] = OSUtils::jsonInt(settings["primaryPort"],(uint64_t)_primaryPort) & 0xffff; - settings["secondaryPort"] = OSUtils::jsonInt(settings["secondaryPort"],(uint64_t)_ports[1]) & 0xffff; - settings["tertiaryPort"] = OSUtils::jsonInt(settings["tertiaryPort"],(uint64_t)_tertiaryPort) & 0xffff; + json& settings = out["config"]["settings"]; + settings["allowTcpFallbackRelay"] = OSUtils::jsonBool(settings["allowTcpFallbackRelay"], _allowTcpFallbackRelay); + settings["forceTcpRelay"] = OSUtils::jsonBool(settings["forceTcpRelay"], _forceTcpRelay); + settings["primaryPort"] = OSUtils::jsonInt(settings["primaryPort"], (uint64_t)_primaryPort) & 0xffff; + settings["secondaryPort"] = OSUtils::jsonInt(settings["secondaryPort"], (uint64_t)_ports[1]) & 0xffff; + settings["tertiaryPort"] = OSUtils::jsonInt(settings["tertiaryPort"], (uint64_t)_tertiaryPort) & 0xffff; settings["homeDir"] = _homePath; // Enumerate all local address/port pairs that this node is listening on std::vector boundAddrs(_binder.allBoundLocalInterfaceAddresses()); @@ -2213,29 +2255,29 @@ public: settings["surfaceAddresses"] = surfaceAddrArray; #ifdef ZT_USE_MINIUPNPC - settings["portMappingEnabled"] = OSUtils::jsonBool(settings["portMappingEnabled"],true); + settings["portMappingEnabled"] = OSUtils::jsonBool(settings["portMappingEnabled"], true); #else - settings["portMappingEnabled"] = false; // not supported in build + settings["portMappingEnabled"] = false; // not supported in build #endif #ifndef ZT_SDK - settings["softwareUpdate"] = OSUtils::jsonString(settings["softwareUpdate"],ZT_SOFTWARE_UPDATE_DEFAULT); - settings["softwareUpdateChannel"] = OSUtils::jsonString(settings["softwareUpdateChannel"],ZT_SOFTWARE_UPDATE_DEFAULT_CHANNEL); + settings["softwareUpdate"] = OSUtils::jsonString(settings["softwareUpdate"], ZT_SOFTWARE_UPDATE_DEFAULT); + settings["softwareUpdateChannel"] = OSUtils::jsonString(settings["softwareUpdateChannel"], ZT_SOFTWARE_UPDATE_DEFAULT_CHANNEL); #endif const World planet(_node->planet()); out["planetWorldId"] = planet.id(); out["planetWorldTimestamp"] = planet.timestamp(); - setContent(req, res, out.dump()); + setContent(req, res, out.dump()); }; - _controlPlane.Get(statusPath, statusGet); - _controlPlaneV6.Get(statusPath, statusGet); + _controlPlane.Get(statusPath, statusGet); + _controlPlaneV6.Get(statusPath, statusGet); #if ZT_SSO_ENABLED - std::string ssoPath = "/sso"; - auto ssoGet = [this](const httplib::Request &req, httplib::Response &res) { + std::string ssoPath = "/sso"; + auto ssoGet = [this](const httplib::Request& req, httplib::Response& res) { std::string htmlTemplatePath = _homePath + ZT_PATH_SEPARATOR + "sso-auth.template.html"; std::string htmlTemplate; - if (!OSUtils::readFile(htmlTemplatePath.c_str(), htmlTemplate)) { + if (! OSUtils::readFile(htmlTemplatePath.c_str(), htmlTemplate)) { htmlTemplate = ssoResponseTemplate; } @@ -2243,7 +2285,6 @@ public: std::string responseBody = ""; json outData; - if (req.has_param("error")) { std::string error = req.get_param_value("error"); std::string desc = req.get_param_value("error_description"); @@ -2272,7 +2313,7 @@ public: if (_nets.find(id) != _nets.end()) { NetworkState& ns = _nets[id]; std::string code = req.get_param_value("code"); - char *ret = ns.doTokenExchange(code.c_str()); + char* ret = ns.doTokenExchange(code.c_str()); json ssoResult = json::parse(ret); if (ssoResult.is_object()) { if (ssoResult.contains("errorMessage")) { @@ -2281,13 +2322,15 @@ public: responseBody = inja::render(htmlTemplate, outData); res.set_content(responseBody, responseContentType); res.status = 500; - } else { + } + else { outData["isError"] = false; outData["messageText"] = "Authentication Successful. You may now access the network."; responseBody = inja::render(htmlTemplate, outData); res.set_content(responseBody, responseContentType); } - } else { + } + else { // not an object? We got a problem outData["isError"] = true; outData["messageText"] = "ERROR: Unkown SSO response. Please contact your administrator."; @@ -2300,1710 +2343,1769 @@ public: } }; _controlPlane.Get(ssoPath, ssoGet); - _controlPlaneV6.Get(ssoPath, ssoGet); + _controlPlaneV6.Get(ssoPath, ssoGet); #endif - auto metricsGet = [this](const httplib::Request &req, httplib::Response &res) { + auto metricsGet = [this](const httplib::Request& req, httplib::Response& res) { std::string statspath = _homePath + ZT_PATH_SEPARATOR + "metrics.prom"; std::string metrics; if (OSUtils::readFile(statspath.c_str(), metrics)) { res.set_content(metrics, "text/plain"); - } else { + } + else { res.set_content("{}", "application/json"); res.status = 500; } }; _controlPlane.Get(metricsPath, metricsGet); - _controlPlaneV6.Get(metricsPath, metricsGet); + _controlPlaneV6.Get(metricsPath, metricsGet); - auto exceptionHandler = [&, setContent](const httplib::Request &req, httplib::Response &res, std::exception_ptr ep) { - char buf[1024]; - auto fmt = "{\"error\": %d, \"description\": \"%s\"}"; - try { - std::rethrow_exception(ep); - } catch (std::exception &e) { - snprintf(buf, sizeof(buf), fmt, 500, e.what()); - } catch (...) { - snprintf(buf, sizeof(buf), fmt, 500, "Unknown Exception"); - } - setContent(req, res, buf); - res.status = 500; - }; - _controlPlane.set_exception_handler(exceptionHandler); - _controlPlaneV6.set_exception_handler(exceptionHandler); + auto exceptionHandler = [&, setContent](const httplib::Request& req, httplib::Response& res, std::exception_ptr ep) { + char buf[1024]; + auto fmt = "{\"error\": %d, \"description\": \"%s\"}"; + try { + std::rethrow_exception(ep); + } + catch (std::exception& e) { + snprintf(buf, sizeof(buf), fmt, 500, e.what()); + } + catch (...) { + snprintf(buf, sizeof(buf), fmt, 500, "Unknown Exception"); + } + setContent(req, res, buf); + res.status = 500; + }; + _controlPlane.set_exception_handler(exceptionHandler); + _controlPlaneV6.set_exception_handler(exceptionHandler); - if (_controller) { - _controller->configureHTTPControlPlane(_controlPlane, _controlPlaneV6, setContent); - } + if (_controller) { + _controller->configureHTTPControlPlane(_controlPlane, _controlPlaneV6, setContent); + } - _controlPlane.set_pre_routing_handler(authCheck); - _controlPlaneV6.set_pre_routing_handler(authCheck); + _controlPlane.set_pre_routing_handler(authCheck); + _controlPlaneV6.set_pre_routing_handler(authCheck); -#if ZT_DEBUG==1 - _controlPlane.set_logger([](const httplib::Request &req, const httplib::Response &res) { - fprintf(stderr, "%s", http_log(req, res).c_str()); - }); - _controlPlaneV6.set_logger([](const httplib::Request &req, const httplib::Response &res) { - fprintf(stderr, "%s", http_log(req, res).c_str()); - }); +#if ZT_DEBUG == 1 + _controlPlane.set_logger([](const httplib::Request& req, const httplib::Response& res) { fprintf(stderr, "%s", http_log(req, res).c_str()); }); + _controlPlaneV6.set_logger([](const httplib::Request& req, const httplib::Response& res) { fprintf(stderr, "%s", http_log(req, res).c_str()); }); #endif - if (_primaryPort==0) { - fprintf(stderr, "unable to determine local control port"); - exit(-1); - } + if (_primaryPort == 0) { + fprintf(stderr, "unable to determine local control port"); + exit(-1); + } - bool v4controlPlaneBound = false; - _controlPlane.set_address_family(AF_INET); - if(_controlPlane.bind_to_port("0.0.0.0", _primaryPort)) { - _serverThread = std::thread([&] { - _serverThreadRunning = true; - fprintf(stderr, "Starting Control Plane...\n"); - if(!_controlPlane.listen_after_bind()) { - fprintf(stderr, "Error on listen_after_bind()\n"); - } - fprintf(stderr, "Control Plane Stopped\n"); - _serverThreadRunning = false; - }); - v4controlPlaneBound = true; - } else { - fprintf(stderr, "Error binding control plane to 0.0.0.0:%d\n", _primaryPort); - v4controlPlaneBound = false; - } + bool v4controlPlaneBound = false; + _controlPlane.set_address_family(AF_INET); + if (_controlPlane.bind_to_port("0.0.0.0", _primaryPort)) { + _serverThread = std::thread([&] { + _serverThreadRunning = true; + fprintf(stderr, "Starting Control Plane...\n"); + if (! _controlPlane.listen_after_bind()) { + fprintf(stderr, "Error on listen_after_bind()\n"); + } + fprintf(stderr, "Control Plane Stopped\n"); + _serverThreadRunning = false; + }); + v4controlPlaneBound = true; + } + else { + fprintf(stderr, "Error binding control plane to 0.0.0.0:%d\n", _primaryPort); + v4controlPlaneBound = false; + } - bool v6controlPlaneBound = false; - _controlPlaneV6.set_address_family(AF_INET6); - if(_controlPlaneV6.bind_to_port("::", _primaryPort)) { - _serverThreadV6 = std::thread([&] { - _serverThreadRunningV6 = true; - fprintf(stderr, "Starting V6 Control Plane...\n"); - if(!_controlPlaneV6.listen_after_bind()) { - fprintf(stderr, "Error on V6 listen_after_bind()\n"); - } - fprintf(stderr, "V6 Control Plane Stopped\n"); - _serverThreadRunningV6 = false; - }); - v6controlPlaneBound = true; - } else { - fprintf(stderr, "Error binding control plane to [::]:%d\n", _primaryPort); - v6controlPlaneBound = false; - } + bool v6controlPlaneBound = false; + _controlPlaneV6.set_address_family(AF_INET6); + if (_controlPlaneV6.bind_to_port("::", _primaryPort)) { + _serverThreadV6 = std::thread([&] { + _serverThreadRunningV6 = true; + fprintf(stderr, "Starting V6 Control Plane...\n"); + if (! _controlPlaneV6.listen_after_bind()) { + fprintf(stderr, "Error on V6 listen_after_bind()\n"); + } + fprintf(stderr, "V6 Control Plane Stopped\n"); + _serverThreadRunningV6 = false; + }); + v6controlPlaneBound = true; + } + else { + fprintf(stderr, "Error binding control plane to [::]:%d\n", _primaryPort); + v6controlPlaneBound = false; + } - if (!v4controlPlaneBound && !v6controlPlaneBound) { - fprintf(stderr, "ERROR: Could not bind control plane. Exiting...\n"); - exit(-1); - } + if (! v4controlPlaneBound && ! v6controlPlaneBound) { + fprintf(stderr, "ERROR: Could not bind control plane. Exiting...\n"); + exit(-1); + } } - // Must be called after _localConfig is read or modified - void applyLocalConfig() - { - Mutex::Lock _l(_localConfig_m); - json lc(_localConfig); + // Must be called after _localConfig is read or modified + void applyLocalConfig() + { + Mutex::Lock _l(_localConfig_m); + json lc(_localConfig); - _v4Hints.clear(); - _v6Hints.clear(); - _v4Blacklists.clear(); - _v6Blacklists.clear(); - json &virt = lc["virtual"]; - if (virt.is_object()) { - for(json::iterator v(virt.begin());v!=virt.end();++v) { - const std::string nstr = v.key(); - if ((nstr.length() == ZT_ADDRESS_LENGTH_HEX)&&(v.value().is_object())) { - const Address ztaddr(Utils::hexStrToU64(nstr.c_str())); - if (ztaddr) { - const uint64_t ztaddr2 = ztaddr.toInt(); - std::vector &v4h = _v4Hints[ztaddr2]; - std::vector &v6h = _v6Hints[ztaddr2]; - std::vector &v4b = _v4Blacklists[ztaddr2]; - std::vector &v6b = _v6Blacklists[ztaddr2]; + _v4Hints.clear(); + _v6Hints.clear(); + _v4Blacklists.clear(); + _v6Blacklists.clear(); + json& virt = lc["virtual"]; + if (virt.is_object()) { + for (json::iterator v(virt.begin()); v != virt.end(); ++v) { + const std::string nstr = v.key(); + if ((nstr.length() == ZT_ADDRESS_LENGTH_HEX) && (v.value().is_object())) { + const Address ztaddr(Utils::hexStrToU64(nstr.c_str())); + if (ztaddr) { + const uint64_t ztaddr2 = ztaddr.toInt(); + std::vector& v4h = _v4Hints[ztaddr2]; + std::vector& v6h = _v6Hints[ztaddr2]; + std::vector& v4b = _v4Blacklists[ztaddr2]; + std::vector& v6b = _v6Blacklists[ztaddr2]; - json &tryAddrs = v.value()["try"]; - if (tryAddrs.is_array()) { - for(unsigned long i=0;i 0)) { - if (phy.value().is_object()) { - if (OSUtils::jsonBool(phy.value()["blacklist"],false)) { - if (net.ss_family == AF_INET) - _globalV4Blacklist.push_back(net); - else if (net.ss_family == AF_INET6) - _globalV6Blacklist.push_back(net); - } - } - } - } - } + _globalV4Blacklist.clear(); + _globalV6Blacklist.clear(); + json& physical = lc["physical"]; + if (physical.is_object()) { + for (json::iterator phy(physical.begin()); phy != physical.end(); ++phy) { + const InetAddress net(OSUtils::jsonString(phy.key(), "").c_str()); + if ((net) && (net.netmaskBits() > 0)) { + if (phy.value().is_object()) { + if (OSUtils::jsonBool(phy.value()["blacklist"], false)) { + if (net.ss_family == AF_INET) + _globalV4Blacklist.push_back(net); + else if (net.ss_family == AF_INET6) + _globalV6Blacklist.push_back(net); + } + } + } + } + } - _allowManagementFrom.clear(); - _interfacePrefixBlacklist.clear(); + _allowManagementFrom.clear(); + _interfacePrefixBlacklist.clear(); - json &settings = lc["settings"]; + json& settings = lc["settings"]; - if (!_node->bondController()->inUse()) { - _node->bondController()->setBinder(&_binder); - // defaultBondingPolicy - std::string defaultBondingPolicyStr(OSUtils::jsonString(settings["defaultBondingPolicy"],"")); - int defaultBondingPolicy = _node->bondController()->getPolicyCodeByStr(defaultBondingPolicyStr); - _node->bondController()->setBondingLayerDefaultPolicy(defaultBondingPolicy); - _node->bondController()->setBondingLayerDefaultPolicyStr(defaultBondingPolicyStr); // Used if custom policy - // Custom Policies - json &customBondingPolicies = settings["policies"]; - for (json::iterator policyItr = customBondingPolicies.begin(); policyItr != customBondingPolicies.end();++policyItr) { - // Custom Policy - std::string customPolicyStr(policyItr.key()); - json &customPolicy = policyItr.value(); - std::string basePolicyStr(OSUtils::jsonString(customPolicy["basePolicy"],"")); - if (basePolicyStr.empty()) { - fprintf(stderr, "error: no base policy was specified for custom policy (%s)\n", customPolicyStr.c_str()); - } - int basePolicyCode = _node->bondController()->getPolicyCodeByStr(basePolicyStr); - if (basePolicyCode == ZT_BOND_POLICY_NONE) { - fprintf(stderr, "error: custom policy (%s) is invalid, unknown base policy (%s).\n", - customPolicyStr.c_str(), basePolicyStr.c_str()); - continue; - } if (_node->bondController()->getPolicyCodeByStr(customPolicyStr) != ZT_BOND_POLICY_NONE) { - fprintf(stderr, "error: custom policy (%s) will be ignored, cannot use standard policy names for custom policies.\n", - customPolicyStr.c_str()); - continue; - } - // New bond, used as a copy template for new instances - SharedPtr newTemplateBond = new Bond(NULL, basePolicyStr, customPolicyStr, SharedPtr()); - newTemplateBond->setPolicy(basePolicyCode); - // Custom link quality spec - json &linkQualitySpec = customPolicy["linkQuality"]; - if (linkQualitySpec.size() == ZT_QOS_PARAMETER_SIZE) { - float weights[ZT_QOS_PARAMETER_SIZE] = {}; - weights[ZT_QOS_LAT_MAX_IDX] = (float)OSUtils::jsonDouble(linkQualitySpec["lat_max"],0.0); - weights[ZT_QOS_PDV_MAX_IDX] = (float)OSUtils::jsonDouble(linkQualitySpec["pdv_max"],0.0); - weights[ZT_QOS_PLR_MAX_IDX] = (float)OSUtils::jsonDouble(linkQualitySpec["plr_max"],0.0); - weights[ZT_QOS_PER_MAX_IDX] = (float)OSUtils::jsonDouble(linkQualitySpec["per_max"],0.0); - weights[ZT_QOS_LAT_WEIGHT_IDX] = (float)OSUtils::jsonDouble(linkQualitySpec["lat_weight"],0.0); - weights[ZT_QOS_PDV_WEIGHT_IDX] = (float)OSUtils::jsonDouble(linkQualitySpec["pdv_weight"],0.0); - weights[ZT_QOS_PLR_WEIGHT_IDX] = (float)OSUtils::jsonDouble(linkQualitySpec["plr_weight"],0.0); - weights[ZT_QOS_PER_WEIGHT_IDX] = (float)OSUtils::jsonDouble(linkQualitySpec["per_weight"],0.0); - newTemplateBond->setUserLinkQualitySpec(weights,ZT_QOS_PARAMETER_SIZE); - } - // Bond-specific properties - newTemplateBond->setUpDelay(OSUtils::jsonInt(customPolicy["upDelay"],-1)); - newTemplateBond->setDownDelay(OSUtils::jsonInt(customPolicy["downDelay"],-1)); - newTemplateBond->setFailoverInterval(OSUtils::jsonInt(customPolicy["failoverInterval"],ZT_BOND_FAILOVER_DEFAULT_INTERVAL)); - newTemplateBond->setPacketsPerLink(OSUtils::jsonInt(customPolicy["packetsPerLink"],-1)); + if (! _node->bondController()->inUse()) { + _node->bondController()->setBinder(&_binder); + // defaultBondingPolicy + std::string defaultBondingPolicyStr(OSUtils::jsonString(settings["defaultBondingPolicy"], "")); + int defaultBondingPolicy = _node->bondController()->getPolicyCodeByStr(defaultBondingPolicyStr); + _node->bondController()->setBondingLayerDefaultPolicy(defaultBondingPolicy); + _node->bondController()->setBondingLayerDefaultPolicyStr(defaultBondingPolicyStr); // Used if custom policy + // Custom Policies + json& customBondingPolicies = settings["policies"]; + for (json::iterator policyItr = customBondingPolicies.begin(); policyItr != customBondingPolicies.end(); ++policyItr) { + // Custom Policy + std::string customPolicyStr(policyItr.key()); + json& customPolicy = policyItr.value(); + std::string basePolicyStr(OSUtils::jsonString(customPolicy["basePolicy"], "")); + if (basePolicyStr.empty()) { + fprintf(stderr, "error: no base policy was specified for custom policy (%s)\n", customPolicyStr.c_str()); + } + int basePolicyCode = _node->bondController()->getPolicyCodeByStr(basePolicyStr); + if (basePolicyCode == ZT_BOND_POLICY_NONE) { + fprintf(stderr, "error: custom policy (%s) is invalid, unknown base policy (%s).\n", customPolicyStr.c_str(), basePolicyStr.c_str()); + continue; + } + if (_node->bondController()->getPolicyCodeByStr(customPolicyStr) != ZT_BOND_POLICY_NONE) { + fprintf(stderr, "error: custom policy (%s) will be ignored, cannot use standard policy names for custom policies.\n", customPolicyStr.c_str()); + continue; + } + // New bond, used as a copy template for new instances + SharedPtr newTemplateBond = new Bond(NULL, basePolicyStr, customPolicyStr, SharedPtr()); + newTemplateBond->setPolicy(basePolicyCode); + // Custom link quality spec + json& linkQualitySpec = customPolicy["linkQuality"]; + if (linkQualitySpec.size() == ZT_QOS_PARAMETER_SIZE) { + float weights[ZT_QOS_PARAMETER_SIZE] = {}; + weights[ZT_QOS_LAT_MAX_IDX] = (float)OSUtils::jsonDouble(linkQualitySpec["lat_max"], 0.0); + weights[ZT_QOS_PDV_MAX_IDX] = (float)OSUtils::jsonDouble(linkQualitySpec["pdv_max"], 0.0); + weights[ZT_QOS_PLR_MAX_IDX] = (float)OSUtils::jsonDouble(linkQualitySpec["plr_max"], 0.0); + weights[ZT_QOS_PER_MAX_IDX] = (float)OSUtils::jsonDouble(linkQualitySpec["per_max"], 0.0); + weights[ZT_QOS_LAT_WEIGHT_IDX] = (float)OSUtils::jsonDouble(linkQualitySpec["lat_weight"], 0.0); + weights[ZT_QOS_PDV_WEIGHT_IDX] = (float)OSUtils::jsonDouble(linkQualitySpec["pdv_weight"], 0.0); + weights[ZT_QOS_PLR_WEIGHT_IDX] = (float)OSUtils::jsonDouble(linkQualitySpec["plr_weight"], 0.0); + weights[ZT_QOS_PER_WEIGHT_IDX] = (float)OSUtils::jsonDouble(linkQualitySpec["per_weight"], 0.0); + newTemplateBond->setUserLinkQualitySpec(weights, ZT_QOS_PARAMETER_SIZE); + } + // Bond-specific properties + newTemplateBond->setUpDelay(OSUtils::jsonInt(customPolicy["upDelay"], -1)); + newTemplateBond->setDownDelay(OSUtils::jsonInt(customPolicy["downDelay"], -1)); + newTemplateBond->setFailoverInterval(OSUtils::jsonInt(customPolicy["failoverInterval"], ZT_BOND_FAILOVER_DEFAULT_INTERVAL)); + newTemplateBond->setPacketsPerLink(OSUtils::jsonInt(customPolicy["packetsPerLink"], -1)); - // Policy-Specific link set - json &links = customPolicy["links"]; - for (json::iterator linkItr = links.begin(); linkItr != links.end();++linkItr) { - std::string linkNameStr(linkItr.key()); - json &link = linkItr.value(); - bool enabled = OSUtils::jsonInt(link["enabled"],true); - uint32_t capacity = OSUtils::jsonInt(link["capacity"],0); - uint8_t ipvPref = OSUtils::jsonInt(link["ipvPref"],0); - uint16_t mtu = OSUtils::jsonInt(link["mtu"],0); - std::string failoverToStr(OSUtils::jsonString(link["failoverTo"],"")); - // Mode - std::string linkModeStr(OSUtils::jsonString(link["mode"],"spare")); - uint8_t linkMode = ZT_BOND_SLAVE_MODE_SPARE; - if (linkModeStr == "primary") { linkMode = ZT_BOND_SLAVE_MODE_PRIMARY; } - if (linkModeStr == "spare") { linkMode = ZT_BOND_SLAVE_MODE_SPARE; } - // ipvPref - if ((ipvPref != 0) && (ipvPref != 4) && (ipvPref != 6) && (ipvPref != 46) && (ipvPref != 64)) { - fprintf(stderr, "error: invalid ipvPref value (%d), link disabled.\n", ipvPref); - enabled = false; - } - if (linkMode == ZT_BOND_SLAVE_MODE_SPARE && failoverToStr.length()) { - fprintf(stderr, "error: cannot specify failover links for spares, link disabled.\n"); - failoverToStr = ""; - enabled = false; - } - _node->bondController()->addCustomLink(customPolicyStr, new Link(linkNameStr,ipvPref,mtu,capacity,enabled,linkMode,failoverToStr)); - } - std::string linkSelectMethodStr(OSUtils::jsonString(customPolicy["activeReselect"],"always")); - if (linkSelectMethodStr == "always") { - newTemplateBond->setLinkSelectMethod(ZT_BOND_RESELECTION_POLICY_ALWAYS); - } - if (linkSelectMethodStr == "better") { - newTemplateBond->setLinkSelectMethod(ZT_BOND_RESELECTION_POLICY_BETTER); - } - if (linkSelectMethodStr == "failure") { - newTemplateBond->setLinkSelectMethod(ZT_BOND_RESELECTION_POLICY_FAILURE); - } - if (linkSelectMethodStr == "optimize") { - newTemplateBond->setLinkSelectMethod(ZT_BOND_RESELECTION_POLICY_OPTIMIZE); - } - if (newTemplateBond->getLinkSelectMethod() < 0 || newTemplateBond->getLinkSelectMethod() > 3) { - fprintf(stderr, "warning: invalid value (%s) for linkSelectMethod, assuming mode: always\n", linkSelectMethodStr.c_str()); - } - if (!_node->bondController()->addCustomPolicy(newTemplateBond)) { - fprintf(stderr, "error: a custom policy of this name (%s) already exists.\n", customPolicyStr.c_str()); - } - } - // Peer-specific bonding - json &peerSpecificBonds = settings["peerSpecificBonds"]; - for (json::iterator peerItr = peerSpecificBonds.begin(); peerItr != peerSpecificBonds.end();++peerItr) { - _node->bondController()->assignBondingPolicyToPeer(std::stoull(peerItr.key(),0,16), peerItr.value()); - } - // Check settings - if (defaultBondingPolicyStr.length() && !defaultBondingPolicy && !_node->bondController()->inUse()) { - fprintf(stderr, "error: unknown policy (%s) specified by defaultBondingPolicy, bond disabled.\n", defaultBondingPolicyStr.c_str()); - } - } + // Policy-Specific link set + json& links = customPolicy["links"]; + for (json::iterator linkItr = links.begin(); linkItr != links.end(); ++linkItr) { + std::string linkNameStr(linkItr.key()); + json& link = linkItr.value(); + bool enabled = OSUtils::jsonInt(link["enabled"], true); + uint32_t capacity = OSUtils::jsonInt(link["capacity"], 0); + uint8_t ipvPref = OSUtils::jsonInt(link["ipvPref"], 0); + uint16_t mtu = OSUtils::jsonInt(link["mtu"], 0); + std::string failoverToStr(OSUtils::jsonString(link["failoverTo"], "")); + // Mode + std::string linkModeStr(OSUtils::jsonString(link["mode"], "spare")); + uint8_t linkMode = ZT_BOND_SLAVE_MODE_SPARE; + if (linkModeStr == "primary") { + linkMode = ZT_BOND_SLAVE_MODE_PRIMARY; + } + if (linkModeStr == "spare") { + linkMode = ZT_BOND_SLAVE_MODE_SPARE; + } + // ipvPref + if ((ipvPref != 0) && (ipvPref != 4) && (ipvPref != 6) && (ipvPref != 46) && (ipvPref != 64)) { + fprintf(stderr, "error: invalid ipvPref value (%d), link disabled.\n", ipvPref); + enabled = false; + } + if (linkMode == ZT_BOND_SLAVE_MODE_SPARE && failoverToStr.length()) { + fprintf(stderr, "error: cannot specify failover links for spares, link disabled.\n"); + failoverToStr = ""; + enabled = false; + } + _node->bondController()->addCustomLink(customPolicyStr, new Link(linkNameStr, ipvPref, mtu, capacity, enabled, linkMode, failoverToStr)); + } + std::string linkSelectMethodStr(OSUtils::jsonString(customPolicy["activeReselect"], "always")); + if (linkSelectMethodStr == "always") { + newTemplateBond->setLinkSelectMethod(ZT_BOND_RESELECTION_POLICY_ALWAYS); + } + if (linkSelectMethodStr == "better") { + newTemplateBond->setLinkSelectMethod(ZT_BOND_RESELECTION_POLICY_BETTER); + } + if (linkSelectMethodStr == "failure") { + newTemplateBond->setLinkSelectMethod(ZT_BOND_RESELECTION_POLICY_FAILURE); + } + if (linkSelectMethodStr == "optimize") { + newTemplateBond->setLinkSelectMethod(ZT_BOND_RESELECTION_POLICY_OPTIMIZE); + } + if (newTemplateBond->getLinkSelectMethod() < 0 || newTemplateBond->getLinkSelectMethod() > 3) { + fprintf(stderr, "warning: invalid value (%s) for linkSelectMethod, assuming mode: always\n", linkSelectMethodStr.c_str()); + } + if (! _node->bondController()->addCustomPolicy(newTemplateBond)) { + fprintf(stderr, "error: a custom policy of this name (%s) already exists.\n", customPolicyStr.c_str()); + } + } + // Peer-specific bonding + json& peerSpecificBonds = settings["peerSpecificBonds"]; + for (json::iterator peerItr = peerSpecificBonds.begin(); peerItr != peerSpecificBonds.end(); ++peerItr) { + _node->bondController()->assignBondingPolicyToPeer(std::stoull(peerItr.key(), 0, 16), peerItr.value()); + } + // Check settings + if (defaultBondingPolicyStr.length() && ! defaultBondingPolicy && ! _node->bondController()->inUse()) { + fprintf(stderr, "error: unknown policy (%s) specified by defaultBondingPolicy, bond disabled.\n", defaultBondingPolicyStr.c_str()); + } + } - // bondingPolicy cannot be used with allowTcpFallbackRelay - bool _forceTcpRelayTmp = (OSUtils::jsonBool(settings["forceTcpRelay"],false)); - bool _bondInUse = _node->bondController()->inUse(); - if (_forceTcpRelayTmp && _bondInUse) { - fprintf(stderr, "Warning: forceTcpRelay cannot be used with multipath. Disabling forceTcpRelay\n"); - } - _allowTcpFallbackRelay = (OSUtils::jsonBool(settings["allowTcpFallbackRelay"],true) && !_node->bondController()->inUse()); - _forceTcpRelay = (_forceTcpRelayTmp && !_node->bondController()->inUse()); - _enableWebServer = (OSUtils::jsonBool(settings["enableWebServer"],false)); + // bondingPolicy cannot be used with allowTcpFallbackRelay + bool _forceTcpRelayTmp = (OSUtils::jsonBool(settings["forceTcpRelay"], false)); + bool _bondInUse = _node->bondController()->inUse(); + if (_forceTcpRelayTmp && _bondInUse) { + fprintf(stderr, "Warning: forceTcpRelay cannot be used with multipath. Disabling forceTcpRelay\n"); + } + _allowTcpFallbackRelay = (OSUtils::jsonBool(settings["allowTcpFallbackRelay"], true) && ! _node->bondController()->inUse()); + _forceTcpRelay = (_forceTcpRelayTmp && ! _node->bondController()->inUse()); + _enableWebServer = (OSUtils::jsonBool(settings["enableWebServer"], false)); #ifdef ZT_TCP_FALLBACK_RELAY - _fallbackRelayAddress = InetAddress(OSUtils::jsonString(settings["tcpFallbackRelay"], ZT_TCP_FALLBACK_RELAY).c_str()); + _fallbackRelayAddress = InetAddress(OSUtils::jsonString(settings["tcpFallbackRelay"], ZT_TCP_FALLBACK_RELAY).c_str()); #endif - _primaryPort = (unsigned int)OSUtils::jsonInt(settings["primaryPort"],(uint64_t)_primaryPort) & 0xffff; - _allowSecondaryPort = OSUtils::jsonBool(settings["allowSecondaryPort"],true); - _secondaryPort = (unsigned int)OSUtils::jsonInt(settings["secondaryPort"],0); - _tertiaryPort = (unsigned int)OSUtils::jsonInt(settings["tertiaryPort"],0); - if (_secondaryPort != 0 || _tertiaryPort != 0) { - fprintf(stderr,"WARNING: using manually-specified secondary and/or tertiary ports. This can cause NAT issues." ZT_EOL_S); - } - _portMappingEnabled = OSUtils::jsonBool(settings["portMappingEnabled"],true); + _primaryPort = (unsigned int)OSUtils::jsonInt(settings["primaryPort"], (uint64_t)_primaryPort) & 0xffff; + _allowSecondaryPort = OSUtils::jsonBool(settings["allowSecondaryPort"], true); + _secondaryPort = (unsigned int)OSUtils::jsonInt(settings["secondaryPort"], 0); + _tertiaryPort = (unsigned int)OSUtils::jsonInt(settings["tertiaryPort"], 0); + if (_secondaryPort != 0 || _tertiaryPort != 0) { + fprintf(stderr, "WARNING: using manually-specified secondary and/or tertiary ports. This can cause NAT issues." ZT_EOL_S); + } + _portMappingEnabled = OSUtils::jsonBool(settings["portMappingEnabled"], true); + _node->setLowBandwidthMode(OSUtils::jsonBool(settings["lowBandwidthMode"], false)); #if defined(__LINUX__) || defined(__FreeBSD__) - _multicoreEnabled = OSUtils::jsonBool(settings["multicoreEnabled"],false); - _concurrency = OSUtils::jsonInt(settings["concurrency"],1); - _cpuPinningEnabled = OSUtils::jsonBool(settings["cpuPinningEnabled"],false); - if (_multicoreEnabled) { - unsigned int maxConcurrency = std::thread::hardware_concurrency(); - if (_concurrency <= 1 || _concurrency >= maxConcurrency) { - unsigned int conservativeDefault = (std::thread::hardware_concurrency() >= 4 ? 2 : 1); - fprintf(stderr, "Concurrency level provided (%d) is invalid, assigning conservative default value of (%d)\n", _concurrency, conservativeDefault); - _concurrency = conservativeDefault; - } - setUpMultithreading(); - } - else { - // Force values in case the user accidentally defined them with multicore disabled - _concurrency = 1; - _cpuPinningEnabled = false; - } + _multicoreEnabled = OSUtils::jsonBool(settings["multicoreEnabled"], false); + _concurrency = OSUtils::jsonInt(settings["concurrency"], 1); + _cpuPinningEnabled = OSUtils::jsonBool(settings["cpuPinningEnabled"], false); + if (_multicoreEnabled) { + unsigned int maxConcurrency = std::thread::hardware_concurrency(); + if (_concurrency <= 1 || _concurrency >= maxConcurrency) { + unsigned int conservativeDefault = (std::thread::hardware_concurrency() >= 4 ? 2 : 1); + fprintf(stderr, "Concurrency level provided (%d) is invalid, assigning conservative default value of (%d)\n", _concurrency, conservativeDefault); + _concurrency = conservativeDefault; + } + setUpMultithreading(); + } + else { + // Force values in case the user accidentally defined them with multicore disabled + _concurrency = 1; + _cpuPinningEnabled = false; + } #else - _multicoreEnabled = false; - _concurrency = 1; - _cpuPinningEnabled = false; + _multicoreEnabled = false; + _concurrency = 1; + _cpuPinningEnabled = false; #endif #ifndef ZT_SDK - const std::string up(OSUtils::jsonString(settings["softwareUpdate"],ZT_SOFTWARE_UPDATE_DEFAULT)); - const bool udist = OSUtils::jsonBool(settings["softwareUpdateDist"],false); - if (((up == "apply")||(up == "download"))||(udist)) { - if (!_updater) - _updater = new SoftwareUpdater(*_node,_homePath); - _updateAutoApply = (up == "apply"); - _updater->setUpdateDistribution(udist); - _updater->setChannel(OSUtils::jsonString(settings["softwareUpdateChannel"],ZT_SOFTWARE_UPDATE_DEFAULT_CHANNEL)); - } else { - delete _updater; - _updater = (SoftwareUpdater *)0; - _updateAutoApply = false; - } + const std::string up(OSUtils::jsonString(settings["softwareUpdate"], ZT_SOFTWARE_UPDATE_DEFAULT)); + const bool udist = OSUtils::jsonBool(settings["softwareUpdateDist"], false); + if (((up == "apply") || (up == "download")) || (udist)) { + if (! _updater) + _updater = new SoftwareUpdater(*_node, _homePath); + _updateAutoApply = (up == "apply"); + _updater->setUpdateDistribution(udist); + _updater->setChannel(OSUtils::jsonString(settings["softwareUpdateChannel"], ZT_SOFTWARE_UPDATE_DEFAULT_CHANNEL)); + } + else { + delete _updater; + _updater = (SoftwareUpdater*)0; + _updateAutoApply = false; + } #endif - json &ignoreIfs = settings["interfacePrefixBlacklist"]; - if (ignoreIfs.is_array()) { - for(unsigned long i=0;i 0) - _interfacePrefixBlacklist.push_back(tmp); - } - } + json& ignoreIfs = settings["interfacePrefixBlacklist"]; + if (ignoreIfs.is_array()) { + for (unsigned long i = 0; i < ignoreIfs.size(); ++i) { + const std::string tmp(OSUtils::jsonString(ignoreIfs[i], "")); + if (tmp.length() > 0) + _interfacePrefixBlacklist.push_back(tmp); + } + } - json &amf = settings["allowManagementFrom"]; - if (amf.is_array()) { - for(unsigned long i=0;i &ips,const InetAddress &ip) const - { - for(std::set::const_iterator i(ips.begin());i!=ips.end();++i) { - if (i->ipsEqual(ip)) - return true; - } - return false; - } + // Match only an IP from a vector of IPs -- used in syncManagedStuff() + inline bool matchIpOnly(const std::set& ips, const InetAddress& ip) const + { + for (std::set::const_iterator i(ips.begin()); i != ips.end(); ++i) { + if (i->ipsEqual(ip)) + return true; + } + return false; + } - // Apply or update managed IPs for a configured network (be sure n.tap exists) - void syncManagedStuff(NetworkState &n,bool syncIps,bool syncRoutes, bool syncDns) - { - char ipbuf[64]; + // Apply or update managed IPs for a configured network (be sure n.tap exists) + void syncManagedStuff(NetworkState& n, bool syncIps, bool syncRoutes, bool syncDns) + { + char ipbuf[64]; - // assumes _nets_m is locked - if (syncIps) { - std::vector newManagedIps; - newManagedIps.reserve(n.config().assignedAddressCount); + // assumes _nets_m is locked + if (syncIps) { + std::vector newManagedIps; + newManagedIps.reserve(n.config().assignedAddressCount); #ifdef __APPLE__ - std::vector newManagedIps2; - newManagedIps2.reserve(n.config().assignedAddressCount); + std::vector newManagedIps2; + newManagedIps2.reserve(n.config().assignedAddressCount); #endif - for(unsigned int i=0;i(&(n.config().assignedAddresses[i])); - if (checkIfManagedIsAllowed(n,*ii)) - newManagedIps.push_back(*ii); - } - std::sort(newManagedIps.begin(),newManagedIps.end()); - newManagedIps.erase(std::unique(newManagedIps.begin(),newManagedIps.end()),newManagedIps.end()); + for (unsigned int i = 0; i < n.config().assignedAddressCount; ++i) { + const InetAddress* ii = reinterpret_cast(&(n.config().assignedAddresses[i])); + if (checkIfManagedIsAllowed(n, *ii)) + newManagedIps.push_back(*ii); + } + std::sort(newManagedIps.begin(), newManagedIps.end()); + newManagedIps.erase(std::unique(newManagedIps.begin(), newManagedIps.end()), newManagedIps.end()); - for(std::vector::iterator ip(n.managedIps().begin());ip!=n.managedIps().end();++ip) { - if (std::find(newManagedIps.begin(),newManagedIps.end(),*ip) == newManagedIps.end()) { - if (!n.tap()->removeIp(*ip)) - fprintf(stderr,"ERROR: unable to remove ip address %s" ZT_EOL_S, ip->toString(ipbuf)); + for (std::vector::iterator ip(n.managedIps().begin()); ip != n.managedIps().end(); ++ip) { + if (std::find(newManagedIps.begin(), newManagedIps.end(), *ip) == newManagedIps.end()) { + if (! n.tap()->removeIp(*ip)) + fprintf(stderr, "ERROR: unable to remove ip address %s" ZT_EOL_S, ip->toString(ipbuf)); - #ifdef __WINDOWS__ - WinFWHelper::removeICMPRule(*ip, n.config().nwid); - #endif - } - } - - - for(std::vector::iterator ip(newManagedIps.begin());ip!=newManagedIps.end();++ip) { - -#ifdef __APPLE__ - // We can't add multiple addresses to an interface on macOs unless we futz with the netmask. - // see `man ifconfig`, alias section - // "If the address is on the same subnet as the first network address for this interface, a non-conflicting netmask must be given. Usually 0xffffffff is most appropriate." - - auto same_subnet = [ip](InetAddress i){ - return ip->network() == i.network(); - }; -#endif - - if (std::find(n.managedIps().begin(),n.managedIps().end(),*ip) == n.managedIps().end()) { -#ifdef __APPLE__ - // if same subnet as a previously added address - if ( - std::find_if(n.managedIps().begin(),n.managedIps().end(), same_subnet) != n.managedIps().end() || - std::find_if(newManagedIps2.begin(),newManagedIps2.end(), same_subnet) != newManagedIps2.end() - ) { - if (ip->isV4()) { - ip->setPort(32); - } else { - ip->setPort(128); - } - } else { - newManagedIps2.push_back(*ip); - } -#endif - - if (! n.tap()->addIp(*ip)) { - fprintf(stderr, "ERROR: unable to add ip address %s" ZT_EOL_S, ip->toString(ipbuf)); - } - else { #ifdef __WINDOWS__ - WinFWHelper::newICMPRule(*ip, n.config().nwid); + WinFWHelper::removeICMPRule(*ip, n.config().nwid); #endif - } - } - } + } + } + + for (std::vector::iterator ip(newManagedIps.begin()); ip != newManagedIps.end(); ++ip) { +#ifdef __APPLE__ + // We can't add multiple addresses to an interface on macOs unless we futz with the netmask. + // see `man ifconfig`, alias section + // "If the address is on the same subnet as the first network address for this interface, a non-conflicting netmask must be given. Usually 0xffffffff is most appropriate." + + auto same_subnet = [ip](InetAddress i) { return ip->network() == i.network(); }; +#endif + + if (std::find(n.managedIps().begin(), n.managedIps().end(), *ip) == n.managedIps().end()) { +#ifdef __APPLE__ + // if same subnet as a previously added address + if (std::find_if(n.managedIps().begin(), n.managedIps().end(), same_subnet) != n.managedIps().end() || std::find_if(newManagedIps2.begin(), newManagedIps2.end(), same_subnet) != newManagedIps2.end()) { + if (ip->isV4()) { + ip->setPort(32); + } + else { + ip->setPort(128); + } + } + else { + newManagedIps2.push_back(*ip); + } +#endif + + if (! n.tap()->addIp(*ip)) { + fprintf(stderr, "ERROR: unable to add ip address %s" ZT_EOL_S, ip->toString(ipbuf)); + } + else { +#ifdef __WINDOWS__ + WinFWHelper::newICMPRule(*ip, n.config().nwid); +#endif + } + } + } #ifdef __APPLE__ - if (!MacDNSHelper::addIps6(n.config().nwid, n.config().mac, n.tap()->deviceName().c_str(), newManagedIps)) { - fprintf(stderr, "ERROR: unable to add v6 addresses to system configuration" ZT_EOL_S); - } + if (! MacDNSHelper::addIps6(n.config().nwid, n.config().mac, n.tap()->deviceName().c_str(), newManagedIps)) { + fprintf(stderr, "ERROR: unable to add v6 addresses to system configuration" ZT_EOL_S); + } - if (!MacDNSHelper::addIps4(n.config().nwid, n.config().mac, n.tap()->deviceName().c_str(), newManagedIps)) { - fprintf(stderr, "ERROR: unable to add v4 addresses to system configuration" ZT_EOL_S); - } + if (! MacDNSHelper::addIps4(n.config().nwid, n.config().mac, n.tap()->deviceName().c_str(), newManagedIps)) { + fprintf(stderr, "ERROR: unable to add v4 addresses to system configuration" ZT_EOL_S); + } #endif - n.setManagedIps(newManagedIps); - } + n.setManagedIps(newManagedIps); + } - if (syncRoutes) { - // Get tap device name (use LUID in hex on Windows) and IP addresses. -#if defined(__WINDOWS__) && !defined(ZT_SDK) - char tapdevbuf[64]; - OSUtils::ztsnprintf(tapdevbuf,sizeof(tapdevbuf),"%.16llx",(unsigned long long)((WindowsEthernetTap *)(n.tap().get()))->luid().Value); - std::string tapdev(tapdevbuf); + if (syncRoutes) { + // Get tap device name (use LUID in hex on Windows) and IP addresses. +#if defined(__WINDOWS__) && ! defined(ZT_SDK) + char tapdevbuf[64]; + OSUtils::ztsnprintf(tapdevbuf, sizeof(tapdevbuf), "%.16llx", (unsigned long long)((WindowsEthernetTap*)(n.tap().get()))->luid().Value); + std::string tapdev(tapdevbuf); #else - std::string tapdev(n.tap()->deviceName()); + std::string tapdev(n.tap()->deviceName()); #endif - std::vector tapIps(n.tap()->ips()); - std::set myIps(tapIps.begin(), tapIps.end()); - for(unsigned int i=0;i tapIps(n.tap()->ips()); + std::set myIps(tapIps.begin(), tapIps.end()); + for (unsigned int i = 0; i < n.config().assignedAddressCount; ++i) + myIps.insert(InetAddress(n.config().assignedAddresses[i])); - std::set haveRouteTargets; - for(unsigned int i=0;i(&(n.config().routes[i].target)); - const InetAddress *const via = reinterpret_cast(&(n.config().routes[i].via)); + std::set haveRouteTargets; + for (unsigned int i = 0; i < n.config().routeCount; ++i) { + const InetAddress* const target = reinterpret_cast(&(n.config().routes[i].target)); + const InetAddress* const via = reinterpret_cast(&(n.config().routes[i].via)); - // Make sure we are allowed to set this managed route, and that 'via' is not our IP. The latter - // avoids setting routes via the router on the router. - if ( (!checkIfManagedIsAllowed(n,*target)) || ((via->ss_family == target->ss_family)&&(matchIpOnly(myIps,*via))) ) - continue; + // Make sure we are allowed to set this managed route, and that 'via' is not our IP. The latter + // avoids setting routes via the router on the router. + if ((! checkIfManagedIsAllowed(n, *target)) || ((via->ss_family == target->ss_family) && (matchIpOnly(myIps, *via)))) + continue; - // Find an IP on the interface that can be a source IP, abort if no IPs assigned. - const InetAddress *src = nullptr; - unsigned int mostMatchingPrefixBits = 0; - for(std::set::const_iterator i(myIps.begin());i!=myIps.end();++i) { - const unsigned int matchingPrefixBits = i->matchingPrefixBits(*target); - if (matchingPrefixBits >= mostMatchingPrefixBits && ((target->isV4() && i->isV4()) || (target->isV6() && i->isV6()))) { - mostMatchingPrefixBits = matchingPrefixBits; - src = &(*i); - } - } - if (!src) - continue; + // Find an IP on the interface that can be a source IP, abort if no IPs assigned. + const InetAddress* src = nullptr; + unsigned int mostMatchingPrefixBits = 0; + for (std::set::const_iterator i(myIps.begin()); i != myIps.end(); ++i) { + const unsigned int matchingPrefixBits = i->matchingPrefixBits(*target); + if (matchingPrefixBits >= mostMatchingPrefixBits && ((target->isV4() && i->isV4()) || (target->isV6() && i->isV6()))) { + mostMatchingPrefixBits = matchingPrefixBits; + src = &(*i); + } + } + if (! src) + continue; - // Ignore routes implied by local managed IPs since adding the IP adds the route. - // Apple on the other hand seems to need this at least on some versions. + // Ignore routes implied by local managed IPs since adding the IP adds the route. + // Apple on the other hand seems to need this at least on some versions. #ifndef __APPLE__ - bool haveRoute = false; - for(std::vector::iterator ip(n.managedIps().begin());ip!=n.managedIps().end();++ip) { - if ((target->netmaskBits() == ip->netmaskBits())&&(target->containsAddress(*ip))) { - haveRoute = true; - break; - } - } - if (haveRoute) - continue; + bool haveRoute = false; + for (std::vector::iterator ip(n.managedIps().begin()); ip != n.managedIps().end(); ++ip) { + if ((target->netmaskBits() == ip->netmaskBits()) && (target->containsAddress(*ip))) { + haveRoute = true; + break; + } + } + if (haveRoute) + continue; #endif - haveRouteTargets.insert(*target); + haveRouteTargets.insert(*target); #ifndef ZT_SDK - SharedPtr &mr = n.managedRoutes()[*target]; - if (!mr) - mr.set(new ManagedRoute(*target, *via, *src, tapdev.c_str())); + SharedPtr& mr = n.managedRoutes()[*target]; + if (! mr) + mr.set(new ManagedRoute(*target, *via, *src, tapdev.c_str())); #endif - } + } - for(std::map< InetAddress, SharedPtr >::iterator r(n.managedRoutes().begin());r!=n.managedRoutes().end();) { - if (haveRouteTargets.find(r->first) == haveRouteTargets.end()) - n.managedRoutes().erase(r++); - else ++r; - } + for (std::map >::iterator r(n.managedRoutes().begin()); r != n.managedRoutes().end();) { + if (haveRouteTargets.find(r->first) == haveRouteTargets.end()) + n.managedRoutes().erase(r++); + else + ++r; + } - // Sync device-local managed routes first, then indirect results. That way - // we don't get destination unreachable for routes that are via things - // that do not yet have routes in the system. - for(std::map< InetAddress, SharedPtr >::iterator r(n.managedRoutes().begin());r!=n.managedRoutes().end();++r) { - if (!r->second->via()) - r->second->sync(); - } - for(std::map< InetAddress, SharedPtr >::iterator r(n.managedRoutes().begin());r!=n.managedRoutes().end();++r) { - if (r->second->via() && (!r->second->target().isDefaultRoute() || _node->online())) { - r->second->sync(); - } - } - } + // Sync device-local managed routes first, then indirect results. That way + // we don't get destination unreachable for routes that are via things + // that do not yet have routes in the system. + for (std::map >::iterator r(n.managedRoutes().begin()); r != n.managedRoutes().end(); ++r) { + if (! r->second->via()) + r->second->sync(); + } + for (std::map >::iterator r(n.managedRoutes().begin()); r != n.managedRoutes().end(); ++r) { + if (r->second->via() && (! r->second->target().isDefaultRoute() || _node->online())) { + r->second->sync(); + } + } + } - if (syncDns) { - if (n.allowDNS()) { - if (strlen(n.config().dns.domain) != 0) { - std::vector servers; - for (int j = 0; j < ZT_MAX_DNS_SERVERS; ++j) { - InetAddress a(n.config().dns.server_addr[j]); - if (a.isV4() || a.isV6()) { - servers.push_back(a); - } - } - n.tap()->setDns(n.config().dns.domain, servers); - } - } else { + if (syncDns) { + if (n.allowDNS()) { + if (strlen(n.config().dns.domain) != 0) { + std::vector servers; + for (int j = 0; j < ZT_MAX_DNS_SERVERS; ++j) { + InetAddress a(n.config().dns.server_addr[j]); + if (a.isV4() || a.isV6()) { + servers.push_back(a); + } + } + n.tap()->setDns(n.config().dns.domain, servers); + } + } + else { #ifdef __APPLE__ - MacDNSHelper::removeDNS(n.config().nwid); + MacDNSHelper::removeDNS(n.config().nwid); #elif defined(__WINDOWS__) - WinDNSHelper::removeDNS(n.config().nwid); + WinDNSHelper::removeDNS(n.config().nwid); #endif - } + } + } + } - } - } + // ========================================================================= + // Handlers for Node and Phy<> callbacks + // ========================================================================= - // ========================================================================= - // Handlers for Node and Phy<> callbacks - // ========================================================================= + inline void phyOnDatagram(PhySocket* sock, void** uptr, const struct sockaddr* localAddr, const struct sockaddr* from, void* data, unsigned long len) + { + if (_forceTcpRelay) { + return; + } + Metrics::udp_recv += len; + const uint64_t now = OSUtils::now(); + if ((len >= 16) && (reinterpret_cast(from)->ipScope() == InetAddress::IP_SCOPE_GLOBAL)) { + _lastDirectReceiveFromGlobal = now; + } + const ZT_ResultCode rc = _node->processWirePacket(nullptr, now, reinterpret_cast(sock), reinterpret_cast(from), data, len, &_nextBackgroundTaskDeadline); + if (ZT_ResultCode_isFatal(rc)) { + char tmp[256]; + OSUtils::ztsnprintf(tmp, sizeof(tmp), "fatal error code from processWirePacket: %d", (int)rc); + Mutex::Lock _l(_termReason_m); + _termReason = ONE_UNRECOVERABLE_ERROR; + _fatalErrorMessage = tmp; + this->terminate(); + } + } + inline void phyOnTcpConnect(PhySocket* sock, void** uptr, bool success) + { + if (! success) { + phyOnTcpClose(sock, uptr); + return; + } + TcpConnection* const tc = reinterpret_cast(*uptr); + if (! tc) { // sanity check + _phy.close(sock, true); + return; + } + tc->sock = sock; + if (tc->type == TcpConnection::TCP_TUNNEL_OUTGOING) { + if (_tcpFallbackTunnel) + _phy.close(_tcpFallbackTunnel->sock); + _tcpFallbackTunnel = tc; + _phy.streamSend(sock, ZT_TCP_TUNNEL_HELLO, sizeof(ZT_TCP_TUNNEL_HELLO)); + } + else { + _phy.close(sock, true); + } + } - inline void phyOnDatagram(PhySocket* sock, void** uptr, const struct sockaddr* localAddr, const struct sockaddr* from, void* data, unsigned long len) - { - if (_forceTcpRelay) { - return; - } - Metrics::udp_recv += len; - const uint64_t now = OSUtils::now(); - if ((len >= 16) && (reinterpret_cast(from)->ipScope() == InetAddress::IP_SCOPE_GLOBAL)) { - _lastDirectReceiveFromGlobal = now; - } - const ZT_ResultCode rc = _node->processWirePacket(nullptr,now,reinterpret_cast(sock),reinterpret_cast(from),data,len,&_nextBackgroundTaskDeadline); - if (ZT_ResultCode_isFatal(rc)) { - char tmp[256]; - OSUtils::ztsnprintf(tmp,sizeof(tmp),"fatal error code from processWirePacket: %d",(int)rc); - Mutex::Lock _l(_termReason_m); - _termReason = ONE_UNRECOVERABLE_ERROR; - _fatalErrorMessage = tmp; - this->terminate(); - } - } - - - inline void phyOnTcpConnect(PhySocket *sock,void **uptr,bool success) - { - if (!success) { - phyOnTcpClose(sock,uptr); - return; - } - - TcpConnection *const tc = reinterpret_cast(*uptr); - if (!tc) { // sanity check - _phy.close(sock,true); - return; - } - tc->sock = sock; - - if (tc->type == TcpConnection::TCP_TUNNEL_OUTGOING) { - if (_tcpFallbackTunnel) - _phy.close(_tcpFallbackTunnel->sock); - _tcpFallbackTunnel = tc; - _phy.streamSend(sock,ZT_TCP_TUNNEL_HELLO,sizeof(ZT_TCP_TUNNEL_HELLO)); - } else { - _phy.close(sock,true); - } - } - - inline void phyOnTcpAccept(PhySocket *sockL,PhySocket *sockN,void **uptrL,void **uptrN,const struct sockaddr *from) - { - if (!from) { - _phy.close(sockN,false); - return; - } else { + inline void phyOnTcpAccept(PhySocket* sockL, PhySocket* sockN, void** uptrL, void** uptrN, const struct sockaddr* from) + { + if (! from) { + _phy.close(sockN, false); + return; + } + else { #ifdef ZT_SDK - // Immediately close new local connections. The intention is to prevent the backplane from being accessed when operating as libzt - if (!allowHttpBackplaneManagement && ((InetAddress*)from)->ipScope() == InetAddress::IP_SCOPE_LOOPBACK) { - _phy.close(sockN,false); - return; - } + // Immediately close new local connections. The intention is to prevent the backplane from being accessed when operating as libzt + if (! allowHttpBackplaneManagement && ((InetAddress*)from)->ipScope() == InetAddress::IP_SCOPE_LOOPBACK) { + _phy.close(sockN, false); + return; + } #endif - TcpConnection *tc = new TcpConnection(); - { - Mutex::Lock _l(_tcpConnections_m); - _tcpConnections.push_back(tc); - } + TcpConnection* tc = new TcpConnection(); + { + Mutex::Lock _l(_tcpConnections_m); + _tcpConnections.push_back(tc); + } - tc->type = TcpConnection::TCP_UNCATEGORIZED_INCOMING; - tc->parent = this; - tc->sock = sockN; - tc->remoteAddr = from; - tc->lastReceive = OSUtils::now(); - http_parser_init(&(tc->parser),HTTP_REQUEST); - tc->parser.data = (void *)tc; - tc->messageSize = 0; + tc->type = TcpConnection::TCP_UNCATEGORIZED_INCOMING; + tc->parent = this; + tc->sock = sockN; + tc->remoteAddr = from; + tc->lastReceive = OSUtils::now(); + http_parser_init(&(tc->parser), HTTP_REQUEST); + tc->parser.data = (void*)tc; + tc->messageSize = 0; - *uptrN = (void *)tc; - } - } + *uptrN = (void*)tc; + } + } - void phyOnTcpClose(PhySocket *sock,void **uptr) - { - TcpConnection *tc = (TcpConnection *)*uptr; - if (tc) { - if (tc == _tcpFallbackTunnel) { - _tcpFallbackTunnel = (TcpConnection *)0; - } - { - Mutex::Lock _l(_tcpConnections_m); - _tcpConnections.erase(std::remove(_tcpConnections.begin(),_tcpConnections.end(),tc),_tcpConnections.end()); - } - delete tc; - } - } + void phyOnTcpClose(PhySocket* sock, void** uptr) + { + TcpConnection* tc = (TcpConnection*)*uptr; + if (tc) { + if (tc == _tcpFallbackTunnel) { + _tcpFallbackTunnel = (TcpConnection*)0; + } + { + Mutex::Lock _l(_tcpConnections_m); + _tcpConnections.erase(std::remove(_tcpConnections.begin(), _tcpConnections.end(), tc), _tcpConnections.end()); + } + delete tc; + } + } - void phyOnTcpData(PhySocket *sock,void **uptr,void *data,unsigned long len) - { - try { - if (!len) return; // sanity check, should never happen + void phyOnTcpData(PhySocket* sock, void** uptr, void* data, unsigned long len) + { + try { + if (! len) + return; // sanity check, should never happen Metrics::tcp_recv += len; - TcpConnection *tc = reinterpret_cast(*uptr); - tc->lastReceive = OSUtils::now(); - switch(tc->type) { - case TcpConnection::TCP_UNCATEGORIZED_INCOMING: - return; + TcpConnection* tc = reinterpret_cast(*uptr); + tc->lastReceive = OSUtils::now(); + switch (tc->type) { + case TcpConnection::TCP_UNCATEGORIZED_INCOMING: + return; - case TcpConnection::TCP_HTTP_INCOMING: - case TcpConnection::TCP_HTTP_OUTGOING: - http_parser_execute(&(tc->parser),&HTTP_PARSER_SETTINGS,(const char *)data,len); - if ((tc->parser.upgrade)||(tc->parser.http_errno != HPE_OK)) - _phy.close(sock); - return; + case TcpConnection::TCP_HTTP_INCOMING: + case TcpConnection::TCP_HTTP_OUTGOING: + http_parser_execute(&(tc->parser), &HTTP_PARSER_SETTINGS, (const char*)data, len); + if ((tc->parser.upgrade) || (tc->parser.http_errno != HPE_OK)) + _phy.close(sock); + return; - case TcpConnection::TCP_TUNNEL_OUTGOING: - tc->readq.append((const char *)data,len); - while (tc->readq.length() >= 5) { - const char *data = tc->readq.data(); - const unsigned long mlen = ( ((((unsigned long)data[3]) & 0xff) << 8) | (((unsigned long)data[4]) & 0xff) ); - if (tc->readq.length() >= (mlen + 5)) { - InetAddress from; + case TcpConnection::TCP_TUNNEL_OUTGOING: + tc->readq.append((const char*)data, len); + while (tc->readq.length() >= 5) { + const char* data = tc->readq.data(); + const unsigned long mlen = (((((unsigned long)data[3]) & 0xff) << 8) | (((unsigned long)data[4]) & 0xff)); + if (tc->readq.length() >= (mlen + 5)) { + InetAddress from; - unsigned long plen = mlen; // payload length, modified if there's an IP header - data += 5; // skip forward past pseudo-TLS junk and mlen - if (plen == 4) { - // Hello message, which isn't sent by proxy and would be ignored by client - } else if (plen) { - // Messages should contain IPv4 or IPv6 source IP address data - switch(data[0]) { - case 4: // IPv4 - if (plen >= 7) { - from.set((const void *)(data + 1),4,((((unsigned int)data[5]) & 0xff) << 8) | (((unsigned int)data[6]) & 0xff)); - data += 7; // type + 4 byte IP + 2 byte port - plen -= 7; - } else { - _phy.close(sock); - return; - } - break; - case 6: // IPv6 - if (plen >= 19) { - from.set((const void *)(data + 1),16,((((unsigned int)data[17]) & 0xff) << 8) | (((unsigned int)data[18]) & 0xff)); - data += 19; // type + 16 byte IP + 2 byte port - plen -= 19; - } else { - _phy.close(sock); - return; - } - break; - case 0: // none/omitted - ++data; - --plen; - break; - default: // invalid address type - _phy.close(sock); - return; - } + unsigned long plen = mlen; // payload length, modified if there's an IP header + data += 5; // skip forward past pseudo-TLS junk and mlen + if (plen == 4) { + // Hello message, which isn't sent by proxy and would be ignored by client + } + else if (plen) { + // Messages should contain IPv4 or IPv6 source IP address data + switch (data[0]) { + case 4: // IPv4 + if (plen >= 7) { + from.set((const void*)(data + 1), 4, ((((unsigned int)data[5]) & 0xff) << 8) | (((unsigned int)data[6]) & 0xff)); + data += 7; // type + 4 byte IP + 2 byte port + plen -= 7; + } + else { + _phy.close(sock); + return; + } + break; + case 6: // IPv6 + if (plen >= 19) { + from.set((const void*)(data + 1), 16, ((((unsigned int)data[17]) & 0xff) << 8) | (((unsigned int)data[18]) & 0xff)); + data += 19; // type + 16 byte IP + 2 byte port + plen -= 19; + } + else { + _phy.close(sock); + return; + } + break; + case 0: // none/omitted + ++data; + --plen; + break; + default: // invalid address type + _phy.close(sock); + return; + } - if (from) { - InetAddress fakeTcpLocalInterfaceAddress((uint32_t)0xffffffff,0xffff); - const ZT_ResultCode rc = _node->processWirePacket( - (void *)0, - OSUtils::now(), - -1, - reinterpret_cast(&from), - data, - plen, - &_nextBackgroundTaskDeadline); - if (ZT_ResultCode_isFatal(rc)) { - char tmp[256]; - OSUtils::ztsnprintf(tmp,sizeof(tmp),"fatal error code from processWirePacket: %d",(int)rc); - Mutex::Lock _l(_termReason_m); - _termReason = ONE_UNRECOVERABLE_ERROR; - _fatalErrorMessage = tmp; - this->terminate(); - _phy.close(sock); - return; - } - } - } + if (from) { + InetAddress fakeTcpLocalInterfaceAddress((uint32_t)0xffffffff, 0xffff); + const ZT_ResultCode rc = _node->processWirePacket((void*)0, OSUtils::now(), -1, reinterpret_cast(&from), data, plen, &_nextBackgroundTaskDeadline); + if (ZT_ResultCode_isFatal(rc)) { + char tmp[256]; + OSUtils::ztsnprintf(tmp, sizeof(tmp), "fatal error code from processWirePacket: %d", (int)rc); + Mutex::Lock _l(_termReason_m); + _termReason = ONE_UNRECOVERABLE_ERROR; + _fatalErrorMessage = tmp; + this->terminate(); + _phy.close(sock); + return; + } + } + } - if (tc->readq.length() > (mlen + 5)) - tc->readq.erase(tc->readq.begin(),tc->readq.begin() + (mlen + 5)); - else tc->readq.clear(); - } else break; - } - return; + if (tc->readq.length() > (mlen + 5)) + tc->readq.erase(tc->readq.begin(), tc->readq.begin() + (mlen + 5)); + else + tc->readq.clear(); + } + else + break; + } + return; + } + } + catch (...) { + _phy.close(sock); + } + } - } - } catch ( ... ) { - _phy.close(sock); - } - } - - inline void phyOnTcpWritable(PhySocket *sock,void **uptr) - { - TcpConnection *tc = reinterpret_cast(*uptr); - bool closeit = false; - { - Mutex::Lock _l(tc->writeq_m); - if (tc->writeq.length() > 0) { - long sent = (long)_phy.streamSend(sock,tc->writeq.data(),(unsigned long)tc->writeq.length(),true); + inline void phyOnTcpWritable(PhySocket* sock, void** uptr) + { + TcpConnection* tc = reinterpret_cast(*uptr); + bool closeit = false; + { + Mutex::Lock _l(tc->writeq_m); + if (tc->writeq.length() > 0) { + long sent = (long)_phy.streamSend(sock, tc->writeq.data(), (unsigned long)tc->writeq.length(), true); Metrics::tcp_send += sent; - if (sent > 0) { - if ((unsigned long)sent >= (unsigned long)tc->writeq.length()) { - tc->writeq.clear(); - _phy.setNotifyWritable(sock,false); + if (sent > 0) { + if ((unsigned long)sent >= (unsigned long)tc->writeq.length()) { + tc->writeq.clear(); + _phy.setNotifyWritable(sock, false); - if (tc->type == TcpConnection::TCP_HTTP_INCOMING) - closeit = true; // HTTP keep alive not supported - } else { - tc->writeq.erase(tc->writeq.begin(),tc->writeq.begin() + sent); - } - } - } else { - _phy.setNotifyWritable(sock,false); - } - } - if (closeit) - _phy.close(sock); - } + if (tc->type == TcpConnection::TCP_HTTP_INCOMING) + closeit = true; // HTTP keep alive not supported + } + else { + tc->writeq.erase(tc->writeq.begin(), tc->writeq.begin() + sent); + } + } + } + else { + _phy.setNotifyWritable(sock, false); + } + } + if (closeit) + _phy.close(sock); + } - inline void phyOnFileDescriptorActivity(PhySocket *sock,void **uptr,bool readable,bool writable) {} - inline void phyOnUnixAccept(PhySocket *sockL,PhySocket *sockN,void **uptrL,void **uptrN) {} - inline void phyOnUnixClose(PhySocket *sock,void **uptr) {} - inline void phyOnUnixData(PhySocket *sock,void **uptr,void *data,unsigned long len) {} - inline void phyOnUnixWritable(PhySocket *sock,void **uptr) {} + inline void phyOnFileDescriptorActivity(PhySocket* sock, void** uptr, bool readable, bool writable) + { + } + inline void phyOnUnixAccept(PhySocket* sockL, PhySocket* sockN, void** uptrL, void** uptrN) + { + } + inline void phyOnUnixClose(PhySocket* sock, void** uptr) + { + } + inline void phyOnUnixData(PhySocket* sock, void** uptr, void* data, unsigned long len) + { + } + inline void phyOnUnixWritable(PhySocket* sock, void** uptr) + { + } - inline int nodeVirtualNetworkConfigFunction(uint64_t nwid,void **nuptr,enum ZT_VirtualNetworkConfigOperation op,const ZT_VirtualNetworkConfig *nwc) - { - Mutex::Lock _l(_nets_m); - NetworkState &n = _nets[nwid]; - n.setWebPort(_primaryPort); + inline int nodeVirtualNetworkConfigFunction(uint64_t nwid, void** nuptr, enum ZT_VirtualNetworkConfigOperation op, const ZT_VirtualNetworkConfig* nwc) + { + Mutex::Lock _l(_nets_m); + NetworkState& n = _nets[nwid]; + n.setWebPort(_primaryPort); - switch (op) { - case ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_UP: - if (!n.tap()) { - try { - char friendlyName[128]; - OSUtils::ztsnprintf(friendlyName,sizeof(friendlyName),"ZeroTier One [%.16llx]",nwid); + switch (op) { + case ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_UP: + if (! n.tap()) { + try { + char friendlyName[128]; + OSUtils::ztsnprintf(friendlyName, sizeof(friendlyName), "ZeroTier One [%.16llx]", nwid); - n.setTap(EthernetTap::newInstance( - nullptr, - _concurrency, - _cpuPinningEnabled, - _homePath.c_str(), - MAC(nwc->mac), - nwc->mtu, - (unsigned int)ZT_IF_METRIC, - nwid, - friendlyName, - StapFrameHandler, - (void *)this)); - *nuptr = (void *)&n; + n.setTap(EthernetTap::newInstance(nullptr, _concurrency, _cpuPinningEnabled, _homePath.c_str(), MAC(nwc->mac), nwc->mtu, (unsigned int)ZT_IF_METRIC, nwid, friendlyName, StapFrameHandler, (void*)this)); + *nuptr = (void*)&n; - char nlcpath[256]; - OSUtils::ztsnprintf(nlcpath,sizeof(nlcpath),"%s" ZT_PATH_SEPARATOR_S "networks.d" ZT_PATH_SEPARATOR_S "%.16llx.local.conf",_homePath.c_str(),nwid); - std::string nlcbuf; - if (OSUtils::readFile(nlcpath,nlcbuf)) { - Dictionary<4096> nc; - nc.load(nlcbuf.c_str()); - Buffer<1024> allowManaged; - if (nc.get("allowManaged", allowManaged) && allowManaged.size() > 0) { - std::string addresses (allowManaged.begin(), allowManaged.size()); - if (allowManaged.size() <= 5) { // untidy parsing for backward compatibility - if (allowManaged[0] == '1' || allowManaged[0] == 't' || allowManaged[0] == 'T') { - n.setAllowManaged(true); - } else { - n.setAllowManaged(false); - } - } else { - // this should be a list of IP addresses - n.setAllowManaged(true); - size_t pos = 0; - while (true) { - size_t nextPos = addresses.find(',', pos); - std::string address = addresses.substr(pos, (nextPos == std::string::npos ? addresses.size() : nextPos) - pos); - n.addToAllowManagedWhiteList(InetAddress(address.c_str())); - if (nextPos == std::string::npos) break; - pos = nextPos + 1; - } - } - } else { - n.setAllowManaged(true); - } - n.setAllowGlobal(nc.getB("allowGlobal", false)); - n.setAllowDefault(nc.getB("allowDefault", false)); - n.setAllowDNS(nc.getB("allowDNS", false)); - } - } catch (std::exception &exc) { + char nlcpath[256]; + OSUtils::ztsnprintf(nlcpath, sizeof(nlcpath), "%s" ZT_PATH_SEPARATOR_S "networks.d" ZT_PATH_SEPARATOR_S "%.16llx.local.conf", _homePath.c_str(), nwid); + std::string nlcbuf; + if (OSUtils::readFile(nlcpath, nlcbuf)) { + Dictionary<4096> nc; + nc.load(nlcbuf.c_str()); + Buffer<1024> allowManaged; + if (nc.get("allowManaged", allowManaged) && allowManaged.size() > 0) { + std::string addresses(allowManaged.begin(), allowManaged.size()); + if (allowManaged.size() <= 5) { // untidy parsing for backward compatibility + if (allowManaged[0] == '1' || allowManaged[0] == 't' || allowManaged[0] == 'T') { + n.setAllowManaged(true); + } + else { + n.setAllowManaged(false); + } + } + else { + // this should be a list of IP addresses + n.setAllowManaged(true); + size_t pos = 0; + while (true) { + size_t nextPos = addresses.find(',', pos); + std::string address = addresses.substr(pos, (nextPos == std::string::npos ? addresses.size() : nextPos) - pos); + n.addToAllowManagedWhiteList(InetAddress(address.c_str())); + if (nextPos == std::string::npos) + break; + pos = nextPos + 1; + } + } + } + else { + n.setAllowManaged(true); + } + n.setAllowGlobal(nc.getB("allowGlobal", false)); + n.setAllowDefault(nc.getB("allowDefault", false)); + n.setAllowDNS(nc.getB("allowDNS", false)); + } + } + catch (std::exception& exc) { #ifdef __WINDOWS__ - FILE *tapFailLog = fopen((_homePath + ZT_PATH_SEPARATOR_S"port_error_log.txt").c_str(),"a"); - if (tapFailLog) { - fprintf(tapFailLog,"%.16llx: %s" ZT_EOL_S,(unsigned long long)nwid,exc.what()); - fclose(tapFailLog); - } + FILE* tapFailLog = fopen((_homePath + ZT_PATH_SEPARATOR_S "port_error_log.txt").c_str(), "a"); + if (tapFailLog) { + fprintf(tapFailLog, "%.16llx: %s" ZT_EOL_S, (unsigned long long)nwid, exc.what()); + fclose(tapFailLog); + } #else - fprintf(stderr,"ERROR: unable to configure virtual network port: %s" ZT_EOL_S,exc.what()); + fprintf(stderr, "ERROR: unable to configure virtual network port: %s" ZT_EOL_S, exc.what()); #endif - _nets.erase(nwid); - return -999; - } catch ( ... ) { - return -999; // tap init failed - } - } - // After setting up tap, fall through to CONFIG_UPDATE since we also want to do this... + _nets.erase(nwid); + return -999; + } + catch (...) { + return -999; // tap init failed + } + } + // After setting up tap, fall through to CONFIG_UPDATE since we also want to do this... - case ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_CONFIG_UPDATE: - n.setConfig(nwc); + case ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_CONFIG_UPDATE: + n.setConfig(nwc); - if (n.tap()) { // sanity check -#if defined(__WINDOWS__) && !defined(ZT_SDK) - // wait for up to 5 seconds for the WindowsEthernetTap to actually be initialized - // - // without WindowsEthernetTap::isInitialized() returning true, the won't actually - // be online yet and setting managed routes on it will fail. - const int MAX_SLEEP_COUNT = 500; - for (int i = 0; !((WindowsEthernetTap *)(n.tap().get()))->isInitialized() && i < MAX_SLEEP_COUNT; i++) { - Sleep(10); - } + if (n.tap()) { // sanity check +#if defined(__WINDOWS__) && ! defined(ZT_SDK) + // wait for up to 5 seconds for the WindowsEthernetTap to actually be initialized + // + // without WindowsEthernetTap::isInitialized() returning true, the won't actually + // be online yet and setting managed routes on it will fail. + const int MAX_SLEEP_COUNT = 500; + for (int i = 0; ! ((WindowsEthernetTap*)(n.tap().get()))->isInitialized() && i < MAX_SLEEP_COUNT; i++) { + Sleep(10); + } #endif - syncManagedStuff(n,true,true,true); - n.tap()->setMtu(nwc->mtu); - } else { - _nets.erase(nwid); - return -999; // tap init failed - } - break; + syncManagedStuff(n, true, true, true); + n.tap()->setMtu(nwc->mtu); + } + else { + _nets.erase(nwid); + return -999; // tap init failed + } + break; - case ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_DOWN: - case ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_DESTROY: - if (n.tap()) { // sanity check -#if defined(__WINDOWS__) && !defined(ZT_SDK) - std::string winInstanceId(((WindowsEthernetTap *)(n.tap().get()))->instanceId()); + case ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_DOWN: + case ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_DESTROY: + if (n.tap()) { // sanity check +#if defined(__WINDOWS__) && ! defined(ZT_SDK) + std::string winInstanceId(((WindowsEthernetTap*)(n.tap().get()))->instanceId()); #endif - *nuptr = (void *)0; - n.tap().reset(); - _nets.erase(nwid); -#if defined(__WINDOWS__) && !defined(ZT_SDK) - if ((op == ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_DESTROY) && (winInstanceId.length() > 0)) { - WindowsEthernetTap::deletePersistentTapDevice(winInstanceId.c_str()); - WinFWHelper::removeICMPRules(nwid); - } + *nuptr = (void*)0; + n.tap().reset(); + _nets.erase(nwid); +#if defined(__WINDOWS__) && ! defined(ZT_SDK) + if ((op == ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_DESTROY) && (winInstanceId.length() > 0)) { + WindowsEthernetTap::deletePersistentTapDevice(winInstanceId.c_str()); + WinFWHelper::removeICMPRules(nwid); + } #endif - if (op == ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_DESTROY) { - char nlcpath[256]; - OSUtils::ztsnprintf(nlcpath,sizeof(nlcpath),"%s" ZT_PATH_SEPARATOR_S "networks.d" ZT_PATH_SEPARATOR_S "%.16llx.local.conf",_homePath.c_str(),nwid); - OSUtils::rm(nlcpath); - } - } else { - _nets.erase(nwid); - } - break; - } - return 0; - } + if (op == ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_DESTROY) { + char nlcpath[256]; + OSUtils::ztsnprintf(nlcpath, sizeof(nlcpath), "%s" ZT_PATH_SEPARATOR_S "networks.d" ZT_PATH_SEPARATOR_S "%.16llx.local.conf", _homePath.c_str(), nwid); + OSUtils::rm(nlcpath); + } + } + else { + _nets.erase(nwid); + } + break; + } + return 0; + } - inline void nodeEventCallback(enum ZT_Event event,const void *metaData) - { - switch(event) { - case ZT_EVENT_FATAL_ERROR_IDENTITY_COLLISION: { - Mutex::Lock _l(_termReason_m); - _termReason = ONE_IDENTITY_COLLISION; - _fatalErrorMessage = "identity/address collision"; - this->terminate(); - } break; + inline void nodeEventCallback(enum ZT_Event event, const void* metaData) + { + switch (event) { + case ZT_EVENT_FATAL_ERROR_IDENTITY_COLLISION: { + Mutex::Lock _l(_termReason_m); + _termReason = ONE_IDENTITY_COLLISION; + _fatalErrorMessage = "identity/address collision"; + this->terminate(); + } break; - case ZT_EVENT_TRACE: { - if (metaData) { - ::fprintf(stderr,"%s" ZT_EOL_S,(const char *)metaData); - ::fflush(stderr); - } - } break; + case ZT_EVENT_TRACE: { + if (metaData) { + ::fprintf(stderr, "%s" ZT_EOL_S, (const char*)metaData); + ::fflush(stderr); + } + } break; - case ZT_EVENT_USER_MESSAGE: { - const ZT_UserMessage *um = reinterpret_cast(metaData); - if ((um->typeId == ZT_SOFTWARE_UPDATE_USER_MESSAGE_TYPE)&&(_updater)) { - _updater->handleSoftwareUpdateUserMessage(um->origin,um->data,um->length); - } - } break; + case ZT_EVENT_USER_MESSAGE: { + const ZT_UserMessage* um = reinterpret_cast(metaData); + if ((um->typeId == ZT_SOFTWARE_UPDATE_USER_MESSAGE_TYPE) && (_updater)) { + _updater->handleSoftwareUpdateUserMessage(um->origin, um->data, um->length); + } + } break; - case ZT_EVENT_REMOTE_TRACE: { - const ZT_RemoteTrace *rt = reinterpret_cast(metaData); - if ((rt)&&(rt->len > 0)&&(rt->len <= ZT_MAX_REMOTE_TRACE_SIZE)&&(rt->data)) - _controller->handleRemoteTrace(*rt); - } + case ZT_EVENT_REMOTE_TRACE: { + const ZT_RemoteTrace* rt = reinterpret_cast(metaData); + if ((rt) && (rt->len > 0) && (rt->len <= ZT_MAX_REMOTE_TRACE_SIZE) && (rt->data)) + _controller->handleRemoteTrace(*rt); + } - default: - break; - } - } + default: + break; + } + } #if ZT_VAULT_SUPPORT - inline bool nodeVaultPutIdentity(enum ZT_StateObjectType type, const void *data, int len) - { - bool retval = false; - if (type != ZT_STATE_OBJECT_IDENTITY_PUBLIC && type != ZT_STATE_OBJECT_IDENTITY_SECRET) { - return retval; - } + inline bool nodeVaultPutIdentity(enum ZT_StateObjectType type, const void* data, int len) + { + bool retval = false; + if (type != ZT_STATE_OBJECT_IDENTITY_PUBLIC && type != ZT_STATE_OBJECT_IDENTITY_SECRET) { + return retval; + } - CURL *curl = curl_easy_init(); - if (curl) { - char token[512] = { 0 }; - snprintf(token, sizeof(token), "X-Vault-Token: %s", _vaultToken.c_str()); + CURL* curl = curl_easy_init(); + if (curl) { + char token[512] = { 0 }; + snprintf(token, sizeof(token), "X-Vault-Token: %s", _vaultToken.c_str()); - struct curl_slist *chunk = NULL; - chunk = curl_slist_append(chunk, token); + struct curl_slist* chunk = NULL; + chunk = curl_slist_append(chunk, token); + char content_type[512] = { 0 }; + snprintf(content_type, sizeof(content_type), "Content-Type: application/json"); - char content_type[512] = { 0 }; - snprintf(content_type, sizeof(content_type), "Content-Type: application/json"); + chunk = curl_slist_append(chunk, content_type); - chunk = curl_slist_append(chunk, content_type); + curl_easy_setopt(curl, CURLOPT_HTTPHEADER, chunk); - curl_easy_setopt(curl, CURLOPT_HTTPHEADER, chunk); + char url[2048] = { 0 }; + snprintf(url, sizeof(url), "%s/v1/%s", _vaultURL.c_str(), _vaultPath.c_str()); - char url[2048] = { 0 }; - snprintf(url, sizeof(url), "%s/v1/%s", _vaultURL.c_str(), _vaultPath.c_str()); + curl_easy_setopt(curl, CURLOPT_URL, url); - curl_easy_setopt(curl, CURLOPT_URL, url); + json d = json::object(); + if (type == ZT_STATE_OBJECT_IDENTITY_PUBLIC) { + std::string key((const char*)data, len); + d["public"] = key; + } + else if (type == ZT_STATE_OBJECT_IDENTITY_SECRET) { + std::string key((const char*)data, len); + d["secret"] = key; + } - json d = json::object(); - if (type == ZT_STATE_OBJECT_IDENTITY_PUBLIC) { - std::string key((const char*)data, len); - d["public"] = key; - } - else if (type == ZT_STATE_OBJECT_IDENTITY_SECRET) { - std::string key((const char*)data, len); - d["secret"] = key; - } + if (! d.empty()) { + std::string post = d.dump(); - if (!d.empty()) { - std::string post = d.dump(); - - if (!post.empty()) { - curl_easy_setopt(curl, CURLOPT_POSTFIELDS, post.c_str()); - curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, post.length()); + if (! post.empty()) { + curl_easy_setopt(curl, CURLOPT_POSTFIELDS, post.c_str()); + curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, post.length()); #ifndef NDEBUG - curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); + curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); #endif - CURLcode res = curl_easy_perform(curl); - if (res == CURLE_OK) { - long response_code = 0; - curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code); - if (response_code == 200 || response_code == 204) { - retval = true; - } - } - } - } + CURLcode res = curl_easy_perform(curl); + if (res == CURLE_OK) { + long response_code = 0; + curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code); + if (response_code == 200 || response_code == 204) { + retval = true; + } + } + } + } - curl_easy_cleanup(curl); - curl = NULL; - curl_slist_free_all(chunk); - chunk = NULL; - } + curl_easy_cleanup(curl); + curl = NULL; + curl_slist_free_all(chunk); + chunk = NULL; + } - return retval; - } + return retval; + } #endif - inline void nodeStatePutFunction(enum ZT_StateObjectType type,const uint64_t id[2],const void *data,int len) - { + inline void nodeStatePutFunction(enum ZT_StateObjectType type, const uint64_t id[2], const void* data, int len) + { #if ZT_VAULT_SUPPORT - if (_vaultEnabled && (type == ZT_STATE_OBJECT_IDENTITY_SECRET || type == ZT_STATE_OBJECT_IDENTITY_PUBLIC)) { - if (nodeVaultPutIdentity(type, data, len)) { - // value successfully written to Vault - return; - } - // else fallback to disk - } + if (_vaultEnabled && (type == ZT_STATE_OBJECT_IDENTITY_SECRET || type == ZT_STATE_OBJECT_IDENTITY_PUBLIC)) { + if (nodeVaultPutIdentity(type, data, len)) { + // value successfully written to Vault + return; + } + // else fallback to disk + } #endif - char p[1024]; - FILE *f; - bool secure = false; - char dirname[1024]; - dirname[0] = 0; + char p[1024]; + FILE* f; + bool secure = false; + char dirname[1024]; + dirname[0] = 0; - switch(type) { - case ZT_STATE_OBJECT_IDENTITY_PUBLIC: - OSUtils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "identity.public",_homePath.c_str()); - break; - case ZT_STATE_OBJECT_IDENTITY_SECRET: - OSUtils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "identity.secret",_homePath.c_str()); - secure = true; - break; - case ZT_STATE_OBJECT_PLANET: - OSUtils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "planet",_homePath.c_str()); - break; - case ZT_STATE_OBJECT_MOON: - OSUtils::ztsnprintf(dirname,sizeof(dirname),"%s" ZT_PATH_SEPARATOR_S "moons.d",_homePath.c_str()); - OSUtils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "%.16llx.moon",dirname,(unsigned long long)id[0]); - break; - case ZT_STATE_OBJECT_NETWORK_CONFIG: - OSUtils::ztsnprintf(dirname,sizeof(dirname),"%s" ZT_PATH_SEPARATOR_S "networks.d",_homePath.c_str()); - OSUtils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "%.16llx.conf",dirname,(unsigned long long)id[0]); - break; - case ZT_STATE_OBJECT_PEER: - OSUtils::ztsnprintf(dirname,sizeof(dirname),"%s" ZT_PATH_SEPARATOR_S "peers.d",_homePath.c_str()); - OSUtils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "%.10llx.peer",dirname,(unsigned long long)id[0]); - break; - default: - return; - } + switch (type) { + case ZT_STATE_OBJECT_IDENTITY_PUBLIC: + OSUtils::ztsnprintf(p, sizeof(p), "%s" ZT_PATH_SEPARATOR_S "identity.public", _homePath.c_str()); + break; + case ZT_STATE_OBJECT_IDENTITY_SECRET: + OSUtils::ztsnprintf(p, sizeof(p), "%s" ZT_PATH_SEPARATOR_S "identity.secret", _homePath.c_str()); + secure = true; + break; + case ZT_STATE_OBJECT_PLANET: + OSUtils::ztsnprintf(p, sizeof(p), "%s" ZT_PATH_SEPARATOR_S "planet", _homePath.c_str()); + break; + case ZT_STATE_OBJECT_MOON: + OSUtils::ztsnprintf(dirname, sizeof(dirname), "%s" ZT_PATH_SEPARATOR_S "moons.d", _homePath.c_str()); + OSUtils::ztsnprintf(p, sizeof(p), "%s" ZT_PATH_SEPARATOR_S "%.16llx.moon", dirname, (unsigned long long)id[0]); + break; + case ZT_STATE_OBJECT_NETWORK_CONFIG: + OSUtils::ztsnprintf(dirname, sizeof(dirname), "%s" ZT_PATH_SEPARATOR_S "networks.d", _homePath.c_str()); + OSUtils::ztsnprintf(p, sizeof(p), "%s" ZT_PATH_SEPARATOR_S "%.16llx.conf", dirname, (unsigned long long)id[0]); + break; + case ZT_STATE_OBJECT_PEER: + OSUtils::ztsnprintf(dirname, sizeof(dirname), "%s" ZT_PATH_SEPARATOR_S "peers.d", _homePath.c_str()); + OSUtils::ztsnprintf(p, sizeof(p), "%s" ZT_PATH_SEPARATOR_S "%.10llx.peer", dirname, (unsigned long long)id[0]); + break; + default: + return; + } - if ((len >= 0)&&(data)) { - // Check to see if we've already written this first. This reduces - // redundant writes and I/O overhead on most platforms and has - // little effect on others. - f = fopen(p,"rb"); - if (f) { - char *const buf = (char *)malloc(len*4); - if (buf) { - long l = (long)fread(buf,1,(size_t)(len*4),f); - fclose(f); - if ((l == (long)len)&&(memcmp(data,buf,l) == 0)) { - free(buf); - return; - } - free(buf); - } - } + if ((len >= 0) && (data)) { + // Check to see if we've already written this first. This reduces + // redundant writes and I/O overhead on most platforms and has + // little effect on others. + f = fopen(p, "rb"); + if (f) { + char* const buf = (char*)malloc(len * 4); + if (buf) { + long l = (long)fread(buf, 1, (size_t)(len * 4), f); + fclose(f); + if ((l == (long)len) && (memcmp(data, buf, l) == 0)) { + free(buf); + return; + } + free(buf); + } + } - f = fopen(p,"wb"); - if ((!f)&&(dirname[0])) { // create subdirectory if it does not exist - OSUtils::mkdir(dirname); - f = fopen(p,"wb"); - } - if (f) { - if (fwrite(data,len,1,f) != 1) - fprintf(stderr,"WARNING: unable to write to file: %s (I/O error)" ZT_EOL_S,p); - fclose(f); - if (secure) - OSUtils::lockDownFile(p,false); - } else { - fprintf(stderr,"WARNING: unable to write to file: %s (unable to open)" ZT_EOL_S,p); - } - } else { - OSUtils::rm(p); - } - } + f = fopen(p, "wb"); + if ((! f) && (dirname[0])) { // create subdirectory if it does not exist + OSUtils::mkdir(dirname); + f = fopen(p, "wb"); + } + if (f) { + if (fwrite(data, len, 1, f) != 1) + fprintf(stderr, "WARNING: unable to write to file: %s (I/O error)" ZT_EOL_S, p); + fclose(f); + if (secure) + OSUtils::lockDownFile(p, false); + } + else { + fprintf(stderr, "WARNING: unable to write to file: %s (unable to open)" ZT_EOL_S, p); + } + } + else { + OSUtils::rm(p); + } + } #if ZT_VAULT_SUPPORT - inline int nodeVaultGetIdentity(enum ZT_StateObjectType type, void *data, unsigned int maxlen) - { - if (type != ZT_STATE_OBJECT_IDENTITY_SECRET && type != ZT_STATE_OBJECT_IDENTITY_PUBLIC) { - return -1; - } + inline int nodeVaultGetIdentity(enum ZT_StateObjectType type, void* data, unsigned int maxlen) + { + if (type != ZT_STATE_OBJECT_IDENTITY_SECRET && type != ZT_STATE_OBJECT_IDENTITY_PUBLIC) { + return -1; + } - int ret = -1; - CURL *curl = curl_easy_init(); - if (curl) { - char token[512] = { 0 }; - snprintf(token, sizeof(token), "X-Vault-Token: %s", _vaultToken.c_str()); + int ret = -1; + CURL* curl = curl_easy_init(); + if (curl) { + char token[512] = { 0 }; + snprintf(token, sizeof(token), "X-Vault-Token: %s", _vaultToken.c_str()); - struct curl_slist *chunk = NULL; - chunk = curl_slist_append(chunk, token); - curl_easy_setopt(curl, CURLOPT_HTTPHEADER, chunk); + struct curl_slist* chunk = NULL; + chunk = curl_slist_append(chunk, token); + curl_easy_setopt(curl, CURLOPT_HTTPHEADER, chunk); - char url[2048] = { 0 }; - snprintf(url, sizeof(url), "%s/v1/%s", _vaultURL.c_str(), _vaultPath.c_str()); + char url[2048] = { 0 }; + snprintf(url, sizeof(url), "%s/v1/%s", _vaultURL.c_str(), _vaultPath.c_str()); - curl_easy_setopt(curl, CURLOPT_URL, url); + curl_easy_setopt(curl, CURLOPT_URL, url); - std::string response; - std::string res_headers; + std::string response; + std::string res_headers; - curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &curlResponseWrite); - curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response); - curl_easy_setopt(curl, CURLOPT_HEADERDATA, &res_headers); + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &curlResponseWrite); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response); + curl_easy_setopt(curl, CURLOPT_HEADERDATA, &res_headers); #ifndef NDEBUG - curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); + curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); #endif - CURLcode res = curl_easy_perform(curl); + CURLcode res = curl_easy_perform(curl); - if (res == CURLE_OK) { - long response_code = 0; - curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code); - if (response_code == 200) { - try { - json payload = json::parse(response); - if (!payload["data"].is_null()) { - json &d = payload["data"]; - if (type == ZT_STATE_OBJECT_IDENTITY_SECRET) { - std::string secret = OSUtils::jsonString(d["secret"],""); + if (res == CURLE_OK) { + long response_code = 0; + curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code); + if (response_code == 200) { + try { + json payload = json::parse(response); + if (! payload["data"].is_null()) { + json& d = payload["data"]; + if (type == ZT_STATE_OBJECT_IDENTITY_SECRET) { + std::string secret = OSUtils::jsonString(d["secret"], ""); - if (!secret.empty()) { - ret = (int)secret.length(); - memcpy(data, secret.c_str(), ret); - } - } - else if (type == ZT_STATE_OBJECT_IDENTITY_PUBLIC) { - std::string pub = OSUtils::jsonString(d["public"],""); + if (! secret.empty()) { + ret = (int)secret.length(); + memcpy(data, secret.c_str(), ret); + } + } + else if (type == ZT_STATE_OBJECT_IDENTITY_PUBLIC) { + std::string pub = OSUtils::jsonString(d["public"], ""); - if (!pub.empty()) { - ret = (int)pub.length(); - memcpy(data, pub.c_str(), ret); - } - } - } - } - catch (...) { - ret = -1; - } - } - } + if (! pub.empty()) { + ret = (int)pub.length(); + memcpy(data, pub.c_str(), ret); + } + } + } + } + catch (...) { + ret = -1; + } + } + } - curl_easy_cleanup(curl); - curl = NULL; - curl_slist_free_all(chunk); - chunk = NULL; - } - return ret; - } + curl_easy_cleanup(curl); + curl = NULL; + curl_slist_free_all(chunk); + chunk = NULL; + } + return ret; + } #endif - inline int nodeStateGetFunction(enum ZT_StateObjectType type,const uint64_t id[2],void *data,unsigned int maxlen) - { + inline int nodeStateGetFunction(enum ZT_StateObjectType type, const uint64_t id[2], void* data, unsigned int maxlen) + { #if ZT_VAULT_SUPPORT - if (_vaultEnabled && (type == ZT_STATE_OBJECT_IDENTITY_SECRET || type == ZT_STATE_OBJECT_IDENTITY_PUBLIC) ) { - int retval = nodeVaultGetIdentity(type, data, maxlen); - if (retval >= 0) - return retval; + if (_vaultEnabled && (type == ZT_STATE_OBJECT_IDENTITY_SECRET || type == ZT_STATE_OBJECT_IDENTITY_PUBLIC)) { + int retval = nodeVaultGetIdentity(type, data, maxlen); + if (retval >= 0) + return retval; - // else continue file based lookup - } + // else continue file based lookup + } #endif - char p[4096]; - switch(type) { - case ZT_STATE_OBJECT_IDENTITY_PUBLIC: - OSUtils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "identity.public",_homePath.c_str()); - break; - case ZT_STATE_OBJECT_IDENTITY_SECRET: - OSUtils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "identity.secret",_homePath.c_str()); - break; - case ZT_STATE_OBJECT_PLANET: - OSUtils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "planet",_homePath.c_str()); - break; - case ZT_STATE_OBJECT_MOON: - OSUtils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "moons.d" ZT_PATH_SEPARATOR_S "%.16llx.moon",_homePath.c_str(),(unsigned long long)id[0]); - break; - case ZT_STATE_OBJECT_NETWORK_CONFIG: - OSUtils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "networks.d" ZT_PATH_SEPARATOR_S "%.16llx.conf",_homePath.c_str(),(unsigned long long)id[0]); - break; - case ZT_STATE_OBJECT_PEER: - OSUtils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "peers.d" ZT_PATH_SEPARATOR_S "%.10llx.peer",_homePath.c_str(),(unsigned long long)id[0]); - break; - default: - return -1; - } - FILE *f = fopen(p,"rb"); - if (f) { - int n = (int)fread(data,1,maxlen,f); - fclose(f); + char p[4096]; + switch (type) { + case ZT_STATE_OBJECT_IDENTITY_PUBLIC: + OSUtils::ztsnprintf(p, sizeof(p), "%s" ZT_PATH_SEPARATOR_S "identity.public", _homePath.c_str()); + break; + case ZT_STATE_OBJECT_IDENTITY_SECRET: + OSUtils::ztsnprintf(p, sizeof(p), "%s" ZT_PATH_SEPARATOR_S "identity.secret", _homePath.c_str()); + break; + case ZT_STATE_OBJECT_PLANET: + OSUtils::ztsnprintf(p, sizeof(p), "%s" ZT_PATH_SEPARATOR_S "planet", _homePath.c_str()); + break; + case ZT_STATE_OBJECT_MOON: + OSUtils::ztsnprintf(p, sizeof(p), "%s" ZT_PATH_SEPARATOR_S "moons.d" ZT_PATH_SEPARATOR_S "%.16llx.moon", _homePath.c_str(), (unsigned long long)id[0]); + break; + case ZT_STATE_OBJECT_NETWORK_CONFIG: + OSUtils::ztsnprintf(p, sizeof(p), "%s" ZT_PATH_SEPARATOR_S "networks.d" ZT_PATH_SEPARATOR_S "%.16llx.conf", _homePath.c_str(), (unsigned long long)id[0]); + break; + case ZT_STATE_OBJECT_PEER: + OSUtils::ztsnprintf(p, sizeof(p), "%s" ZT_PATH_SEPARATOR_S "peers.d" ZT_PATH_SEPARATOR_S "%.10llx.peer", _homePath.c_str(), (unsigned long long)id[0]); + break; + default: + return -1; + } + FILE* f = fopen(p, "rb"); + if (f) { + int n = (int)fread(data, 1, maxlen, f); + fclose(f); #if ZT_VAULT_SUPPORT - if (_vaultEnabled && (type == ZT_STATE_OBJECT_IDENTITY_SECRET || type == ZT_STATE_OBJECT_IDENTITY_PUBLIC)) { - // If we've gotten here while Vault is enabled, Vault does not know the key and it's been - // read from disk instead. - // - // We should put the value in Vault and remove the local file. - if (nodeVaultPutIdentity(type, data, n)) { - unlink(p); - } - } + if (_vaultEnabled && (type == ZT_STATE_OBJECT_IDENTITY_SECRET || type == ZT_STATE_OBJECT_IDENTITY_PUBLIC)) { + // If we've gotten here while Vault is enabled, Vault does not know the key and it's been + // read from disk instead. + // + // We should put the value in Vault and remove the local file. + if (nodeVaultPutIdentity(type, data, n)) { + unlink(p); + } + } #endif - if (n >= 0) - return n; - } - return -1; - } + if (n >= 0) + return n; + } + return -1; + } - inline int nodeWirePacketSendFunction(const int64_t localSocket,const struct sockaddr_storage *addr,const void *data,unsigned int len,unsigned int ttl) - { + inline int nodeWirePacketSendFunction(const int64_t localSocket, const struct sockaddr_storage* addr, const void* data, unsigned int len, unsigned int ttl) + { #ifdef ZT_TCP_FALLBACK_RELAY - if(_allowTcpFallbackRelay) { - if (addr->ss_family == AF_INET) { - // TCP fallback tunnel support, currently IPv4 only - if ((len >= 16)&&(reinterpret_cast(addr)->ipScope() == InetAddress::IP_SCOPE_GLOBAL)) { - // Engage TCP tunnel fallback if we haven't received anything valid from a global - // IP address in ZT_TCP_FALLBACK_AFTER milliseconds. If we do start getting - // valid direct traffic we'll stop using it and close the socket after a while. - const int64_t now = OSUtils::now(); - if (_forceTcpRelay || (((now - _lastDirectReceiveFromGlobal) > ZT_TCP_FALLBACK_AFTER)&&((now - _lastRestart) > ZT_TCP_FALLBACK_AFTER))) { - if (_tcpFallbackTunnel) { - bool flushNow = false; - { - Mutex::Lock _l(_tcpFallbackTunnel->writeq_m); - if (_tcpFallbackTunnel->writeq.size() < (1024 * 64)) { - if (_tcpFallbackTunnel->writeq.length() == 0) { - _phy.setNotifyWritable(_tcpFallbackTunnel->sock,true); - flushNow = true; - } - const unsigned long mlen = len + 7; - _tcpFallbackTunnel->writeq.push_back((char)0x17); - _tcpFallbackTunnel->writeq.push_back((char)0x03); - _tcpFallbackTunnel->writeq.push_back((char)0x03); // fake TLS 1.2 header - _tcpFallbackTunnel->writeq.push_back((char)((mlen >> 8) & 0xff)); - _tcpFallbackTunnel->writeq.push_back((char)(mlen & 0xff)); - _tcpFallbackTunnel->writeq.push_back((char)4); // IPv4 - _tcpFallbackTunnel->writeq.append(reinterpret_cast(reinterpret_cast(&(reinterpret_cast(addr)->sin_addr.s_addr))),4); - _tcpFallbackTunnel->writeq.append(reinterpret_cast(reinterpret_cast(&(reinterpret_cast(addr)->sin_port))),2); - _tcpFallbackTunnel->writeq.append((const char *)data,len); - } - } - if (flushNow) { - void *tmpptr = (void *)_tcpFallbackTunnel; - phyOnTcpWritable(_tcpFallbackTunnel->sock,&tmpptr); - } - } else if (_forceTcpRelay || (((now - _lastSendToGlobalV4) < ZT_TCP_FALLBACK_AFTER)&&((now - _lastSendToGlobalV4) > (ZT_PING_CHECK_INTERVAL / 2)))) { - const InetAddress addr(_fallbackRelayAddress); - TcpConnection *tc = new TcpConnection(); - { - Mutex::Lock _l(_tcpConnections_m); - _tcpConnections.push_back(tc); - } - tc->type = TcpConnection::TCP_TUNNEL_OUTGOING; - tc->remoteAddr = addr; - tc->lastReceive = OSUtils::now(); - tc->parent = this; - tc->sock = (PhySocket *)0; // set in connect handler - tc->messageSize = 0; - bool connected = false; - _phy.tcpConnect(reinterpret_cast(&addr),connected,(void *)tc,true); - } - } - _lastSendToGlobalV4 = now; - } - } - } - if (_forceTcpRelay) { - // Shortcut here so that we don't emit any UDP packets - return 0; - } -#endif // ZT_TCP_FALLBACK_RELAY - - // Even when relaying we still send via UDP. This way if UDP starts - // working we can instantly "fail forward" to it and stop using TCP - // proxy fallback, which is slow. - if ((localSocket != -1)&&(localSocket != 0)&&(_binder.isUdpSocketValid((PhySocket *)((uintptr_t)localSocket)))) { - if ((ttl)&&(addr->ss_family == AF_INET)) { - _phy.setIp4UdpTtl((PhySocket *)((uintptr_t)localSocket),ttl); + if (_allowTcpFallbackRelay) { + if (addr->ss_family == AF_INET) { + // TCP fallback tunnel support, currently IPv4 only + if ((len >= 16) && (reinterpret_cast(addr)->ipScope() == InetAddress::IP_SCOPE_GLOBAL)) { + // Engage TCP tunnel fallback if we haven't received anything valid from a global + // IP address in ZT_TCP_FALLBACK_AFTER milliseconds. If we do start getting + // valid direct traffic we'll stop using it and close the socket after a while. + const int64_t now = OSUtils::now(); + if (_forceTcpRelay || (((now - _lastDirectReceiveFromGlobal) > ZT_TCP_FALLBACK_AFTER) && ((now - _lastRestart) > ZT_TCP_FALLBACK_AFTER))) { + if (_tcpFallbackTunnel) { + bool flushNow = false; + { + Mutex::Lock _l(_tcpFallbackTunnel->writeq_m); + if (_tcpFallbackTunnel->writeq.size() < (1024 * 64)) { + if (_tcpFallbackTunnel->writeq.length() == 0) { + _phy.setNotifyWritable(_tcpFallbackTunnel->sock, true); + flushNow = true; + } + const unsigned long mlen = len + 7; + _tcpFallbackTunnel->writeq.push_back((char)0x17); + _tcpFallbackTunnel->writeq.push_back((char)0x03); + _tcpFallbackTunnel->writeq.push_back((char)0x03); // fake TLS 1.2 header + _tcpFallbackTunnel->writeq.push_back((char)((mlen >> 8) & 0xff)); + _tcpFallbackTunnel->writeq.push_back((char)(mlen & 0xff)); + _tcpFallbackTunnel->writeq.push_back((char)4); // IPv4 + _tcpFallbackTunnel->writeq.append(reinterpret_cast(reinterpret_cast(&(reinterpret_cast(addr)->sin_addr.s_addr))), 4); + _tcpFallbackTunnel->writeq.append(reinterpret_cast(reinterpret_cast(&(reinterpret_cast(addr)->sin_port))), 2); + _tcpFallbackTunnel->writeq.append((const char*)data, len); + } + } + if (flushNow) { + void* tmpptr = (void*)_tcpFallbackTunnel; + phyOnTcpWritable(_tcpFallbackTunnel->sock, &tmpptr); + } + } + else if (_forceTcpRelay || (((now - _lastSendToGlobalV4) < ZT_TCP_FALLBACK_AFTER) && ((now - _lastSendToGlobalV4) > (ZT_PING_CHECK_INTERVAL / 2)))) { + const InetAddress addr(_fallbackRelayAddress); + TcpConnection* tc = new TcpConnection(); + { + Mutex::Lock _l(_tcpConnections_m); + _tcpConnections.push_back(tc); + } + tc->type = TcpConnection::TCP_TUNNEL_OUTGOING; + tc->remoteAddr = addr; + tc->lastReceive = OSUtils::now(); + tc->parent = this; + tc->sock = (PhySocket*)0; // set in connect handler + tc->messageSize = 0; + bool connected = false; + _phy.tcpConnect(reinterpret_cast(&addr), connected, (void*)tc, true); + } + } + _lastSendToGlobalV4 = now; + } } - const bool r = _phy.udpSend((PhySocket *)((uintptr_t)localSocket),(const struct sockaddr *)addr,data,len); - if ((ttl)&&(addr->ss_family == AF_INET)) { - _phy.setIp4UdpTtl((PhySocket *)((uintptr_t)localSocket),255); + } + if (_forceTcpRelay) { + // Shortcut here so that we don't emit any UDP packets + return 0; + } +#endif // ZT_TCP_FALLBACK_RELAY + + // Even when relaying we still send via UDP. This way if UDP starts + // working we can instantly "fail forward" to it and stop using TCP + // proxy fallback, which is slow. + if ((localSocket != -1) && (localSocket != 0) && (_binder.isUdpSocketValid((PhySocket*)((uintptr_t)localSocket)))) { + if ((ttl) && (addr->ss_family == AF_INET)) { + _phy.setIp4UdpTtl((PhySocket*)((uintptr_t)localSocket), ttl); } - return ((r) ? 0 : -1); - } else { - return ((_binder.udpSendAll(_phy,addr,data,len,ttl)) ? 0 : -1); - } - } + const bool r = _phy.udpSend((PhySocket*)((uintptr_t)localSocket), (const struct sockaddr*)addr, data, len); + if ((ttl) && (addr->ss_family == AF_INET)) { + _phy.setIp4UdpTtl((PhySocket*)((uintptr_t)localSocket), 255); + } + return ((r) ? 0 : -1); + } + else { + return ((_binder.udpSendAll(_phy, addr, data, len, ttl)) ? 0 : -1); + } + } - inline void nodeVirtualNetworkFrameFunction(uint64_t nwid,void **nuptr,uint64_t sourceMac,uint64_t destMac,unsigned int etherType,unsigned int vlanId,const void *data,unsigned int len) - { - NetworkState *n = reinterpret_cast(*nuptr); - if ((!n)||(!n->tap())) { - return; - } - n->tap()->put(MAC(sourceMac),MAC(destMac),etherType,data,len); - } + inline void nodeVirtualNetworkFrameFunction(uint64_t nwid, void** nuptr, uint64_t sourceMac, uint64_t destMac, unsigned int etherType, unsigned int vlanId, const void* data, unsigned int len) + { + NetworkState* n = reinterpret_cast(*nuptr); + if ((! n) || (! n->tap())) { + return; + } + n->tap()->put(MAC(sourceMac), MAC(destMac), etherType, data, len); + } - inline int nodePathCheckFunction(uint64_t ztaddr,const int64_t localSocket,const struct sockaddr_storage *remoteAddr) - { - // Make sure we're not trying to do ZeroTier-over-ZeroTier - { - Mutex::Lock _l(_nets_m); - for(std::map::const_iterator n(_nets.begin());n!=_nets.end();++n) { - if (n->second.tap()) { - std::vector ips(n->second.tap()->ips()); - for(std::vector::const_iterator i(ips.begin());i!=ips.end();++i) { - if (i->containsAddress(*(reinterpret_cast(remoteAddr)))) { - return 0; - } - } - } - } - } + inline int nodePathCheckFunction(uint64_t ztaddr, const int64_t localSocket, const struct sockaddr_storage* remoteAddr) + { + // Make sure we're not trying to do ZeroTier-over-ZeroTier + { + Mutex::Lock _l(_nets_m); + for (std::map::const_iterator n(_nets.begin()); n != _nets.end(); ++n) { + if (n->second.tap()) { + std::vector ips(n->second.tap()->ips()); + for (std::vector::const_iterator i(ips.begin()); i != ips.end(); ++i) { + if (i->containsAddress(*(reinterpret_cast(remoteAddr)))) { + return 0; + } + } + } + } + } - /* Note: I do not think we need to scan for overlap with managed routes - * because of the "route forking" and interface binding that we do. This - * ensures (we hope) that ZeroTier traffic will still take the physical - * path even if its managed routes override this for other traffic. Will - * revisit if we see recursion problems. */ + /* Note: I do not think we need to scan for overlap with managed routes + * because of the "route forking" and interface binding that we do. This + * ensures (we hope) that ZeroTier traffic will still take the physical + * path even if its managed routes override this for other traffic. Will + * revisit if we see recursion problems. */ - // Check blacklists - const Hashtable< uint64_t,std::vector > *blh = (const Hashtable< uint64_t,std::vector > *)0; - const std::vector *gbl = (const std::vector *)0; - if (remoteAddr->ss_family == AF_INET) { - blh = &_v4Blacklists; - gbl = &_globalV4Blacklist; - } else if (remoteAddr->ss_family == AF_INET6) { - blh = &_v6Blacklists; - gbl = &_globalV6Blacklist; - } - if (blh) { - Mutex::Lock _l(_localConfig_m); - const std::vector *l = blh->get(ztaddr); - if (l) { - for(std::vector::const_iterator a(l->begin());a!=l->end();++a) { - if (a->containsAddress(*reinterpret_cast(remoteAddr))) - return 0; - } - } - } - if (gbl) { - for(std::vector::const_iterator a(gbl->begin());a!=gbl->end();++a) { - if (a->containsAddress(*reinterpret_cast(remoteAddr))) - return 0; - } - } - return 1; - } + // Check blacklists + const Hashtable >* blh = (const Hashtable >*)0; + const std::vector* gbl = (const std::vector*)0; + if (remoteAddr->ss_family == AF_INET) { + blh = &_v4Blacklists; + gbl = &_globalV4Blacklist; + } + else if (remoteAddr->ss_family == AF_INET6) { + blh = &_v6Blacklists; + gbl = &_globalV6Blacklist; + } + if (blh) { + Mutex::Lock _l(_localConfig_m); + const std::vector* l = blh->get(ztaddr); + if (l) { + for (std::vector::const_iterator a(l->begin()); a != l->end(); ++a) { + if (a->containsAddress(*reinterpret_cast(remoteAddr))) + return 0; + } + } + } + if (gbl) { + for (std::vector::const_iterator a(gbl->begin()); a != gbl->end(); ++a) { + if (a->containsAddress(*reinterpret_cast(remoteAddr))) + return 0; + } + } + return 1; + } - inline int nodePathLookupFunction(uint64_t ztaddr, int family, struct sockaddr_storage* result) - { - const Hashtable< uint64_t, std::vector >* lh = (const Hashtable< uint64_t, std::vector > *)0; - if (family < 0) - lh = (_node->prng() & 1) ? &_v4Hints : &_v6Hints; - else if (family == AF_INET) - lh = &_v4Hints; - else if (family == AF_INET6) - lh = &_v6Hints; - else return 0; - const std::vector* l = lh->get(ztaddr); - if ((l) && (!l->empty())) { - memcpy(result, &((*l)[(unsigned long)_node->prng() % l->size()]), sizeof(struct sockaddr_storage)); - return 1; - } - else return 0; - } + inline int nodePathLookupFunction(uint64_t ztaddr, int family, struct sockaddr_storage* result) + { + const Hashtable >* lh = (const Hashtable >*)0; + if (family < 0) + lh = (_node->prng() & 1) ? &_v4Hints : &_v6Hints; + else if (family == AF_INET) + lh = &_v4Hints; + else if (family == AF_INET6) + lh = &_v6Hints; + else + return 0; + const std::vector* l = lh->get(ztaddr); + if ((l) && (! l->empty())) { + memcpy(result, &((*l)[(unsigned long)_node->prng() % l->size()]), sizeof(struct sockaddr_storage)); + return 1; + } + else + return 0; + } - inline void tapFrameHandler(uint64_t nwid, const MAC& from, const MAC& to, unsigned int etherType, unsigned int vlanId, const void* data, unsigned int len) - { - _node->processVirtualNetworkFrame((void*)0, OSUtils::now(), nwid, from.toInt(), to.toInt(), etherType, vlanId, data, len, &_nextBackgroundTaskDeadline); - } + inline void tapFrameHandler(uint64_t nwid, const MAC& from, const MAC& to, unsigned int etherType, unsigned int vlanId, const void* data, unsigned int len) + { + _node->processVirtualNetworkFrame((void*)0, OSUtils::now(), nwid, from.toInt(), to.toInt(), etherType, vlanId, data, len, &_nextBackgroundTaskDeadline); + } - inline void onHttpResponseFromClient(TcpConnection* tc) - { - _phy.close(tc->sock); - } + inline void onHttpResponseFromClient(TcpConnection* tc) + { + _phy.close(tc->sock); + } - bool shouldBindInterface(const char* ifname, const InetAddress& ifaddr) - { + bool shouldBindInterface(const char* ifname, const InetAddress& ifaddr) + { #if defined(__linux__) || defined(linux) || defined(__LINUX__) || defined(__linux) - if ((ifname[0] == 'l') && (ifname[1] == 'o')) return false; // loopback - if ((ifname[0] == 'z') && (ifname[1] == 't')) return false; // sanity check: zt# - if ((ifname[0] == 't') && (ifname[1] == 'u') && (ifname[2] == 'n')) return false; // tun# is probably an OpenVPN tunnel or similar - if ((ifname[0] == 't') && (ifname[1] == 'a') && (ifname[2] == 'p')) return false; // tap# is probably an OpenVPN tunnel or similar + if ((ifname[0] == 'l') && (ifname[1] == 'o')) + return false; // loopback + if ((ifname[0] == 'z') && (ifname[1] == 't')) + return false; // sanity check: zt# + if ((ifname[0] == 't') && (ifname[1] == 'u') && (ifname[2] == 'n')) + return false; // tun# is probably an OpenVPN tunnel or similar + if ((ifname[0] == 't') && (ifname[1] == 'a') && (ifname[2] == 'p')) + return false; // tap# is probably an OpenVPN tunnel or similar #endif #ifdef __APPLE__ - if ((ifname[0] == 'f') && (ifname[1] == 'e') && (ifname[2] == 't') && (ifname[3] == 'h')) return false; // ... as is feth# - if ((ifname[0] == 'l') && (ifname[1] == 'o')) return false; // loopback - if ((ifname[0] == 'z') && (ifname[1] == 't')) return false; // sanity check: zt# - if ((ifname[0] == 't') && (ifname[1] == 'u') && (ifname[2] == 'n')) return false; // tun# is probably an OpenVPN tunnel or similar - if ((ifname[0] == 't') && (ifname[1] == 'a') && (ifname[2] == 'p')) return false; // tap# is probably an OpenVPN tunnel or similar - if ((ifname[0] == 'u') && (ifname[1] == 't') && (ifname[2] == 'u') && (ifname[3] == 'n')) return false; // ... as is utun# + if ((ifname[0] == 'f') && (ifname[1] == 'e') && (ifname[2] == 't') && (ifname[3] == 'h')) + return false; // ... as is feth# + if ((ifname[0] == 'l') && (ifname[1] == 'o')) + return false; // loopback + if ((ifname[0] == 'z') && (ifname[1] == 't')) + return false; // sanity check: zt# + if ((ifname[0] == 't') && (ifname[1] == 'u') && (ifname[2] == 'n')) + return false; // tun# is probably an OpenVPN tunnel or similar + if ((ifname[0] == 't') && (ifname[1] == 'a') && (ifname[2] == 'p')) + return false; // tap# is probably an OpenVPN tunnel or similar + if ((ifname[0] == 'u') && (ifname[1] == 't') && (ifname[2] == 'u') && (ifname[3] == 'n')) + return false; // ... as is utun# #endif #ifdef __FreeBSD__ - if ((ifname[0] == 'l') && (ifname[1] == 'o')) return false; // loopback - if ((ifname[0] == 'z') && (ifname[1] == 't')) return false; // sanity check: zt# + if ((ifname[0] == 'l') && (ifname[1] == 'o')) + return false; // loopback + if ((ifname[0] == 'z') && (ifname[1] == 't')) + return false; // sanity check: zt# #endif - { - Mutex::Lock _l(_localConfig_m); - for(std::vector::const_iterator p(_interfacePrefixBlacklist.begin());p!=_interfacePrefixBlacklist.end();++p) { - if (!strncmp(p->c_str(),ifname,p->length())) - return false; - } - } - { - // Check global blacklists - const std::vector *gbl = (const std::vector *)0; - if (ifaddr.ss_family == AF_INET) { - gbl = &_globalV4Blacklist; - } else if (ifaddr.ss_family == AF_INET6) { - gbl = &_globalV6Blacklist; - } - if (gbl) { - Mutex::Lock _l(_localConfig_m); - for(std::vector::const_iterator a(gbl->begin());a!=gbl->end();++a) { - if (a->containsAddress(ifaddr)) - return false; - } - } - } - { - Mutex::Lock _l(_nets_m); - for(std::map::const_iterator n(_nets.begin());n!=_nets.end();++n) { - if (n->second.tap()) { - std::vector ips(n->second.tap()->ips()); - for(std::vector::const_iterator i(ips.begin());i!=ips.end();++i) { - if (i->ipsEqual(ifaddr)) - return false; - } + { + Mutex::Lock _l(_localConfig_m); + for (std::vector::const_iterator p(_interfacePrefixBlacklist.begin()); p != _interfacePrefixBlacklist.end(); ++p) { + if (! strncmp(p->c_str(), ifname, p->length())) + return false; + } + } + { + // Check global blacklists + const std::vector* gbl = (const std::vector*)0; + if (ifaddr.ss_family == AF_INET) { + gbl = &_globalV4Blacklist; + } + else if (ifaddr.ss_family == AF_INET6) { + gbl = &_globalV6Blacklist; + } + if (gbl) { + Mutex::Lock _l(_localConfig_m); + for (std::vector::const_iterator a(gbl->begin()); a != gbl->end(); ++a) { + if (a->containsAddress(ifaddr)) + return false; + } + } + } + { + Mutex::Lock _l(_nets_m); + for (std::map::const_iterator n(_nets.begin()); n != _nets.end(); ++n) { + if (n->second.tap()) { + std::vector ips(n->second.tap()->ips()); + for (std::vector::const_iterator i(ips.begin()); i != ips.end(); ++i) { + if (i->ipsEqual(ifaddr)) + return false; + } #ifdef _WIN32 - if (n->second.tap()->friendlyName() == ifname) - return false; + if (n->second.tap()->friendlyName() == ifname) + return false; #endif - } - } - } + } + } + } - return true; - } + return true; + } - unsigned int _getRandomPort() - { - unsigned int randp = 0; - Utils::getSecureRandom(&randp,sizeof(randp)); - randp = 20000 + (randp % 45500); - for(int i=0;;++i) { - if (i > 1000) { - return 0; - } else if (++randp >= 65536) { - randp = 20000; - } - if (_trialBind(randp)) - break; - } - return randp; - } + unsigned int _getRandomPort() + { + unsigned int randp = 0; + Utils::getSecureRandom(&randp, sizeof(randp)); + randp = 20000 + (randp % 45500); + for (int i = 0;; ++i) { + if (i > 1000) { + return 0; + } + else if (++randp >= 65536) { + randp = 20000; + } + if (_trialBind(randp)) + break; + } + return randp; + } - bool _trialBind(unsigned int port) - { - struct sockaddr_in in4; - struct sockaddr_in6 in6; - PhySocket *tb; + bool _trialBind(unsigned int port) + { + struct sockaddr_in in4; + struct sockaddr_in6 in6; + PhySocket* tb; - memset(&in4,0,sizeof(in4)); - in4.sin_family = AF_INET; - in4.sin_port = Utils::hton((uint16_t)port); - tb = _phy.udpBind(reinterpret_cast(&in4),(void *)0,0); - if (tb) { - _phy.close(tb,false); - tb = _phy.tcpListen(reinterpret_cast(&in4),(void *)0); - if (tb) { - _phy.close(tb,false); - return true; - } - } + memset(&in4, 0, sizeof(in4)); + in4.sin_family = AF_INET; + in4.sin_port = Utils::hton((uint16_t)port); + tb = _phy.udpBind(reinterpret_cast(&in4), (void*)0, 0); + if (tb) { + _phy.close(tb, false); + tb = _phy.tcpListen(reinterpret_cast(&in4), (void*)0); + if (tb) { + _phy.close(tb, false); + return true; + } + } - memset(&in6,0,sizeof(in6)); - in6.sin6_family = AF_INET6; - in6.sin6_port = Utils::hton((uint16_t)port); - tb = _phy.udpBind(reinterpret_cast(&in6),(void *)0,0); - if (tb) { - _phy.close(tb,false); - tb = _phy.tcpListen(reinterpret_cast(&in6),(void *)0); - if (tb) { - _phy.close(tb,false); - return true; - } - } + memset(&in6, 0, sizeof(in6)); + in6.sin6_family = AF_INET6; + in6.sin6_port = Utils::hton((uint16_t)port); + tb = _phy.udpBind(reinterpret_cast(&in6), (void*)0, 0); + if (tb) { + _phy.close(tb, false); + tb = _phy.tcpListen(reinterpret_cast(&in6), (void*)0); + if (tb) { + _phy.close(tb, false); + return true; + } + } - return false; - } + return false; + } }; -static int SnodeVirtualNetworkConfigFunction(ZT_Node *node,void *uptr,void *tptr,uint64_t nwid,void **nuptr,enum ZT_VirtualNetworkConfigOperation op,const ZT_VirtualNetworkConfig *nwconf) -{ return reinterpret_cast(uptr)->nodeVirtualNetworkConfigFunction(nwid,nuptr,op,nwconf); } -static void SnodeEventCallback(ZT_Node *node,void *uptr,void *tptr,enum ZT_Event event,const void *metaData) -{ reinterpret_cast(uptr)->nodeEventCallback(event,metaData); } -static void SnodeStatePutFunction(ZT_Node *node,void *uptr,void *tptr,enum ZT_StateObjectType type,const uint64_t id[2],const void *data,int len) -{ reinterpret_cast(uptr)->nodeStatePutFunction(type,id,data,len); } -static int SnodeStateGetFunction(ZT_Node *node,void *uptr,void *tptr,enum ZT_StateObjectType type,const uint64_t id[2],void *data,unsigned int maxlen) -{ return reinterpret_cast(uptr)->nodeStateGetFunction(type,id,data,maxlen); } -static int SnodeWirePacketSendFunction(ZT_Node *node,void *uptr,void *tptr,int64_t localSocket,const struct sockaddr_storage *addr,const void *data,unsigned int len,unsigned int ttl) -{ return reinterpret_cast(uptr)->nodeWirePacketSendFunction(localSocket,addr,data,len,ttl); } -static void SnodeVirtualNetworkFrameFunction(ZT_Node *node,void *uptr,void *tptr,uint64_t nwid,void **nuptr,uint64_t sourceMac,uint64_t destMac,unsigned int etherType,unsigned int vlanId,const void *data,unsigned int len) -{ reinterpret_cast(uptr)->nodeVirtualNetworkFrameFunction(nwid,nuptr,sourceMac,destMac,etherType,vlanId,data,len); } -static int SnodePathCheckFunction(ZT_Node *node,void *uptr,void *tptr,uint64_t ztaddr,int64_t localSocket,const struct sockaddr_storage *remoteAddr) -{ return reinterpret_cast(uptr)->nodePathCheckFunction(ztaddr,localSocket,remoteAddr); } -static int SnodePathLookupFunction(ZT_Node *node,void *uptr,void *tptr,uint64_t ztaddr,int family,struct sockaddr_storage *result) -{ return reinterpret_cast(uptr)->nodePathLookupFunction(ztaddr,family,result); } -static void StapFrameHandler(void *uptr,void *tptr,uint64_t nwid,const MAC &from,const MAC &to,unsigned int etherType,unsigned int vlanId,const void *data,unsigned int len) -{ reinterpret_cast(uptr)->tapFrameHandler(nwid,from,to,etherType,vlanId,data,len); } - -static int ShttpOnMessageBegin(http_parser *parser) +static int SnodeVirtualNetworkConfigFunction(ZT_Node* node, void* uptr, void* tptr, uint64_t nwid, void** nuptr, enum ZT_VirtualNetworkConfigOperation op, const ZT_VirtualNetworkConfig* nwconf) { - TcpConnection *tc = reinterpret_cast(parser->data); - tc->currentHeaderField = ""; - tc->currentHeaderValue = ""; - tc->messageSize = 0; - tc->url.clear(); - tc->status.clear(); - tc->headers.clear(); - tc->readq.clear(); - return 0; + return reinterpret_cast(uptr)->nodeVirtualNetworkConfigFunction(nwid, nuptr, op, nwconf); } -static int ShttpOnUrl(http_parser *parser,const char *ptr,size_t length) +static void SnodeEventCallback(ZT_Node* node, void* uptr, void* tptr, enum ZT_Event event, const void* metaData) { - TcpConnection *tc = reinterpret_cast(parser->data); - tc->messageSize += (unsigned long)length; - if (tc->messageSize > ZT_MAX_HTTP_MESSAGE_SIZE) - return -1; - tc->url.append(ptr,length); - return 0; + reinterpret_cast(uptr)->nodeEventCallback(event, metaData); +} +static void SnodeStatePutFunction(ZT_Node* node, void* uptr, void* tptr, enum ZT_StateObjectType type, const uint64_t id[2], const void* data, int len) +{ + reinterpret_cast(uptr)->nodeStatePutFunction(type, id, data, len); +} +static int SnodeStateGetFunction(ZT_Node* node, void* uptr, void* tptr, enum ZT_StateObjectType type, const uint64_t id[2], void* data, unsigned int maxlen) +{ + return reinterpret_cast(uptr)->nodeStateGetFunction(type, id, data, maxlen); +} +static int SnodeWirePacketSendFunction(ZT_Node* node, void* uptr, void* tptr, int64_t localSocket, const struct sockaddr_storage* addr, const void* data, unsigned int len, unsigned int ttl) +{ + return reinterpret_cast(uptr)->nodeWirePacketSendFunction(localSocket, addr, data, len, ttl); +} +static void SnodeVirtualNetworkFrameFunction(ZT_Node* node, void* uptr, void* tptr, uint64_t nwid, void** nuptr, uint64_t sourceMac, uint64_t destMac, unsigned int etherType, unsigned int vlanId, const void* data, unsigned int len) +{ + reinterpret_cast(uptr)->nodeVirtualNetworkFrameFunction(nwid, nuptr, sourceMac, destMac, etherType, vlanId, data, len); +} +static int SnodePathCheckFunction(ZT_Node* node, void* uptr, void* tptr, uint64_t ztaddr, int64_t localSocket, const struct sockaddr_storage* remoteAddr) +{ + return reinterpret_cast(uptr)->nodePathCheckFunction(ztaddr, localSocket, remoteAddr); +} +static int SnodePathLookupFunction(ZT_Node* node, void* uptr, void* tptr, uint64_t ztaddr, int family, struct sockaddr_storage* result) +{ + return reinterpret_cast(uptr)->nodePathLookupFunction(ztaddr, family, result); +} +static void StapFrameHandler(void* uptr, void* tptr, uint64_t nwid, const MAC& from, const MAC& to, unsigned int etherType, unsigned int vlanId, const void* data, unsigned int len) +{ + reinterpret_cast(uptr)->tapFrameHandler(nwid, from, to, etherType, vlanId, data, len); +} + +static int ShttpOnMessageBegin(http_parser* parser) +{ + TcpConnection* tc = reinterpret_cast(parser->data); + tc->currentHeaderField = ""; + tc->currentHeaderValue = ""; + tc->messageSize = 0; + tc->url.clear(); + tc->status.clear(); + tc->headers.clear(); + tc->readq.clear(); + return 0; +} +static int ShttpOnUrl(http_parser* parser, const char* ptr, size_t length) +{ + TcpConnection* tc = reinterpret_cast(parser->data); + tc->messageSize += (unsigned long)length; + if (tc->messageSize > ZT_MAX_HTTP_MESSAGE_SIZE) + return -1; + tc->url.append(ptr, length); + return 0; } #if (HTTP_PARSER_VERSION_MAJOR >= 2) && (HTTP_PARSER_VERSION_MINOR >= 2) -static int ShttpOnStatus(http_parser *parser,const char *ptr,size_t length) +static int ShttpOnStatus(http_parser* parser, const char* ptr, size_t length) #else -static int ShttpOnStatus(http_parser *parser) +static int ShttpOnStatus(http_parser* parser) #endif -{ return 0; } -static int ShttpOnHeaderField(http_parser *parser,const char *ptr,size_t length) { - TcpConnection *tc = reinterpret_cast(parser->data); - tc->messageSize += (unsigned long)length; - if (tc->messageSize > ZT_MAX_HTTP_MESSAGE_SIZE) - return -1; - if ((tc->currentHeaderField.length())&&(tc->currentHeaderValue.length())) { - tc->headers[tc->currentHeaderField] = tc->currentHeaderValue; - tc->currentHeaderField = ""; - tc->currentHeaderValue = ""; - } - for(size_t i=0;icurrentHeaderField.push_back(OSUtils::toLower(ptr[i])); - return 0; + return 0; } -static int ShttpOnValue(http_parser *parser,const char *ptr,size_t length) +static int ShttpOnHeaderField(http_parser* parser, const char* ptr, size_t length) { - TcpConnection *tc = reinterpret_cast(parser->data); - tc->messageSize += (unsigned long)length; - if (tc->messageSize > ZT_MAX_HTTP_MESSAGE_SIZE) - return -1; - tc->currentHeaderValue.append(ptr,length); - return 0; + TcpConnection* tc = reinterpret_cast(parser->data); + tc->messageSize += (unsigned long)length; + if (tc->messageSize > ZT_MAX_HTTP_MESSAGE_SIZE) + return -1; + if ((tc->currentHeaderField.length()) && (tc->currentHeaderValue.length())) { + tc->headers[tc->currentHeaderField] = tc->currentHeaderValue; + tc->currentHeaderField = ""; + tc->currentHeaderValue = ""; + } + for (size_t i = 0; i < length; ++i) + tc->currentHeaderField.push_back(OSUtils::toLower(ptr[i])); + return 0; } -static int ShttpOnHeadersComplete(http_parser *parser) +static int ShttpOnValue(http_parser* parser, const char* ptr, size_t length) { - TcpConnection *tc = reinterpret_cast(parser->data); - if ((tc->currentHeaderField.length())&&(tc->currentHeaderValue.length())) - tc->headers[tc->currentHeaderField] = tc->currentHeaderValue; - return 0; + TcpConnection* tc = reinterpret_cast(parser->data); + tc->messageSize += (unsigned long)length; + if (tc->messageSize > ZT_MAX_HTTP_MESSAGE_SIZE) + return -1; + tc->currentHeaderValue.append(ptr, length); + return 0; } -static int ShttpOnBody(http_parser *parser,const char *ptr,size_t length) +static int ShttpOnHeadersComplete(http_parser* parser) { - TcpConnection *tc = reinterpret_cast(parser->data); - tc->messageSize += (unsigned long)length; - if (tc->messageSize > ZT_MAX_HTTP_MESSAGE_SIZE) - return -1; - tc->readq.append(ptr,length); - return 0; + TcpConnection* tc = reinterpret_cast(parser->data); + if ((tc->currentHeaderField.length()) && (tc->currentHeaderValue.length())) + tc->headers[tc->currentHeaderField] = tc->currentHeaderValue; + return 0; } -static int ShttpOnMessageComplete(http_parser *parser) +static int ShttpOnBody(http_parser* parser, const char* ptr, size_t length) { - TcpConnection *tc = reinterpret_cast(parser->data); - if (tc->type == TcpConnection::TCP_HTTP_INCOMING) { - } else { - tc->parent->onHttpResponseFromClient(tc); - } - return 0; + TcpConnection* tc = reinterpret_cast(parser->data); + tc->messageSize += (unsigned long)length; + if (tc->messageSize > ZT_MAX_HTTP_MESSAGE_SIZE) + return -1; + tc->readq.append(ptr, length); + return 0; +} +static int ShttpOnMessageComplete(http_parser* parser) +{ + TcpConnection* tc = reinterpret_cast(parser->data); + if (tc->type == TcpConnection::TCP_HTTP_INCOMING) {} + else { + tc->parent->onHttpResponseFromClient(tc); + } + return 0; } -} // anonymous namespace +} // anonymous namespace std::string OneService::platformDefaultHomePath() { - return OSUtils::platformDefaultHomePath(); + return OSUtils::platformDefaultHomePath(); } -OneService *OneService::newInstance(const char *hp,unsigned int port) { return new OneServiceImpl(hp,port); } -OneService::~OneService() {} +OneService* OneService::newInstance(const char* hp, unsigned int port) +{ + return new OneServiceImpl(hp, port); +} +OneService::~OneService() +{ +} -} // namespace ZeroTier +} // namespace ZeroTier diff --git a/service/OneService.hpp b/service/OneService.hpp index 3f8947ae..abe5c566 100644 --- a/service/OneService.hpp +++ b/service/OneService.hpp @@ -22,7 +22,9 @@ namespace ZeroTier { #ifdef ZT_SDK class VirtualTap; // Use the virtual libzt endpoint instead of a tun/tap port driver -namespace ZeroTier { typedef VirtualTap EthernetTap; } +namespace ZeroTier { +typedef VirtualTap EthernetTap; +} #endif // Forward declaration so we can avoid dragging everything in @@ -32,164 +34,171 @@ class Node; /** * Local service for ZeroTier One as system VPN/NFV provider */ -class OneService -{ -public: - /** - * Returned by node main if/when it terminates - */ - enum ReasonForTermination - { - /** - * Instance is still running - */ - ONE_STILL_RUNNING = 0, +class OneService { + public: + /** + * Returned by node main if/when it terminates + */ + enum ReasonForTermination { + /** + * Instance is still running + */ + ONE_STILL_RUNNING = 0, - /** - * Normal shutdown - */ - ONE_NORMAL_TERMINATION = 1, + /** + * Normal shutdown + */ + ONE_NORMAL_TERMINATION = 1, - /** - * A serious unrecoverable error has occurred - */ - ONE_UNRECOVERABLE_ERROR = 2, + /** + * A serious unrecoverable error has occurred + */ + ONE_UNRECOVERABLE_ERROR = 2, - /** - * Your identity has collided with another - */ - ONE_IDENTITY_COLLISION = 3 - }; + /** + * Your identity has collided with another + */ + ONE_IDENTITY_COLLISION = 3 + }; - /** - * Local settings for each network - */ - struct NetworkSettings - { - /** - * Allow this network to configure IP addresses and routes? - */ - bool allowManaged; + /** + * Local settings for each network + */ + struct NetworkSettings { + /** + * Allow this network to configure IP addresses and routes? + */ + bool allowManaged; - /** - * Whitelist of addresses that can be configured by this network. - * If empty and allowManaged is true, allow all private/pseudoprivate addresses. - */ - std::vector allowManagedWhitelist; + /** + * Whitelist of addresses that can be configured by this network. + * If empty and allowManaged is true, allow all private/pseudoprivate addresses. + */ + std::vector allowManagedWhitelist; - /** - * Allow configuration of IPs and routes within global (Internet) IP space? - */ - bool allowGlobal; + /** + * Allow configuration of IPs and routes within global (Internet) IP space? + */ + bool allowGlobal; - /** - * Allow overriding of system default routes for "full tunnel" operation? - */ - bool allowDefault; + /** + * Allow overriding of system default routes for "full tunnel" operation? + */ + bool allowDefault; - /** - * Allow configuration of DNS for the network - */ - bool allowDNS; - }; + /** + * Allow configuration of DNS for the network + */ + bool allowDNS; + }; - /** - * @return Platform default home path or empty string if this platform doesn't have one - */ - static std::string platformDefaultHomePath(); + /** + * @return Platform default home path or empty string if this platform doesn't have one + */ + static std::string platformDefaultHomePath(); - /** - * Create a new instance of the service - * - * Once created, you must call the run() method to actually start - * processing. - * - * The port is saved to a file in the home path called zerotier-one.port, - * which is used by the CLI and can be used to see which port was chosen if - * 0 (random port) is picked. - * - * @param hp Home path - * @param port TCP and UDP port for packets and HTTP control (if 0, pick random port) - */ - static OneService *newInstance(const char *hp,unsigned int port); + /** + * Create a new instance of the service + * + * Once created, you must call the run() method to actually start + * processing. + * + * The port is saved to a file in the home path called zerotier-one.port, + * which is used by the CLI and can be used to see which port was chosen if + * 0 (random port) is picked. + * + * @param hp Home path + * @param port TCP and UDP port for packets and HTTP control (if 0, pick random port) + */ + static OneService* newInstance(const char* hp, unsigned int port); - virtual ~OneService(); + virtual ~OneService(); - /** - * Execute the service main I/O loop until terminated - * - * The terminate() method may be called from a signal handler or another - * thread to terminate execution. Otherwise this will not return unless - * another condition terminates execution such as a fatal error. - */ - virtual ReasonForTermination run() = 0; + /** + * Execute the service main I/O loop until terminated + * + * The terminate() method may be called from a signal handler or another + * thread to terminate execution. Otherwise this will not return unless + * another condition terminates execution such as a fatal error. + */ + virtual ReasonForTermination run() = 0; - /** - * @return Reason for terminating or ONE_STILL_RUNNING if running - */ - virtual ReasonForTermination reasonForTermination() const = 0; + /** + * @return Reason for terminating or ONE_STILL_RUNNING if running + */ + virtual ReasonForTermination reasonForTermination() const = 0; - /** - * @return Fatal error message or empty string if none - */ - virtual std::string fatalErrorMessage() const = 0; + /** + * @return Fatal error message or empty string if none + */ + virtual std::string fatalErrorMessage() const = 0; - /** - * @return System device name corresponding with a given ZeroTier network ID or empty string if not opened yet or network ID not found - */ - virtual std::string portDeviceName(uint64_t nwid) const = 0; + /** + * @return System device name corresponding with a given ZeroTier network ID or empty string if not opened yet or network ID not found + */ + virtual std::string portDeviceName(uint64_t nwid) const = 0; #ifdef ZT_SDK - /** - * Whether we allow access to the service via local HTTP requests (disabled by default in libzt) - */ - bool allowHttpBackplaneManagement = false; - /** - * @return Reference to the Node - */ - virtual Node * getNode() = 0; - /** - * Fills out a structure with network-specific route information - */ - virtual void getRoutes(uint64_t nwid, void *routeArray, unsigned int *numRoutes) = 0; + /** + * Whether we allow access to the service via local HTTP requests (disabled by default in libzt) + */ + bool allowHttpBackplaneManagement = false; + /** + * @return Reference to the Node + */ + virtual Node* getNode() = 0; + /** + * Fills out a structure with network-specific route information + */ + virtual void getRoutes(uint64_t nwid, void* routeArray, unsigned int* numRoutes) = 0; #endif - /** - * Terminate background service (can be called from other threads) - */ - virtual void terminate() = 0; + /** + * Terminate background service (can be called from other threads) + */ + virtual void terminate() = 0; - /** - * Get local settings for a network - * - * @param nwid Network ID - * @param settings Buffer to fill with local network settings - * @return True if network was found and settings is filled - */ - virtual bool getNetworkSettings(const uint64_t nwid,NetworkSettings &settings) const = 0; + /** + * Get local settings for a network + * + * @param nwid Network ID + * @param settings Buffer to fill with local network settings + * @return True if network was found and settings is filled + */ + virtual bool getNetworkSettings(const uint64_t nwid, NetworkSettings& settings) const = 0; - /** - * Set local settings for a network - * - * @param nwid Network ID - * @param settings New network local settings - * @return True if network was found and setting modified - */ - virtual bool setNetworkSettings(const uint64_t nwid,const NetworkSettings &settings) = 0; + /** + * Set local settings for a network + * + * @param nwid Network ID + * @param settings New network local settings + * @return True if network was found and setting modified + */ + virtual bool setNetworkSettings(const uint64_t nwid, const NetworkSettings& settings) = 0; - /** - * @return True if service is still running - */ - inline bool isRunning() const { return (this->reasonForTermination() == ONE_STILL_RUNNING); } + /** + * @return True if service is still running + */ + inline bool isRunning() const + { + return (this->reasonForTermination() == ONE_STILL_RUNNING); + } -protected: - OneService() {} + protected: + OneService() + { + } -private: - OneService(const OneService &one) {} - inline OneService &operator=(const OneService &one) { return *this; } + private: + OneService(const OneService& one) + { + } + inline OneService& operator=(const OneService& one) + { + return *this; + } }; -} // namespace ZeroTier +} // namespace ZeroTier #endif diff --git a/service/SoftwareUpdater.cpp b/service/SoftwareUpdater.cpp index 8335e389..0800a44c 100644 --- a/service/SoftwareUpdater.cpp +++ b/service/SoftwareUpdater.cpp @@ -11,416 +11,436 @@ */ /****/ -#include -#include -#include -#include - #include "../node/Constants.hpp" #include "../version.h" +#include +#include +#include +#include + #ifdef __WINDOWS__ -#include -#include -#include -#include #include +#include +#include +#include +#include #else -#include +#include #include +#include #include #include -#include #endif -#include "SoftwareUpdater.hpp" - -#include "../node/Utils.hpp" -#include "../node/SHA512.hpp" #include "../node/Buffer.hpp" #include "../node/Node.hpp" - +#include "../node/SHA512.hpp" +#include "../node/Utils.hpp" #include "../osdep/OSUtils.hpp" +#include "SoftwareUpdater.hpp" namespace ZeroTier { -static int _compareVersion(unsigned int maj1,unsigned int min1,unsigned int rev1,unsigned int b1,unsigned int maj2,unsigned int min2,unsigned int rev2,unsigned int b2) +static int _compareVersion(unsigned int maj1, unsigned int min1, unsigned int rev1, unsigned int b1, unsigned int maj2, unsigned int min2, unsigned int rev2, unsigned int b2) { - if (maj1 > maj2) { - return 1; - } else if (maj1 < maj2) { - return -1; - } else { - if (min1 > min2) { - return 1; - } else if (min1 < min2) { - return -1; - } else { - if (rev1 > rev2) { - return 1; - } else if (rev1 < rev2) { - return -1; - } else { - if (b1 > b2) { - return 1; - } else if (b1 < b2) { - return -1; - } else { - return 0; - } - } - } - } + if (maj1 > maj2) { + return 1; + } + else if (maj1 < maj2) { + return -1; + } + else { + if (min1 > min2) { + return 1; + } + else if (min1 < min2) { + return -1; + } + else { + if (rev1 > rev2) { + return 1; + } + else if (rev1 < rev2) { + return -1; + } + else { + if (b1 > b2) { + return 1; + } + else if (b1 < b2) { + return -1; + } + else { + return 0; + } + } + } + } } -SoftwareUpdater::SoftwareUpdater(Node &node,const std::string &homePath) : - _node(node), - _lastCheckTime(0), - _homePath(homePath), - _channel(ZT_SOFTWARE_UPDATE_DEFAULT_CHANNEL), - _distLog((FILE *)0), - _latestValid(false), - _downloadLength(0) +SoftwareUpdater::SoftwareUpdater(Node& node, const std::string& homePath) : _node(node), _lastCheckTime(0), _homePath(homePath), _channel(ZT_SOFTWARE_UPDATE_DEFAULT_CHANNEL), _distLog((FILE*)0), _latestValid(false), _downloadLength(0) { - OSUtils::rm((_homePath + ZT_PATH_SEPARATOR_S ZT_SOFTWARE_UPDATE_BIN_FILENAME).c_str()); + OSUtils::rm((_homePath + ZT_PATH_SEPARATOR_S ZT_SOFTWARE_UPDATE_BIN_FILENAME).c_str()); } SoftwareUpdater::~SoftwareUpdater() { - if (_distLog) - fclose(_distLog); + if (_distLog) + fclose(_distLog); } void SoftwareUpdater::setUpdateDistribution(bool distribute) { - _dist.clear(); - if (distribute) { - _distLog = fopen((_homePath + ZT_PATH_SEPARATOR_S "update-dist.log").c_str(),"a"); + _dist.clear(); + if (distribute) { + _distLog = fopen((_homePath + ZT_PATH_SEPARATOR_S "update-dist.log").c_str(), "a"); - const std::string udd(_homePath + ZT_PATH_SEPARATOR_S "update-dist.d"); - const std::vector ud(OSUtils::listDirectory(udd.c_str())); - for(std::vector::const_iterator u(ud.begin());u!=ud.end();++u) { - // Each update has a companion .json file describing it. Other files are ignored. - if ((u->length() > 5)&&(u->substr(u->length() - 5,5) == ".json")) { + const std::string udd(_homePath + ZT_PATH_SEPARATOR_S "update-dist.d"); + const std::vector ud(OSUtils::listDirectory(udd.c_str())); + for (std::vector::const_iterator u(ud.begin()); u != ud.end(); ++u) { + // Each update has a companion .json file describing it. Other files are ignored. + if ((u->length() > 5) && (u->substr(u->length() - 5, 5) == ".json")) { + std::string buf; + if (OSUtils::readFile((udd + ZT_PATH_SEPARATOR_S + *u).c_str(), buf)) { + try { + _D d; + d.meta = OSUtils::jsonParse(buf); // throws on invalid JSON - std::string buf; - if (OSUtils::readFile((udd + ZT_PATH_SEPARATOR_S + *u).c_str(),buf)) { - try { - _D d; - d.meta = OSUtils::jsonParse(buf); // throws on invalid JSON - - // If update meta is called e.g. foo.exe.json, then foo.exe is the update itself - const std::string binPath(udd + ZT_PATH_SEPARATOR_S + u->substr(0,u->length() - 5)); - const std::string metaHash(OSUtils::jsonBinFromHex(d.meta[ZT_SOFTWARE_UPDATE_JSON_UPDATE_HASH])); - if ((metaHash.length() == 64)&&(OSUtils::readFile(binPath.c_str(),d.bin))) { - std::array sha512; - SHA512(sha512.data(),d.bin.data(),(unsigned int)d.bin.length()); - if (!memcmp(sha512.data(),metaHash.data(),64)) { // double check that hash in JSON is correct - d.meta[ZT_SOFTWARE_UPDATE_JSON_UPDATE_SIZE] = d.bin.length(); // override with correct value -- setting this in meta json is optional - std::array shakey; - memcpy(shakey.data(),sha512.data(),16); - _dist[shakey] = d; - if (_distLog) { - fprintf(_distLog,".......... INIT: DISTRIBUTING %s (%u bytes)" ZT_EOL_S,binPath.c_str(),(unsigned int)d.bin.length()); - fflush(_distLog); - } - } - } - } catch ( ... ) {} // ignore bad meta JSON, etc. - } - - } - } - } else { - if (_distLog) { - fclose(_distLog); - _distLog = (FILE *)0; - } - } + // If update meta is called e.g. foo.exe.json, then foo.exe is the update itself + const std::string binPath(udd + ZT_PATH_SEPARATOR_S + u->substr(0, u->length() - 5)); + const std::string metaHash(OSUtils::jsonBinFromHex(d.meta[ZT_SOFTWARE_UPDATE_JSON_UPDATE_HASH])); + if ((metaHash.length() == 64) && (OSUtils::readFile(binPath.c_str(), d.bin))) { + std::array sha512; + SHA512(sha512.data(), d.bin.data(), (unsigned int)d.bin.length()); + if (! memcmp(sha512.data(), metaHash.data(), 64)) { // double check that hash in JSON is correct + d.meta[ZT_SOFTWARE_UPDATE_JSON_UPDATE_SIZE] = d.bin.length(); // override with correct value -- setting this in meta json is optional + std::array shakey; + memcpy(shakey.data(), sha512.data(), 16); + _dist[shakey] = d; + if (_distLog) { + fprintf(_distLog, ".......... INIT: DISTRIBUTING %s (%u bytes)" ZT_EOL_S, binPath.c_str(), (unsigned int)d.bin.length()); + fflush(_distLog); + } + } + } + } + catch (...) { + } // ignore bad meta JSON, etc. + } + } + } + } + else { + if (_distLog) { + fclose(_distLog); + _distLog = (FILE*)0; + } + } } -void SoftwareUpdater::handleSoftwareUpdateUserMessage(uint64_t origin,const void *data,unsigned int len) +void SoftwareUpdater::handleSoftwareUpdateUserMessage(uint64_t origin, const void* data, unsigned int len) { - if (!len) return; - const MessageVerb v = (MessageVerb)reinterpret_cast(data)[0]; - try { - switch(v) { + if (! len) + return; + const MessageVerb v = (MessageVerb) reinterpret_cast(data)[0]; + try { + switch (v) { + case VERB_GET_LATEST: + case VERB_LATEST: { + nlohmann::json req = OSUtils::jsonParse(std::string(reinterpret_cast(data) + 1, len - 1)); // throws on invalid JSON + if (req.is_object()) { + const unsigned int rvMaj = (unsigned int)OSUtils::jsonInt(req[ZT_SOFTWARE_UPDATE_JSON_VERSION_MAJOR], 0); + const unsigned int rvMin = (unsigned int)OSUtils::jsonInt(req[ZT_SOFTWARE_UPDATE_JSON_VERSION_MINOR], 0); + const unsigned int rvRev = (unsigned int)OSUtils::jsonInt(req[ZT_SOFTWARE_UPDATE_JSON_VERSION_REVISION], 0); + const unsigned int rvBld = (unsigned int)OSUtils::jsonInt(req[ZT_SOFTWARE_UPDATE_JSON_VERSION_BUILD], 0); + const unsigned int rvPlatform = (unsigned int)OSUtils::jsonInt(req[ZT_SOFTWARE_UPDATE_JSON_PLATFORM], 0); + const unsigned int rvArch = (unsigned int)OSUtils::jsonInt(req[ZT_SOFTWARE_UPDATE_JSON_ARCHITECTURE], 0); + const unsigned int rvVendor = (unsigned int)OSUtils::jsonInt(req[ZT_SOFTWARE_UPDATE_JSON_VENDOR], 0); + const std::string rvChannel(OSUtils::jsonString(req[ZT_SOFTWARE_UPDATE_JSON_CHANNEL], "")); - case VERB_GET_LATEST: - case VERB_LATEST: { - nlohmann::json req = OSUtils::jsonParse(std::string(reinterpret_cast(data) + 1,len - 1)); // throws on invalid JSON - if (req.is_object()) { - const unsigned int rvMaj = (unsigned int)OSUtils::jsonInt(req[ZT_SOFTWARE_UPDATE_JSON_VERSION_MAJOR],0); - const unsigned int rvMin = (unsigned int)OSUtils::jsonInt(req[ZT_SOFTWARE_UPDATE_JSON_VERSION_MINOR],0); - const unsigned int rvRev = (unsigned int)OSUtils::jsonInt(req[ZT_SOFTWARE_UPDATE_JSON_VERSION_REVISION],0); - const unsigned int rvBld = (unsigned int)OSUtils::jsonInt(req[ZT_SOFTWARE_UPDATE_JSON_VERSION_BUILD],0); - const unsigned int rvPlatform = (unsigned int)OSUtils::jsonInt(req[ZT_SOFTWARE_UPDATE_JSON_PLATFORM],0); - const unsigned int rvArch = (unsigned int)OSUtils::jsonInt(req[ZT_SOFTWARE_UPDATE_JSON_ARCHITECTURE],0); - const unsigned int rvVendor = (unsigned int)OSUtils::jsonInt(req[ZT_SOFTWARE_UPDATE_JSON_VENDOR],0); - const std::string rvChannel(OSUtils::jsonString(req[ZT_SOFTWARE_UPDATE_JSON_CHANNEL],"")); + if (v == VERB_GET_LATEST) { + if (! _dist.empty()) { + const nlohmann::json* latest = (const nlohmann::json*)0; + const std::string expectedSigner = OSUtils::jsonString(req[ZT_SOFTWARE_UPDATE_JSON_EXPECT_SIGNED_BY], ""); + unsigned int bestVMaj = rvMaj; + unsigned int bestVMin = rvMin; + unsigned int bestVRev = rvRev; + unsigned int bestVBld = rvBld; + for (std::map, _D>::const_iterator d(_dist.begin()); d != _dist.end(); ++d) { + // The arch field in update description .json files can be an array for e.g. multi-arch update files + const nlohmann::json& dvArch2 = d->second.meta[ZT_SOFTWARE_UPDATE_JSON_ARCHITECTURE]; + std::vector dvArch; + if (dvArch2.is_array()) { + for (unsigned long i = 0; i < dvArch2.size(); ++i) + dvArch.push_back((unsigned int)OSUtils::jsonInt(dvArch2[i], 0)); + } + else { + dvArch.push_back((unsigned int)OSUtils::jsonInt(dvArch2, 0)); + } - if (v == VERB_GET_LATEST) { + if ((OSUtils::jsonInt(d->second.meta[ZT_SOFTWARE_UPDATE_JSON_PLATFORM], 0) == rvPlatform) && (std::find(dvArch.begin(), dvArch.end(), rvArch) != dvArch.end()) + && (OSUtils::jsonInt(d->second.meta[ZT_SOFTWARE_UPDATE_JSON_VENDOR], 0) == rvVendor) && (OSUtils::jsonString(d->second.meta[ZT_SOFTWARE_UPDATE_JSON_CHANNEL], "") == rvChannel) + && (OSUtils::jsonString(d->second.meta[ZT_SOFTWARE_UPDATE_JSON_UPDATE_SIGNED_BY], "") == expectedSigner)) { + const unsigned int dvMaj = (unsigned int)OSUtils::jsonInt(d->second.meta[ZT_SOFTWARE_UPDATE_JSON_VERSION_MAJOR], 0); + const unsigned int dvMin = (unsigned int)OSUtils::jsonInt(d->second.meta[ZT_SOFTWARE_UPDATE_JSON_VERSION_MINOR], 0); + const unsigned int dvRev = (unsigned int)OSUtils::jsonInt(d->second.meta[ZT_SOFTWARE_UPDATE_JSON_VERSION_REVISION], 0); + const unsigned int dvBld = (unsigned int)OSUtils::jsonInt(d->second.meta[ZT_SOFTWARE_UPDATE_JSON_VERSION_BUILD], 0); + if (_compareVersion(dvMaj, dvMin, dvRev, dvBld, bestVMaj, bestVMin, bestVRev, bestVBld) > 0) { + latest = &(d->second.meta); + bestVMaj = dvMaj; + bestVMin = dvMin; + bestVRev = dvRev; + bestVBld = dvBld; + } + } + } + if (latest) { + std::string lj; + lj.push_back((char)VERB_LATEST); + lj.append(OSUtils::jsonDump(*latest)); + _node.sendUserMessage((void*)0, origin, ZT_SOFTWARE_UPDATE_USER_MESSAGE_TYPE, lj.data(), (unsigned int)lj.length()); + if (_distLog) { + fprintf( + _distLog, + "%.10llx GET_LATEST %u.%u.%u_%u platform %u arch %u vendor %u channel %s -> LATEST %u.%u.%u_%u" ZT_EOL_S, + (unsigned long long)origin, + rvMaj, + rvMin, + rvRev, + rvBld, + rvPlatform, + rvArch, + rvVendor, + rvChannel.c_str(), + bestVMaj, + bestVMin, + bestVRev, + bestVBld); + fflush(_distLog); + } + } + } // else no reply, since we have nothing to distribute + } + else { // VERB_LATEST - if (!_dist.empty()) { - const nlohmann::json *latest = (const nlohmann::json *)0; - const std::string expectedSigner = OSUtils::jsonString(req[ZT_SOFTWARE_UPDATE_JSON_EXPECT_SIGNED_BY],""); - unsigned int bestVMaj = rvMaj; - unsigned int bestVMin = rvMin; - unsigned int bestVRev = rvRev; - unsigned int bestVBld = rvBld; - for(std::map< std::array,_D >::const_iterator d(_dist.begin());d!=_dist.end();++d) { - // The arch field in update description .json files can be an array for e.g. multi-arch update files - const nlohmann::json &dvArch2 = d->second.meta[ZT_SOFTWARE_UPDATE_JSON_ARCHITECTURE]; - std::vector dvArch; - if (dvArch2.is_array()) { - for(unsigned long i=0;i 0) + && (OSUtils::jsonString(req[ZT_SOFTWARE_UPDATE_JSON_UPDATE_SIGNED_BY], "") == ZT_SOFTWARE_UPDATE_SIGNING_AUTHORITY)) { + const unsigned long len = (unsigned long)OSUtils::jsonInt(req[ZT_SOFTWARE_UPDATE_JSON_UPDATE_SIZE], 0); + const std::string hash = OSUtils::jsonBinFromHex(req[ZT_SOFTWARE_UPDATE_JSON_UPDATE_HASH]); + if ((len <= ZT_SOFTWARE_UPDATE_MAX_SIZE) && (hash.length() >= 16)) { + if (_latestMeta != req) { + _latestMeta = req; + _latestValid = false; + OSUtils::rm((_homePath + ZT_PATH_SEPARATOR_S ZT_SOFTWARE_UPDATE_BIN_FILENAME).c_str()); + _download = std::string(); + memcpy(_downloadHashPrefix.data(), hash.data(), 16); + _downloadLength = len; + } - if ((OSUtils::jsonInt(d->second.meta[ZT_SOFTWARE_UPDATE_JSON_PLATFORM],0) == rvPlatform)&& - (std::find(dvArch.begin(),dvArch.end(),rvArch) != dvArch.end())&& - (OSUtils::jsonInt(d->second.meta[ZT_SOFTWARE_UPDATE_JSON_VENDOR],0) == rvVendor)&& - (OSUtils::jsonString(d->second.meta[ZT_SOFTWARE_UPDATE_JSON_CHANNEL],"") == rvChannel)&& - (OSUtils::jsonString(d->second.meta[ZT_SOFTWARE_UPDATE_JSON_UPDATE_SIGNED_BY],"") == expectedSigner)) { - const unsigned int dvMaj = (unsigned int)OSUtils::jsonInt(d->second.meta[ZT_SOFTWARE_UPDATE_JSON_VERSION_MAJOR],0); - const unsigned int dvMin = (unsigned int)OSUtils::jsonInt(d->second.meta[ZT_SOFTWARE_UPDATE_JSON_VERSION_MINOR],0); - const unsigned int dvRev = (unsigned int)OSUtils::jsonInt(d->second.meta[ZT_SOFTWARE_UPDATE_JSON_VERSION_REVISION],0); - const unsigned int dvBld = (unsigned int)OSUtils::jsonInt(d->second.meta[ZT_SOFTWARE_UPDATE_JSON_VERSION_BUILD],0); - if (_compareVersion(dvMaj,dvMin,dvRev,dvBld,bestVMaj,bestVMin,bestVRev,bestVBld) > 0) { - latest = &(d->second.meta); - bestVMaj = dvMaj; - bestVMin = dvMin; - bestVRev = dvRev; - bestVBld = dvBld; - } - } - } - if (latest) { - std::string lj; - lj.push_back((char)VERB_LATEST); - lj.append(OSUtils::jsonDump(*latest)); - _node.sendUserMessage((void *)0,origin,ZT_SOFTWARE_UPDATE_USER_MESSAGE_TYPE,lj.data(),(unsigned int)lj.length()); - if (_distLog) { - fprintf(_distLog,"%.10llx GET_LATEST %u.%u.%u_%u platform %u arch %u vendor %u channel %s -> LATEST %u.%u.%u_%u" ZT_EOL_S,(unsigned long long)origin,rvMaj,rvMin,rvRev,rvBld,rvPlatform,rvArch,rvVendor,rvChannel.c_str(),bestVMaj,bestVMin,bestVRev,bestVBld); - fflush(_distLog); - } - } - } // else no reply, since we have nothing to distribute + if ((_downloadLength > 0) && (_download.length() < _downloadLength)) { + Buffer<128> gd; + gd.append((uint8_t)VERB_GET_DATA); + gd.append(_downloadHashPrefix.data(), 16); + gd.append((uint32_t)_download.length()); + _node.sendUserMessage((void*)0, ZT_SOFTWARE_UPDATE_SERVICE, ZT_SOFTWARE_UPDATE_USER_MESSAGE_TYPE, gd.data(), gd.size()); + } + } + } + } + } + } break; - } else { // VERB_LATEST + case VERB_GET_DATA: + if ((len >= 21) && (! _dist.empty())) { + unsigned long idx = (unsigned long)*(reinterpret_cast(data) + 17) << 24; + idx |= (unsigned long)*(reinterpret_cast(data) + 18) << 16; + idx |= (unsigned long)*(reinterpret_cast(data) + 19) << 8; + idx |= (unsigned long)*(reinterpret_cast(data) + 20); + std::array shakey; + memcpy(shakey.data(), reinterpret_cast(data) + 1, 16); + std::map, _D>::iterator d(_dist.find(shakey)); + if ((d != _dist.end()) && (idx < (unsigned long)d->second.bin.length())) { + Buffer buf; + buf.append((uint8_t)VERB_DATA); + buf.append(reinterpret_cast(data) + 1, 16); + buf.append((uint32_t)idx); + buf.append(d->second.bin.data() + idx, std::min((unsigned long)ZT_SOFTWARE_UPDATE_CHUNK_SIZE, (unsigned long)(d->second.bin.length() - idx))); + _node.sendUserMessage((void*)0, origin, ZT_SOFTWARE_UPDATE_USER_MESSAGE_TYPE, buf.data(), buf.size()); + } + } + break; - if ((origin == ZT_SOFTWARE_UPDATE_SERVICE)&& - (_compareVersion(rvMaj,rvMin,rvRev,rvBld,ZEROTIER_ONE_VERSION_MAJOR,ZEROTIER_ONE_VERSION_MINOR,ZEROTIER_ONE_VERSION_REVISION,ZEROTIER_ONE_VERSION_BUILD) > 0)&& - (OSUtils::jsonString(req[ZT_SOFTWARE_UPDATE_JSON_UPDATE_SIGNED_BY],"") == ZT_SOFTWARE_UPDATE_SIGNING_AUTHORITY)) { - const unsigned long len = (unsigned long)OSUtils::jsonInt(req[ZT_SOFTWARE_UPDATE_JSON_UPDATE_SIZE],0); - const std::string hash = OSUtils::jsonBinFromHex(req[ZT_SOFTWARE_UPDATE_JSON_UPDATE_HASH]); - if ((len <= ZT_SOFTWARE_UPDATE_MAX_SIZE)&&(hash.length() >= 16)) { - if (_latestMeta != req) { - _latestMeta = req; - _latestValid = false; - OSUtils::rm((_homePath + ZT_PATH_SEPARATOR_S ZT_SOFTWARE_UPDATE_BIN_FILENAME).c_str()); - _download = std::string(); - memcpy(_downloadHashPrefix.data(),hash.data(),16); - _downloadLength = len; - } + case VERB_DATA: + if ((len >= 21) && (_downloadLength > 0) && (! memcmp(_downloadHashPrefix.data(), reinterpret_cast(data) + 1, 16))) { + unsigned long idx = (unsigned long)*(reinterpret_cast(data) + 17) << 24; + idx |= (unsigned long)*(reinterpret_cast(data) + 18) << 16; + idx |= (unsigned long)*(reinterpret_cast(data) + 19) << 8; + idx |= (unsigned long)*(reinterpret_cast(data) + 20); + if (idx == (unsigned long)_download.length()) { + _download.append(reinterpret_cast(data) + 21, len - 21); + if (_download.length() < _downloadLength) { + Buffer<128> gd; + gd.append((uint8_t)VERB_GET_DATA); + gd.append(_downloadHashPrefix.data(), 16); + gd.append((uint32_t)_download.length()); + _node.sendUserMessage((void*)0, ZT_SOFTWARE_UPDATE_SERVICE, ZT_SOFTWARE_UPDATE_USER_MESSAGE_TYPE, gd.data(), gd.size()); + } + } + } + break; - if ((_downloadLength > 0)&&(_download.length() < _downloadLength)) { - Buffer<128> gd; - gd.append((uint8_t)VERB_GET_DATA); - gd.append(_downloadHashPrefix.data(),16); - gd.append((uint32_t)_download.length()); - _node.sendUserMessage((void *)0,ZT_SOFTWARE_UPDATE_SERVICE,ZT_SOFTWARE_UPDATE_USER_MESSAGE_TYPE,gd.data(),gd.size()); - } - } - } - } - - } - } break; - - case VERB_GET_DATA: - if ((len >= 21)&&(!_dist.empty())) { - unsigned long idx = (unsigned long)*(reinterpret_cast(data) + 17) << 24; - idx |= (unsigned long)*(reinterpret_cast(data) + 18) << 16; - idx |= (unsigned long)*(reinterpret_cast(data) + 19) << 8; - idx |= (unsigned long)*(reinterpret_cast(data) + 20); - std::array shakey; - memcpy(shakey.data(),reinterpret_cast(data) + 1,16); - std::map< std::array,_D >::iterator d(_dist.find(shakey)); - if ((d != _dist.end())&&(idx < (unsigned long)d->second.bin.length())) { - Buffer buf; - buf.append((uint8_t)VERB_DATA); - buf.append(reinterpret_cast(data) + 1,16); - buf.append((uint32_t)idx); - buf.append(d->second.bin.data() + idx,std::min((unsigned long)ZT_SOFTWARE_UPDATE_CHUNK_SIZE,(unsigned long)(d->second.bin.length() - idx))); - _node.sendUserMessage((void *)0,origin,ZT_SOFTWARE_UPDATE_USER_MESSAGE_TYPE,buf.data(),buf.size()); - } - } - break; - - case VERB_DATA: - if ((len >= 21)&&(_downloadLength > 0)&&(!memcmp(_downloadHashPrefix.data(),reinterpret_cast(data) + 1,16))) { - unsigned long idx = (unsigned long)*(reinterpret_cast(data) + 17) << 24; - idx |= (unsigned long)*(reinterpret_cast(data) + 18) << 16; - idx |= (unsigned long)*(reinterpret_cast(data) + 19) << 8; - idx |= (unsigned long)*(reinterpret_cast(data) + 20); - if (idx == (unsigned long)_download.length()) { - _download.append(reinterpret_cast(data) + 21,len - 21); - if (_download.length() < _downloadLength) { - Buffer<128> gd; - gd.append((uint8_t)VERB_GET_DATA); - gd.append(_downloadHashPrefix.data(),16); - gd.append((uint32_t)_download.length()); - _node.sendUserMessage((void *)0,ZT_SOFTWARE_UPDATE_SERVICE,ZT_SOFTWARE_UPDATE_USER_MESSAGE_TYPE,gd.data(),gd.size()); - } - } - } - break; - - default: - if (_distLog) { - fprintf(_distLog,"%.10llx WARNING: bad update message verb==%u length==%u (unrecognized verb)" ZT_EOL_S,(unsigned long long)origin,(unsigned int)v,len); - fflush(_distLog); - } - break; - } - } catch ( ... ) { - if (_distLog) { - fprintf(_distLog,"%.10llx WARNING: bad update message verb==%u length==%u (unexpected exception, likely invalid JSON)" ZT_EOL_S,(unsigned long long)origin,(unsigned int)v,len); - fflush(_distLog); - } - } + default: + if (_distLog) { + fprintf(_distLog, "%.10llx WARNING: bad update message verb==%u length==%u (unrecognized verb)" ZT_EOL_S, (unsigned long long)origin, (unsigned int)v, len); + fflush(_distLog); + } + break; + } + } + catch (...) { + if (_distLog) { + fprintf(_distLog, "%.10llx WARNING: bad update message verb==%u length==%u (unexpected exception, likely invalid JSON)" ZT_EOL_S, (unsigned long long)origin, (unsigned int)v, len); + fflush(_distLog); + } + } } bool SoftwareUpdater::check(const int64_t now) { - if ((now - _lastCheckTime) >= ZT_SOFTWARE_UPDATE_CHECK_PERIOD) { - _lastCheckTime = now; - char tmp[512]; - const unsigned int len = OSUtils::ztsnprintf(tmp,sizeof(tmp), - "%c{\"" ZT_SOFTWARE_UPDATE_JSON_VERSION_MAJOR "\":%d," - "\"" ZT_SOFTWARE_UPDATE_JSON_VERSION_MINOR "\":%d," - "\"" ZT_SOFTWARE_UPDATE_JSON_VERSION_REVISION "\":%d," - "\"" ZT_SOFTWARE_UPDATE_JSON_VERSION_BUILD "\":%d," - "\"" ZT_SOFTWARE_UPDATE_JSON_EXPECT_SIGNED_BY "\":\"%s\"," - "\"" ZT_SOFTWARE_UPDATE_JSON_PLATFORM "\":%d," - "\"" ZT_SOFTWARE_UPDATE_JSON_ARCHITECTURE "\":%d," - "\"" ZT_SOFTWARE_UPDATE_JSON_VENDOR "\":%d," - "\"" ZT_SOFTWARE_UPDATE_JSON_CHANNEL "\":\"%s\"}", - (char)VERB_GET_LATEST, - ZEROTIER_ONE_VERSION_MAJOR, - ZEROTIER_ONE_VERSION_MINOR, - ZEROTIER_ONE_VERSION_REVISION, - ZEROTIER_ONE_VERSION_BUILD, - ZT_SOFTWARE_UPDATE_SIGNING_AUTHORITY, - ZT_BUILD_PLATFORM, - ZT_BUILD_ARCHITECTURE, - (int)ZT_VENDOR_ZEROTIER, - _channel.c_str()); - _node.sendUserMessage((void *)0,ZT_SOFTWARE_UPDATE_SERVICE,ZT_SOFTWARE_UPDATE_USER_MESSAGE_TYPE,tmp,len); - } + if ((now - _lastCheckTime) >= ZT_SOFTWARE_UPDATE_CHECK_PERIOD) { + _lastCheckTime = now; + char tmp[512]; + const unsigned int len = OSUtils::ztsnprintf( + tmp, + sizeof(tmp), + "%c{\"" ZT_SOFTWARE_UPDATE_JSON_VERSION_MAJOR "\":%d," + "\"" ZT_SOFTWARE_UPDATE_JSON_VERSION_MINOR "\":%d," + "\"" ZT_SOFTWARE_UPDATE_JSON_VERSION_REVISION "\":%d," + "\"" ZT_SOFTWARE_UPDATE_JSON_VERSION_BUILD "\":%d," + "\"" ZT_SOFTWARE_UPDATE_JSON_EXPECT_SIGNED_BY "\":\"%s\"," + "\"" ZT_SOFTWARE_UPDATE_JSON_PLATFORM "\":%d," + "\"" ZT_SOFTWARE_UPDATE_JSON_ARCHITECTURE "\":%d," + "\"" ZT_SOFTWARE_UPDATE_JSON_VENDOR "\":%d," + "\"" ZT_SOFTWARE_UPDATE_JSON_CHANNEL "\":\"%s\"}", + (char)VERB_GET_LATEST, + ZEROTIER_ONE_VERSION_MAJOR, + ZEROTIER_ONE_VERSION_MINOR, + ZEROTIER_ONE_VERSION_REVISION, + ZEROTIER_ONE_VERSION_BUILD, + ZT_SOFTWARE_UPDATE_SIGNING_AUTHORITY, + ZT_BUILD_PLATFORM, + ZT_BUILD_ARCHITECTURE, + (int)ZT_VENDOR_ZEROTIER, + _channel.c_str()); + _node.sendUserMessage((void*)0, ZT_SOFTWARE_UPDATE_SERVICE, ZT_SOFTWARE_UPDATE_USER_MESSAGE_TYPE, tmp, len); + } - if (_latestValid) - return true; + if (_latestValid) + return true; - if (_downloadLength > 0) { - if (_download.length() >= _downloadLength) { - // This is the very important security validation part that makes sure - // this software update doesn't have cooties. + if (_downloadLength > 0) { + if (_download.length() >= _downloadLength) { + // This is the very important security validation part that makes sure + // this software update doesn't have cooties. - const std::string binPath(_homePath + ZT_PATH_SEPARATOR_S ZT_SOFTWARE_UPDATE_BIN_FILENAME); - try { - // (1) Check the hash itself to make sure the image is basically okay - uint8_t sha512[64]; - SHA512(sha512,_download.data(),(unsigned int)_download.length()); - char hexbuf[(64 * 2) + 2]; - if (OSUtils::jsonString(_latestMeta[ZT_SOFTWARE_UPDATE_JSON_UPDATE_HASH],"") == Utils::hex(sha512,64,hexbuf)) { - // (2) Check signature by signing authority - const std::string sig(OSUtils::jsonBinFromHex(_latestMeta[ZT_SOFTWARE_UPDATE_JSON_UPDATE_SIGNATURE])); - if (Identity(ZT_SOFTWARE_UPDATE_SIGNING_AUTHORITY).verify(_download.data(),(unsigned int)_download.length(),sig.data(),(unsigned int)sig.length())) { - // (3) Try to save file, and if so we are good. - OSUtils::rm(binPath.c_str()); - if (OSUtils::writeFile(binPath.c_str(),_download)) { - OSUtils::lockDownFile(binPath.c_str(),false); - _latestValid = true; - _download = std::string(); - _downloadLength = 0; - return true; - } - } - } - } catch ( ... ) {} // any exception equals verification failure + const std::string binPath(_homePath + ZT_PATH_SEPARATOR_S ZT_SOFTWARE_UPDATE_BIN_FILENAME); + try { + // (1) Check the hash itself to make sure the image is basically okay + uint8_t sha512[64]; + SHA512(sha512, _download.data(), (unsigned int)_download.length()); + char hexbuf[(64 * 2) + 2]; + if (OSUtils::jsonString(_latestMeta[ZT_SOFTWARE_UPDATE_JSON_UPDATE_HASH], "") == Utils::hex(sha512, 64, hexbuf)) { + // (2) Check signature by signing authority + const std::string sig(OSUtils::jsonBinFromHex(_latestMeta[ZT_SOFTWARE_UPDATE_JSON_UPDATE_SIGNATURE])); + if (Identity(ZT_SOFTWARE_UPDATE_SIGNING_AUTHORITY).verify(_download.data(), (unsigned int)_download.length(), sig.data(), (unsigned int)sig.length())) { + // (3) Try to save file, and if so we are good. + OSUtils::rm(binPath.c_str()); + if (OSUtils::writeFile(binPath.c_str(), _download)) { + OSUtils::lockDownFile(binPath.c_str(), false); + _latestValid = true; + _download = std::string(); + _downloadLength = 0; + return true; + } + } + } + } + catch (...) { + } // any exception equals verification failure - // If we get here, checks failed. - OSUtils::rm(binPath.c_str()); - _latestMeta = nlohmann::json(); - _latestValid = false; - _download = std::string(); - _downloadLength = 0; - } else { - Buffer<128> gd; - gd.append((uint8_t)VERB_GET_DATA); - gd.append(_downloadHashPrefix.data(),16); - gd.append((uint32_t)_download.length()); - _node.sendUserMessage((void *)0,ZT_SOFTWARE_UPDATE_SERVICE,ZT_SOFTWARE_UPDATE_USER_MESSAGE_TYPE,gd.data(),gd.size()); - } - } + // If we get here, checks failed. + OSUtils::rm(binPath.c_str()); + _latestMeta = nlohmann::json(); + _latestValid = false; + _download = std::string(); + _downloadLength = 0; + } + else { + Buffer<128> gd; + gd.append((uint8_t)VERB_GET_DATA); + gd.append(_downloadHashPrefix.data(), 16); + gd.append((uint32_t)_download.length()); + _node.sendUserMessage((void*)0, ZT_SOFTWARE_UPDATE_SERVICE, ZT_SOFTWARE_UPDATE_USER_MESSAGE_TYPE, gd.data(), gd.size()); + } + } - return false; + return false; } void SoftwareUpdater::apply() { - std::string updatePath(_homePath + ZT_PATH_SEPARATOR_S ZT_SOFTWARE_UPDATE_BIN_FILENAME); - if ((_latestMeta.is_object())&&(_latestValid)&&(OSUtils::fileExists(updatePath.c_str(),false))) { + std::string updatePath(_homePath + ZT_PATH_SEPARATOR_S ZT_SOFTWARE_UPDATE_BIN_FILENAME); + if ((_latestMeta.is_object()) && (_latestValid) && (OSUtils::fileExists(updatePath.c_str(), false))) { #ifdef __WINDOWS__ - std::string cmdArgs(OSUtils::jsonString(_latestMeta[ZT_SOFTWARE_UPDATE_JSON_UPDATE_EXEC_ARGS],"")); - if (cmdArgs.length() > 0) { - updatePath.push_back(' '); - updatePath.append(cmdArgs); - } - STARTUPINFOA si; - PROCESS_INFORMATION pi; - memset(&si,0,sizeof(si)); - memset(&pi,0,sizeof(pi)); - CreateProcessA(NULL,const_cast(updatePath.c_str()),NULL,NULL,FALSE,CREATE_NO_WINDOW|CREATE_NEW_PROCESS_GROUP,NULL,NULL,&si,&pi); - // Windows doesn't exit here -- updater will stop the service during update, etc. -- but we do want to stop multiple runs from happening - _latestMeta = nlohmann::json(); - _latestValid = false; + std::string cmdArgs(OSUtils::jsonString(_latestMeta[ZT_SOFTWARE_UPDATE_JSON_UPDATE_EXEC_ARGS], "")); + if (cmdArgs.length() > 0) { + updatePath.push_back(' '); + updatePath.append(cmdArgs); + } + STARTUPINFOA si; + PROCESS_INFORMATION pi; + memset(&si, 0, sizeof(si)); + memset(&pi, 0, sizeof(pi)); + CreateProcessA(NULL, const_cast(updatePath.c_str()), NULL, NULL, FALSE, CREATE_NO_WINDOW | CREATE_NEW_PROCESS_GROUP, NULL, NULL, &si, &pi); + // Windows doesn't exit here -- updater will stop the service during update, etc. -- but we do want to stop multiple runs from happening + _latestMeta = nlohmann::json(); + _latestValid = false; #else - char *argv[256]; - unsigned long ac = 0; - argv[ac++] = const_cast(updatePath.c_str()); - const std::vector argsSplit(OSUtils::split(OSUtils::jsonString(_latestMeta[ZT_SOFTWARE_UPDATE_JSON_UPDATE_EXEC_ARGS],"").c_str()," ","\\","\"")); - for(std::vector::const_iterator a(argsSplit.begin());a!=argsSplit.end();++a) { - argv[ac] = const_cast(a->c_str()); - if (++ac == 255) break; - } - argv[ac] = (char *)0; - chmod(updatePath.c_str(),0700); + char* argv[256]; + unsigned long ac = 0; + argv[ac++] = const_cast(updatePath.c_str()); + const std::vector argsSplit(OSUtils::split(OSUtils::jsonString(_latestMeta[ZT_SOFTWARE_UPDATE_JSON_UPDATE_EXEC_ARGS], "").c_str(), " ", "\\", "\"")); + for (std::vector::const_iterator a(argsSplit.begin()); a != argsSplit.end(); ++a) { + argv[ac] = const_cast(a->c_str()); + if (++ac == 255) + break; + } + argv[ac] = (char*)0; + chmod(updatePath.c_str(), 0700); - // Close all open file descriptors except stdout/stderr/etc. - int minMyFd = STDIN_FILENO; - if (STDOUT_FILENO > minMyFd) minMyFd = STDOUT_FILENO; - if (STDERR_FILENO > minMyFd) minMyFd = STDERR_FILENO; - ++minMyFd; + // Close all open file descriptors except stdout/stderr/etc. + int minMyFd = STDIN_FILENO; + if (STDOUT_FILENO > minMyFd) + minMyFd = STDOUT_FILENO; + if (STDERR_FILENO > minMyFd) + minMyFd = STDERR_FILENO; + ++minMyFd; #ifdef _SC_OPEN_MAX - int maxMyFd = (int)sysconf(_SC_OPEN_MAX); - if (maxMyFd <= minMyFd) - maxMyFd = 65536; + int maxMyFd = (int)sysconf(_SC_OPEN_MAX); + if (maxMyFd <= minMyFd) + maxMyFd = 65536; #else - int maxMyFd = 65536; + int maxMyFd = 65536; #endif - while (minMyFd < maxMyFd) - close(minMyFd++); + while (minMyFd < maxMyFd) + close(minMyFd++); - execv(updatePath.c_str(),argv); - fprintf(stderr,"FATAL: unable to execute software update binary at %s\n",updatePath.c_str()); - exit(1); + execv(updatePath.c_str(), argv); + fprintf(stderr, "FATAL: unable to execute software update binary at %s\n", updatePath.c_str()); + exit(1); #endif - } + } } -} // namespace ZeroTier +} // namespace ZeroTier diff --git a/service/SoftwareUpdater.hpp b/service/SoftwareUpdater.hpp index 59e62d5b..a1a0805f 100644 --- a/service/SoftwareUpdater.hpp +++ b/service/SoftwareUpdater.hpp @@ -14,20 +14,17 @@ #ifndef ZT_SOFTWAREUPDATER_HPP #define ZT_SOFTWAREUPDATER_HPP -#include -#include - -#include -#include -#include -#include - #include "../include/ZeroTierOne.h" - #include "../node/Identity.hpp" #include "../node/Packet.hpp" +#include +#include #include +#include +#include +#include +#include /** * VERB_USER_MESSAGE type ID for software update messages @@ -71,21 +68,21 @@ */ #define ZT_SOFTWARE_UPDATE_BIN_FILENAME "latest-update.exe" -#define ZT_SOFTWARE_UPDATE_JSON_VERSION_MAJOR "vMajor" -#define ZT_SOFTWARE_UPDATE_JSON_VERSION_MINOR "vMinor" +#define ZT_SOFTWARE_UPDATE_JSON_VERSION_MAJOR "vMajor" +#define ZT_SOFTWARE_UPDATE_JSON_VERSION_MINOR "vMinor" #define ZT_SOFTWARE_UPDATE_JSON_VERSION_REVISION "vRev" -#define ZT_SOFTWARE_UPDATE_JSON_VERSION_BUILD "vBuild" -#define ZT_SOFTWARE_UPDATE_JSON_PLATFORM "platform" -#define ZT_SOFTWARE_UPDATE_JSON_ARCHITECTURE "arch" -#define ZT_SOFTWARE_UPDATE_JSON_VENDOR "vendor" -#define ZT_SOFTWARE_UPDATE_JSON_CHANNEL "channel" +#define ZT_SOFTWARE_UPDATE_JSON_VERSION_BUILD "vBuild" +#define ZT_SOFTWARE_UPDATE_JSON_PLATFORM "platform" +#define ZT_SOFTWARE_UPDATE_JSON_ARCHITECTURE "arch" +#define ZT_SOFTWARE_UPDATE_JSON_VENDOR "vendor" +#define ZT_SOFTWARE_UPDATE_JSON_CHANNEL "channel" #define ZT_SOFTWARE_UPDATE_JSON_EXPECT_SIGNED_BY "expectedSigner" #define ZT_SOFTWARE_UPDATE_JSON_UPDATE_SIGNED_BY "signer" #define ZT_SOFTWARE_UPDATE_JSON_UPDATE_SIGNATURE "signature" -#define ZT_SOFTWARE_UPDATE_JSON_UPDATE_HASH "hash" -#define ZT_SOFTWARE_UPDATE_JSON_UPDATE_SIZE "size" +#define ZT_SOFTWARE_UPDATE_JSON_UPDATE_HASH "hash" +#define ZT_SOFTWARE_UPDATE_JSON_UPDATE_SIZE "size" #define ZT_SOFTWARE_UPDATE_JSON_UPDATE_EXEC_ARGS "execArgs" -#define ZT_SOFTWARE_UPDATE_JSON_UPDATE_URL "url" +#define ZT_SOFTWARE_UPDATE_JSON_UPDATE_URL "url" namespace ZeroTier { @@ -94,111 +91,114 @@ class Node; /** * This class handles retrieving and executing updates, or serving them */ -class SoftwareUpdater -{ -public: - /** - * Each message begins with an 8-bit message verb - */ - enum MessageVerb - { - /** - * Payload: JSON containing current system platform, version, etc. - */ - VERB_GET_LATEST = 1, +class SoftwareUpdater { + public: + /** + * Each message begins with an 8-bit message verb + */ + enum MessageVerb { + /** + * Payload: JSON containing current system platform, version, etc. + */ + VERB_GET_LATEST = 1, - /** - * Payload: JSON describing latest update for this target. (No response is sent if there is none.) - */ - VERB_LATEST = 2, + /** + * Payload: JSON describing latest update for this target. (No response is sent if there is none.) + */ + VERB_LATEST = 2, - /** - * Payload: - * <[16] first 128 bits of hash of data object> - * <[4] 32-bit index of chunk to get> - */ - VERB_GET_DATA = 3, + /** + * Payload: + * <[16] first 128 bits of hash of data object> + * <[4] 32-bit index of chunk to get> + */ + VERB_GET_DATA = 3, - /** - * Payload: - * <[16] first 128 bits of hash of data object> - * <[4] 32-bit index of chunk> - * <[...] chunk data> - */ - VERB_DATA = 4 - }; + /** + * Payload: + * <[16] first 128 bits of hash of data object> + * <[4] 32-bit index of chunk> + * <[...] chunk data> + */ + VERB_DATA = 4 + }; - SoftwareUpdater(Node &node,const std::string &homePath); - ~SoftwareUpdater(); + SoftwareUpdater(Node& node, const std::string& homePath); + ~SoftwareUpdater(); - /** - * Set whether or not we will distribute updates - * - * @param distribute If true, scan update-dist.d now and distribute updates found there -- if false, clear and stop distributing - */ - void setUpdateDistribution(bool distribute); + /** + * Set whether or not we will distribute updates + * + * @param distribute If true, scan update-dist.d now and distribute updates found there -- if false, clear and stop distributing + */ + void setUpdateDistribution(bool distribute); - /** - * Handle a software update user message - * - * @param origin ZeroTier address of message origin - * @param data Message payload - * @param len Length of message - */ - void handleSoftwareUpdateUserMessage(uint64_t origin,const void *data,unsigned int len); + /** + * Handle a software update user message + * + * @param origin ZeroTier address of message origin + * @param data Message payload + * @param len Length of message + */ + void handleSoftwareUpdateUserMessage(uint64_t origin, const void* data, unsigned int len); - /** - * Check for updates and do other update-related housekeeping - * - * It should be called about every 10 seconds. - * - * @return True if we've downloaded and verified an update - */ - bool check(const int64_t now); + /** + * Check for updates and do other update-related housekeeping + * + * It should be called about every 10 seconds. + * + * @return True if we've downloaded and verified an update + */ + bool check(const int64_t now); - /** - * @return Meta-data for downloaded update or NULL if none - */ - inline const nlohmann::json &pending() const { return _latestMeta; } + /** + * @return Meta-data for downloaded update or NULL if none + */ + inline const nlohmann::json& pending() const + { + return _latestMeta; + } - /** - * Apply any ready update now - * - * Depending on the platform this function may never return and may forcibly - * exit the process. It does nothing if no update is ready. - */ - void apply(); + /** + * Apply any ready update now + * + * Depending on the platform this function may never return and may forcibly + * exit the process. It does nothing if no update is ready. + */ + void apply(); - /** - * Set software update channel - * - * @param channel 'release', 'beta', etc. - */ - inline void setChannel(const std::string &channel) { _channel = channel; } + /** + * Set software update channel + * + * @param channel 'release', 'beta', etc. + */ + inline void setChannel(const std::string& channel) + { + _channel = channel; + } -private: - Node &_node; - uint64_t _lastCheckTime; - std::string _homePath; - std::string _channel; - FILE *_distLog; + private: + Node& _node; + uint64_t _lastCheckTime; + std::string _homePath; + std::string _channel; + FILE* _distLog; - // Offered software updates if we are an update host (we have update-dist.d and update hosting is enabled) - struct _D - { - nlohmann::json meta; - std::string bin; - }; - std::map< std::array,_D > _dist; // key is first 16 bytes of hash + // Offered software updates if we are an update host (we have update-dist.d and update hosting is enabled) + struct _D { + nlohmann::json meta; + std::string bin; + }; + std::map, _D> _dist; // key is first 16 bytes of hash - nlohmann::json _latestMeta; - bool _latestValid; + nlohmann::json _latestMeta; + bool _latestValid; - std::string _download; - std::array _downloadHashPrefix; - unsigned long _downloadLength; + std::string _download; + std::array _downloadHashPrefix; + unsigned long _downloadLength; }; -} // namespace ZeroTier +} // namespace ZeroTier #endif diff --git a/version.h b/version.h index 8fff820a..35ca9a93 100644 --- a/version.h +++ b/version.h @@ -22,12 +22,12 @@ /** * Minor version */ -#define ZEROTIER_ONE_VERSION_MINOR 14 +#define ZEROTIER_ONE_VERSION_MINOR 15 /** * Revision */ -#define ZEROTIER_ONE_VERSION_REVISION 1 +#define ZEROTIER_ONE_VERSION_REVISION 0 /** * Build version diff --git a/windows/ZeroTierOne/ZeroTierOne.vcxproj b/windows/ZeroTierOne/ZeroTierOne.vcxproj index 2dd05aa5..de094bc7 100644 --- a/windows/ZeroTierOne/ZeroTierOne.vcxproj +++ b/windows/ZeroTierOne/ZeroTierOne.vcxproj @@ -200,7 +200,7 @@ - + @@ -657,4 +657,4 @@ - \ No newline at end of file + diff --git a/windows/ZeroTierOne/ZeroTierOne.vcxproj.filters b/windows/ZeroTierOne/ZeroTierOne.vcxproj.filters index 1b1bb507..8087f1de 100644 --- a/windows/ZeroTierOne/ZeroTierOne.vcxproj.filters +++ b/windows/ZeroTierOne/ZeroTierOne.vcxproj.filters @@ -335,7 +335,7 @@ Header Files\node - + Header Files\node @@ -572,4 +572,4 @@ Resource Files - \ No newline at end of file + diff --git a/windows/ZeroTierOneSDK/ZeroTierOneSDK.vcxproj b/windows/ZeroTierOneSDK/ZeroTierOneSDK.vcxproj index bc719b6e..9e3a1270 100644 --- a/windows/ZeroTierOneSDK/ZeroTierOneSDK.vcxproj +++ b/windows/ZeroTierOneSDK/ZeroTierOneSDK.vcxproj @@ -168,7 +168,7 @@ - + @@ -254,4 +254,4 @@ - \ No newline at end of file + diff --git a/windows/ZeroTierOneSDK/ZeroTierOneSDK.vcxproj.filters b/windows/ZeroTierOneSDK/ZeroTierOneSDK.vcxproj.filters index d7e947f3..7276ba31 100644 --- a/windows/ZeroTierOneSDK/ZeroTierOneSDK.vcxproj.filters +++ b/windows/ZeroTierOneSDK/ZeroTierOneSDK.vcxproj.filters @@ -42,7 +42,7 @@ Header Files - + Header Files @@ -237,4 +237,4 @@ Source Files - \ No newline at end of file + diff --git a/zerotier-one.spec b/zerotier-one.spec index 414b0b62..3458f4ea 100644 --- a/zerotier-one.spec +++ b/zerotier-one.spec @@ -1,5 +1,5 @@ Name: zerotier-one -Version: 1.14.1 +Version: 1.15.0 Release: 1%{?dist} Summary: ZeroTier network virtualization service