├── .gitattributes ├── .github ├── assets │ └── images │ │ └── inputs.png ├── dependabot.yml └── workflows │ ├── ci-auto-rerun-failed-jobs-action.yml │ ├── ci-check-for-new-release-tag.yml │ ├── ci-checks.yml │ ├── ci-docker.yml │ ├── ci-linux-crossbuild.yml │ ├── ci-linux-emulation.yml │ ├── ci-main-reusable-caller.yml │ ├── ci-osx.yml │ ├── ci-release.yml │ ├── ci-windows.yml │ └── test.yml ├── .gitignore ├── Dockerfile ├── LICENSE.txt ├── README.md ├── ci-cygwin-installer-packages.cmd ├── ci-cygwin-installer.cmd ├── ci-linux-crossbuild.sh ├── ci-release-body.md ├── ci-windows-cygwin-build.sh ├── pwsh-here.cmd └── zizmor.yml /.gitattributes: -------------------------------------------------------------------------------- 1 | * -text -------------------------------------------------------------------------------- /.github/assets/images/inputs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/userdocs/iperf3-static/34a4877ff16b717a88d732d648d261475c6798f2/.github/assets/images/inputs.png -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | # Maintain dependencies for GitHub Actions 4 | - package-ecosystem: "github-actions" 5 | directory: "/" 6 | schedule: 7 | interval: "daily" 8 | -------------------------------------------------------------------------------- /.github/workflows/ci-auto-rerun-failed-jobs-action.yml: -------------------------------------------------------------------------------- 1 | name: ci - auto rerun failed jobs 2 | 3 | on: 4 | workflow_dispatch: 5 | inputs: 6 | run_id: 7 | description: "The run id of the workflow to rerun" 8 | required: true 9 | attempts: 10 | description: "The number of attempts to rerun the workflow" 11 | required: true 12 | retries: 13 | description: "The number of retries to rerun the workflow" 14 | required: true 15 | github_repo: 16 | description: "The repository to rerun the workflow" 17 | required: false 18 | distinct_id: 19 | description: "The distinct id of the workflow to rerun" 20 | required: false 21 | 22 | run-name: ci auto rerun failed jobs - attempt ${{ inputs.attempts }} 23 | 24 | jobs: 25 | gh-cli-rerun: 26 | name: rerun - attempt ${{ inputs.attempts }} 27 | permissions: 28 | actions: write 29 | runs-on: ubuntu-24.04-arm 30 | env: 31 | GH_TOKEN: "${{ secrets.AUTO_RERUN || github.token }}" 32 | steps: 33 | - name: Host - Checkout action ${{ inputs.distinct_id }} 34 | uses: actions/checkout@v4 35 | with: 36 | persist-credentials: false 37 | 38 | - uses: userdocs/gh-cli-workflow-reruns/actions/auto-rerun-failed@main 39 | with: 40 | run_id: ${{ inputs.run_id }} 41 | attempts: ${{ inputs.attempts }} 42 | retries: ${{ inputs.retries }} 43 | github_repo: ${{ inputs.github_repo || github.repository }} 44 | distinct_id: ${{ inputs.distinct_id || github.run_id }} 45 | -------------------------------------------------------------------------------- /.github/workflows/ci-check-for-new-release-tag.yml: -------------------------------------------------------------------------------- 1 | name: ci - check for new iperf3 release tag 2 | 3 | on: 4 | workflow_call: 5 | outputs: 6 | continue_build: 7 | value: ${{ jobs.check_release.outputs.continue_build }} 8 | iperf3_tag: 9 | value: ${{ jobs.check_release.outputs.iperf3_tag }} 10 | 11 | env: 12 | GH_TOKEN: "${{ github.TOKEN }}" 13 | 14 | jobs: 15 | check_release: 16 | outputs: 17 | continue_build: ${{ steps.continue_build_check.outputs.continue_build_choice }} 18 | iperf3_tag: ${{ steps.continue_build_check.outputs.iperf3_tag }} 19 | runs-on: ubuntu-24.04-arm 20 | 21 | steps: 22 | # Checkout the code 23 | - name: Checkout code 24 | uses: actions/checkout@v4 25 | with: 26 | persist-credentials: false 27 | 28 | - name: Get latest esnet/iperf tag 29 | run: printf '%s\n' "upstream_iperf3_tag=$(git ls-remote -q -t --refs "https://github.com/esnet/iperf.git" | awk '{sub("refs/tags/", ""); if ($2 ~ /^[0-9]+(\.[0-9]+)*$/) print $2 }' | sort -rV | awk '!/^$/' | head -n 1)" >> $GITHUB_ENV 30 | 31 | - name: Get latest ${{ github.repository }} tag 32 | run: printf '%s\n' "local_iperf3_tag=$(git ls-remote -q -t --refs "https://github.com/${{ github.repository }}.git" | awk '{sub("refs/tags/", ""); if ($2 ~ /^[0-9]+(\.[0-9]+)*$/) print $2 }' | sort -rV | awk '!/^$/' | head -n 1)" >> $GITHUB_ENV 33 | 34 | - name: Test values - latest upstream vs local tags 35 | id: continue_build_check 36 | run: | 37 | ver() { 38 | local test_array 39 | read -ra test_array < <(printf "%s" "${@//./ }") 40 | printf "%d%03d%03d%03d" "${test_array[@]}" 41 | } 42 | 43 | local_iperf3_tag="${{ env.local_iperf3_tag }}" 44 | 45 | if [[ "$(ver "${{ env.upstream_iperf3_tag }}")" -gt "$(ver "${local_iperf3_tag//+/}")" ]]; then 46 | printf "%-14s remote:%-10s local:%-10s %s\n" "$iray" "${{ env.upstream_iperf3_tag }}" "${local_iperf3_tag//+/}" "< New version available - workflow will be triggered" 47 | printf '%s\n' "continue_build_choice=yes" >> $GITHUB_OUTPUT 48 | printf '%s\n' "iperf3_tag=${{ env.upstream_iperf3_tag }}" >> $GITHUB_OUTPUT 49 | else 50 | printf "%-14s remote:%-10s local:%-10s\n" "$iray" "${{ env.upstream_iperf3_tag }}" "${local_iperf3_tag//+/}" 51 | fi 52 | -------------------------------------------------------------------------------- /.github/workflows/ci-checks.yml: -------------------------------------------------------------------------------- 1 | name: ci - checks 2 | on: 3 | push: 4 | pull_request: 5 | workflow_dispatch: 6 | 7 | concurrency: 8 | group: ${{ github.workflow }}-${{ github.ref }} 9 | cancel-in-progress: true 10 | 11 | jobs: 12 | sh-checker: 13 | runs-on: ubuntu-24.04-arm 14 | permissions: 15 | contents: read 16 | steps: 17 | - uses: actions/checkout@v4 18 | with: 19 | persist-credentials: false 20 | 21 | - name: Run the sh-checker 22 | uses: luizm/action-sh-checker@v0.9.0 23 | env: 24 | GITHUB_TOKEN: ${{ github.token }} 25 | SHELLCHECK_OPTS: -e SC2034,SC1091 # It is possible to exclude some shellcheck warnings. 26 | SHFMT_OPTS: -ci -sr -i 0 # It is possible to pass arguments to shftm 27 | with: 28 | sh_checker_comment: true 29 | sh_checker_exclude: "" 30 | 31 | zizmor-checker: 32 | runs-on: ubuntu-24.04-arm 33 | permissions: 34 | contents: read 35 | steps: 36 | - uses: actions/checkout@v4 37 | with: 38 | persist-credentials: false 39 | 40 | - name: Check GitHub Action workflows 41 | shell: bash {0} 42 | run: | 43 | pip install zizmor 44 | 45 | zizmor="$(zizmor . --gh-token "${{ github.token }}")" 46 | exit_code="$?" 47 | 48 | printf '%s\n' "$zizmor" 49 | 50 | printf '%b\n' "\`\`\`" >> $GITHUB_STEP_SUMMARY 51 | printf '%s\n' "$zizmor" >> $GITHUB_STEP_SUMMARY 52 | printf '%b' "\`\`\`" >> $GITHUB_STEP_SUMMARY 53 | 54 | exit "$exit_code" 55 | 56 | editorconfig-checker: 57 | runs-on: ubuntu-24.04-arm 58 | permissions: 59 | contents: read 60 | steps: 61 | - uses: actions/checkout@v4 62 | with: 63 | persist-credentials: false 64 | 65 | - name: editorconfig-checker 66 | env: 67 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 68 | run: | 69 | curl -Lo- "https://github.com/editorconfig-checker/editorconfig-checker/releases/latest/download/ec-linux-amd64.tar.gz" | tar xzf - --strip-components=1 70 | 71 | printf '%b\n' "\`\`\`" >> $GITHUB_STEP_SUMMARY 72 | ./ec-linux-amd64 --exclude '^(docs/.*|patches/.*)$' | sed "s,\x1B\[[0-9;]*[a-zA-Z],,g" >> $GITHUB_STEP_SUMMARY 73 | exit_code=("${PIPESTATUS[0]}") 74 | printf '%b' "\`\`\`" >> $GITHUB_STEP_SUMMARY 75 | 76 | # exit "${exit_code}" 77 | -------------------------------------------------------------------------------- /.github/workflows/ci-docker.yml: -------------------------------------------------------------------------------- 1 | name: ci - linux docker build 2 | 3 | on: 4 | workflow_call: 5 | 6 | env: 7 | DOCKERHUB_REPO: ${{ github.repository }} 8 | GHCR_REPO: ghcr.io/${{ github.repository }} 9 | SET_IMAGE_TAG: latest 10 | GH_TOKEN: ${{ github.token }} 11 | 12 | jobs: 13 | build: 14 | runs-on: ubuntu-24.04-arm 15 | outputs: 16 | latest_tag: ${{ steps.gh_latest_tag.outputs.latest_tag }} 17 | strategy: 18 | fail-fast: false 19 | matrix: 20 | arch: [amd64, arm32v6, arm32v7, arm64v8, i386, ppc64le, riscv64, s390x] 21 | include: 22 | - arch: amd64 23 | platform: linux/amd64 24 | - arch: arm32v6 25 | platform: linux/arm/v6 26 | - arch: arm32v7 27 | platform: linux/arm/v7 28 | - arch: arm64v8 29 | platform: linux/arm64 30 | - arch: i386 31 | platform: linux/386 32 | - arch: ppc64le 33 | platform: linux/ppc64le 34 | - arch: riscv64 35 | platform: linux/riscv64 36 | - arch: s390x 37 | platform: linux/s390x 38 | 39 | steps: 40 | - name: Checkout code 41 | uses: actions/checkout@v4 42 | with: 43 | persist-credentials: false 44 | 45 | - name: Fetch latest GitHub tag 46 | id: gh_latest_tag 47 | run: | 48 | latest_tag="$(gh release list --json tagName -L 1 -q '.[0].tagName')" 49 | printf '%s\n' "latest_tag=${latest_tag//+/-dev}" >> "$GITHUB_ENV" 50 | printf '%s\n' "latest_tag=${latest_tag//+/-dev}" >> "$GITHUB_OUTPUT" 51 | 52 | - name: Prepare 53 | run: | 54 | platform=${{ matrix.platform }} 55 | printf '%s\n' "matrix_platform_hypens=${platform//\//-}" >> $GITHUB_ENV 56 | 57 | - name: Docker meta 58 | id: meta 59 | uses: docker/metadata-action@v5 60 | with: 61 | images: ${{ env.GHCR_REPO }} 62 | 63 | - name: Login to GHCR 64 | uses: docker/login-action@v3 65 | with: 66 | registry: ghcr.io 67 | username: ${{ github.repository_owner }} 68 | password: ${{ github.token }} 69 | 70 | - name: Set up QEMU 71 | uses: docker/setup-qemu-action@v3 72 | 73 | - name: Set up Docker Buildx 74 | uses: docker/setup-buildx-action@v3 75 | with: 76 | cache-binary: false 77 | 78 | - name: Build and push by digest 79 | id: build 80 | uses: docker/build-push-action@v6 81 | with: 82 | context: . 83 | platforms: ${{ matrix.platform }} 84 | provenance: false 85 | push: true 86 | tags: ${{ env.GHCR_REPO }}:${{ steps.meta.outputs.version }} 87 | labels: ${{ steps.meta.outputs.labels }} 88 | no-cache: true 89 | build-args: | 90 | ARCH=${{ matrix.arch }} 91 | REPO=${{ github.repository }} 92 | 93 | - name: Export digest 94 | env: 95 | digest: ${{ steps.build.outputs.digest }} 96 | run: | 97 | mkdir -p ${{ runner.temp }}/digests 98 | digest="${digest}" 99 | touch "${{ runner.temp }}/digests/${digest#sha256:}" 100 | 101 | - name: Upload digest 102 | uses: actions/upload-artifact@v4 103 | with: 104 | name: digests-${{ env.matrix_platform_hypens }} 105 | path: ${{ runner.temp }}/digests/* 106 | if-no-files-found: error 107 | 108 | merge: 109 | runs-on: ubuntu-24.04-arm 110 | needs: build 111 | env: 112 | latest_tag: ${{ needs.build.outputs.latest_tag }} 113 | steps: 114 | - name: Download digests 115 | uses: actions/download-artifact@v4 116 | with: 117 | path: ${{ runner.temp }}/digests 118 | pattern: digests-* 119 | merge-multiple: true 120 | 121 | - name: Login to GHCR 122 | uses: docker/login-action@v3 123 | with: 124 | registry: ghcr.io 125 | username: ${{ github.repository_owner }} 126 | password: ${{ github.token }} 127 | 128 | - name: Set up Docker Buildx 129 | uses: docker/setup-buildx-action@v3 130 | with: 131 | cache-binary: false 132 | 133 | - name: Docker meta 134 | id: meta 135 | uses: docker/metadata-action@v5 136 | with: 137 | images: ${{ env.GHCR_REPO }} 138 | 139 | - name: Create manifest list and push latest 140 | working-directory: ${{ runner.temp }}/digests 141 | run: | 142 | ghcr_digests=$(for digest in *; do printf '%s@sha256:%s ' "${GHCR_REPO}" "${digest}"; done) 143 | docker buildx imagetools create -t ${GHCR_REPO}:latest ${ghcr_digests} 144 | 145 | - name: Create manifest list and push (version) 146 | working-directory: ${{ runner.temp }}/digests 147 | run: | 148 | ghcr_digests=$(for digest in *; do printf '%s@sha256:%s ' "${GHCR_REPO}" "${digest}"; done) 149 | docker buildx imagetools create -t ${GHCR_REPO}:${latest_tag} ${ghcr_digests} 150 | 151 | - name: Inspect image 152 | run: | 153 | docker buildx imagetools inspect ${GHCR_REPO}:latest 154 | docker buildx imagetools inspect ${GHCR_REPO}:${latest_tag} 155 | -------------------------------------------------------------------------------- /.github/workflows/ci-linux-crossbuild.yml: -------------------------------------------------------------------------------- 1 | name: ci - linux binary cross build 2 | 3 | on: 4 | workflow_call: 5 | outputs: 6 | release_tags: 7 | value: ${{ jobs.build.outputs.release_tags }} 8 | inputs: 9 | source_repo: 10 | type: string 11 | required: true 12 | source_branch: 13 | type: string 14 | required: true 15 | secrets: 16 | VT_API_KEY: 17 | required: false 18 | 19 | env: 20 | GH_TOKEN: "${{ github.TOKEN }}" 21 | 22 | jobs: 23 | build: 24 | runs-on: ubuntu-24.04-arm 25 | outputs: 26 | release_tags: ${{ steps.release_tags.outputs.release_tag }} 27 | strategy: 28 | fail-fast: false 29 | matrix: 30 | name: [iperf3] 31 | os_id: [alpine] 32 | os_version_id: [edge] 33 | arch: [x86, x86_64, armhf, armv7, aarch64, ppc64le, riscv64, s390x] 34 | include: 35 | - arch: x86 36 | qbt-musl-cross-make: "i686-linux-musl" 37 | release_name: i386 38 | - arch: x86_64 39 | qbt-musl-cross-make: "x86_64-linux-musl" 40 | release_name: amd64 41 | - arch: armhf 42 | qbt-musl-cross-make: "armv6-linux-musleabihf" 43 | release_name: arm32v6 44 | - arch: armv7 45 | qbt-musl-cross-make: "armv6-linux-musleabihf" 46 | release_name: arm32v7 47 | - arch: armv7 48 | qbt-musl-cross-make: "armv7l-linux-musleabihf" 49 | - arch: aarch64 50 | qbt-musl-cross-make: "aarch64-linux-musl" 51 | release_name: arm64v8 52 | - arch: ppc64le 53 | qbt-musl-cross-make: "powerpc64le-linux-musl" 54 | release_name: ppc64le 55 | - arch: riscv64 56 | qbt-musl-cross-make: "riscv64-linux-musl" 57 | release_name: riscv64 58 | - arch: s390x 59 | qbt-musl-cross-make: "s390x-linux-musl" 60 | release_name: s390x 61 | 62 | name: ${{ matrix.name }} ${{ matrix.os_id }}:${{ matrix.os_version_id }} ${{ matrix.arch }} 63 | 64 | env: 65 | CDN: http://dl-cdn.alpinelinux.org/alpine/edge/main/ 66 | CXXFLAGS: "--static -static" 67 | CPPFLAGS: "--static -static" 68 | LDFLAGS: "--static -static" 69 | source_repo: ${{ inputs.source_repo }} 70 | source_branch: ${{ inputs.source_branch }} 71 | container_name: mcm 72 | 73 | steps: 74 | - name: Checkout 75 | uses: actions/checkout@v4 76 | with: 77 | persist-credentials: false 78 | 79 | - name: Host - Bootstrap qemu 80 | uses: userdocs/actions/qemu@main 81 | 82 | - name: Create docker ${{ env.container_name }} ${{ matrix.platform }} container 83 | run: > 84 | docker run --name ${container_name} -it -d -w /home/gh -v ${{ github.workspace }}:/home/gh 85 | -e CXXFLAGS="${{ env.CXXFLAGS }}" 86 | -e CPPFLAGS="${{ env.CPPFLAGS }}" 87 | -e LDFLAGS="${{ env.LDFLAGS }}" 88 | ghcr.io/userdocs/qbt-musl-cross-make:${{ matrix.qbt-musl-cross-make }} 89 | 90 | - name: Run apk update 91 | run: docker exec ${container_name} apk update 92 | 93 | - name: Run apk upgrade 94 | run: docker exec ${container_name} apk upgrade 95 | 96 | - name: run ci-linux-crossbuild.sh 97 | run: docker exec -u gh:gh ${container_name} /bin/bash /home/gh/ci-linux-crossbuild.sh ${source_repo} ${source_branch} ${{ matrix.qbt-musl-cross-make }} ${{ matrix.arch }} 98 | 99 | - name: Rename ${{ matrix.name }} to ${{ matrix.name }}-${{ matrix.release_name }} 100 | run: docker exec -u gh:gh ${container_name} mv -f /home/gh/local/bin/${{ matrix.name }} /home/gh/${{ matrix.name }}-${{ matrix.release_name }} 101 | 102 | - name: Create path to binary env 103 | run: printf '%s\n' "binary_path=${{ github.workspace }}/${{ matrix.name }}-${{ matrix.release_name }}" >> $GITHUB_ENV 104 | 105 | - name: VirusTotal Scan 106 | id: virustotal 107 | uses: crazy-max/ghaction-virustotal@v4 108 | with: 109 | vt_api_key: ${{ secrets.VT_API_KEY }} 110 | files: ${{ env.binary_path }} 111 | 112 | - name: sha256sum 113 | run: | 114 | printf '%s' https://www.virustotal.com/gui/file/$(sha256sum ${{ env.binary_path }} | awk '{print $1}') > ${{ matrix.name }}-${{ matrix.release_name }}.url 115 | cat ${{ matrix.name }}-${{ matrix.release_name }}.url 116 | 117 | - name: Create tag env 118 | run: printf '%s\n' "release_tag=$(sed -rn 's|(.*)\[(.*)],\[https://github.com/esnet/iperf],(.*)|\2|p' ${{ matrix.name }}/configure.ac)" >> $GITHUB_ENV 119 | 120 | - name: Set tag env to output 121 | id: release_tags 122 | run: printf '%s\n' "release_tag=${{ env.release_tag }}" >> "$GITHUB_OUTPUT" 123 | 124 | - name: Generate artifact attestation 125 | uses: actions/attest-build-provenance@v2 126 | with: 127 | subject-path: ${{ env.binary_path }} 128 | 129 | - name: "Create artifact" 130 | uses: actions/upload-artifact@v4 131 | with: 132 | name: ${{ matrix.name }}-${{ matrix.release_name }} 133 | path: | 134 | ${{ env.binary_path }} 135 | ${{ matrix.name }}-${{ matrix.release_name }}.url 136 | -------------------------------------------------------------------------------- /.github/workflows/ci-linux-emulation.yml: -------------------------------------------------------------------------------- 1 | name: ci - linux binary emulation build 2 | 3 | on: 4 | workflow_call: 5 | outputs: 6 | release_tags: 7 | value: ${{ jobs.build.outputs.release_tags }} 8 | inputs: 9 | source_repo: 10 | type: string 11 | required: true 12 | source_branch: 13 | type: string 14 | required: true 15 | secrets: 16 | VT_API_KEY: 17 | required: false 18 | 19 | env: 20 | GH_TOKEN: "${{ github.TOKEN }}" 21 | 22 | jobs: 23 | build: 24 | runs-on: ubuntu-24.04-arm 25 | outputs: 26 | release_tags: ${{ steps.release_tags.outputs.release_tag }} 27 | strategy: 28 | fail-fast: false 29 | matrix: 30 | name: [iperf3] 31 | os_id: [alpine] 32 | os_version_id: [edge] 33 | arch: [amd64, arm32v6, arm32v7, arm64v8, i386, ppc64le, riscv64, s390x] 34 | include: 35 | - arch: amd64 36 | platform: linux/amd64 37 | - arch: arm32v6 38 | platform: linux/arm/v6 39 | - arch: arm32v7 40 | platform: linux/arm/v7 41 | - arch: arm64v8 42 | platform: linux/arm64 43 | - arch: i386 44 | platform: linux/i386 45 | - arch: ppc64le 46 | platform: linux/ppc64le 47 | - arch: riscv64 48 | platform: linux/riscv64 49 | - arch: s390x 50 | platform: linux/s390x 51 | 52 | name: ${{ matrix.name }} ${{ matrix.os_id }}:${{ matrix.os_version_id }} ${{ matrix.arch }} 53 | 54 | env: 55 | CDN: http://dl-cdn.alpinelinux.org/alpine/edge/main/ 56 | CXXFLAGS: "--static -static" 57 | CPPFLAGS: "--static -static" 58 | LDFLAGS: "--static -static" 59 | source_repo: ${{ inputs.source_repo }} 60 | source_branch: ${{ inputs.source_branch }} 61 | container_name: mcm 62 | 63 | steps: 64 | - name: Checkout 65 | uses: actions/checkout@v4 66 | with: 67 | persist-credentials: false 68 | 69 | - name: Host - Bootstrap qemu 70 | uses: userdocs/actions/qemu@main 71 | 72 | - name: Create docker ${{ env.container_name }} ${{ matrix.platform }} container 73 | run: > 74 | docker run --name ${container_name} -it -d -w /home/gh -v ${{ github.workspace }}:/home/gh --platform ${{ matrix.platform }} 75 | -e CXXFLAGS="${{ env.CXXFLAGS }}" 76 | -e CPPFLAGS="${{ env.CPPFLAGS }}" 77 | -e LDFLAGS="${{ env.LDFLAGS }}" 78 | ${{ matrix.arch }}/${{ matrix.os_id }}:${{ matrix.os_version_id }} 79 | 80 | docker exec ${container_name} sh -c 'adduser -h /home/gh -Ds /bin/bash -u 1001 gh && apk add sudo' 81 | docker exec ${container_name} sh -c 'printf "%s" "gh ALL=(ALL) NOPASSWD: ALL" > /etc/sudoers.d/gh' 82 | 83 | - name: Run apk update 84 | run: docker exec ${container_name} apk update 85 | 86 | - name: Run apk upgrade 87 | run: docker exec ${container_name} apk upgrade 88 | 89 | - name: Run apk to install the core build dependencies 90 | run: docker exec ${container_name} apk add build-base pkgconf autoconf automake curl libtool git tar curl perl openssl-dev openssl-libs-static linux-headers 91 | 92 | - name: Git clone ${{ matrix.name }} 93 | run: docker exec -u gh:gh ${container_name} git clone --no-tags --single-branch --branch "${source_branch}" --shallow-submodules --recurse-submodules -j"$(nproc)" --depth 1 "${source_repo}" /home/gh/${{ matrix.name }} 94 | 95 | - name: Configure ${{ matrix.name }} 96 | run: docker exec -u gh:gh -w /home/gh/${{ matrix.name }} ${container_name} ./configure --disable-shared --with-openssl=/usr --enable-static-bin --prefix=/home/gh 97 | 98 | - name: Make Build ${{ matrix.name }} 99 | run: docker exec -u gh:gh -w /home/gh/${{ matrix.name }} ${container_name} make -j$(nproc) 100 | 101 | - name: Make Install Build ${{ matrix.name }} 102 | run: docker exec -u gh:gh -w /home/gh/${{ matrix.name }} ${container_name} make install 103 | 104 | - name: Rename ${{ matrix.name }} to ${{ matrix.name }}-${{ matrix.arch }} 105 | run: docker exec -u gh:gh ${container_name} mv -f /home/gh/bin/${{ matrix.name }} /home/gh/${{ matrix.name }}-${{ matrix.arch }} 106 | 107 | - name: Create path to binary env 108 | run: printf '%s\n' "binary_path=${{ github.workspace }}/${{ matrix.name }}-${{ matrix.arch }}" >> $GITHUB_ENV 109 | 110 | - name: VirusTotal Scan 111 | id: virustotal 112 | uses: crazy-max/ghaction-virustotal@v4 113 | with: 114 | vt_api_key: ${{ secrets.VT_API_KEY }} 115 | files: ${{ env.binary_path }} 116 | 117 | - name: sha256sum 118 | run: | 119 | printf '%s' https://www.virustotal.com/gui/file/$(sha256sum ${{ env.binary_path }} | awk '{print $1}') > ${{ matrix.name }}-${{ matrix.arch }}.url 120 | cat ${{ matrix.name }}-${{ matrix.arch }}.url 121 | 122 | - name: Create tag env 123 | run: printf '%s\n' "release_tag=$(sed -rn 's|(.*)\[(.*)],\[https://github.com/esnet/iperf],(.*)|\2|p' ${{ matrix.name }}/configure.ac)" >> $GITHUB_ENV 124 | 125 | - name: Set tag env to output 126 | id: release_tags 127 | run: printf '%s\n' "release_tag=${{ env.release_tag }}" >> "$GITHUB_OUTPUT" 128 | 129 | - name: Generate artifact attestation 130 | uses: actions/attest-build-provenance@v2 131 | with: 132 | subject-path: ${{ env.binary_path }} 133 | 134 | - name: "Create artifact" 135 | uses: actions/upload-artifact@v4 136 | with: 137 | name: ${{ matrix.name }}-${{ matrix.arch }} 138 | path: | 139 | ${{ env.binary_path }} 140 | ${{ matrix.name }}-${{ matrix.arch }}.url 141 | -------------------------------------------------------------------------------- /.github/workflows/ci-main-reusable-caller.yml: -------------------------------------------------------------------------------- 1 | name: ci - main reusable caller 2 | 3 | on: 4 | workflow_dispatch: 5 | inputs: 6 | source_repo: 7 | description: "Define the git repo used for the build" 8 | required: true 9 | default: "https://github.com/esnet/iperf.git" 10 | source_branch: 11 | description: "Specify the branch or tag to build" 12 | required: true 13 | default: "master" 14 | skip_new_tag_check: 15 | description: "Bypass new tag check to force build?" 16 | required: true 17 | default: false 18 | type: boolean 19 | linux_build_type: 20 | description: "Build Linux iperf3 via crossbuild" 21 | required: true 22 | default: false 23 | type: boolean 24 | artifacts_only: 25 | description: "Skip release - artifacts only" 26 | required: true 27 | default: false 28 | type: boolean 29 | linux: 30 | description: "Skip Linux build" 31 | type: boolean 32 | required: true 33 | default: false 34 | windows: 35 | description: "Skip Windows build" 36 | type: boolean 37 | required: true 38 | default: false 39 | osx: 40 | description: "Skip OSX builds" 41 | type: boolean 42 | required: true 43 | default: false 44 | skip_rerun: 45 | description: "Skip rerun?" 46 | required: true 47 | default: false 48 | type: boolean 49 | retries: 50 | description: "Number of rerun retries" 51 | required: true 52 | default: "2" 53 | type: choice 54 | options: ["1", "2", "3", "4", "5", "6", "7", "8", "9"] 55 | 56 | schedule: 57 | - cron: "*/5 * * * *" # every 5 minutes 58 | 59 | permissions: {} 60 | 61 | env: 62 | GH_TOKEN: "${{ github.TOKEN }}" 63 | 64 | jobs: 65 | skip_duplicate_job: 66 | runs-on: ubuntu-24.04-arm 67 | permissions: 68 | actions: write 69 | contents: read 70 | outputs: 71 | should_skip: ${{ steps.skip_check.outputs.should_skip }} 72 | steps: 73 | - id: skip_check 74 | uses: fkirc/skip-duplicate-actions@v5 75 | with: 76 | concurrent_skipping: "always" 77 | cancel_others: "false" 78 | skip_after_successful_duplicate: false 79 | do_not_skip: "" 80 | 81 | scheduled_defaults: 82 | if: needs.skip_duplicate_job.outputs.should_skip != 'true' 83 | needs: skip_duplicate_job 84 | runs-on: ubuntu-24.04-arm 85 | permissions: 86 | contents: read 87 | outputs: 88 | source_repo: ${{ github.event.inputs.source_repo || 'https://github.com/esnet/iperf.git' }} 89 | source_branch: ${{ github.event.inputs.source_branch || 'master' }} 90 | artifacts_only: ${{ github.event.inputs.artifacts_only || 'false' }} 91 | skip_new_tag_check: ${{ github.event.inputs.skip_new_tag_check || 'false' }} 92 | linux_build_type: ${{ github.event.inputs.linux_build_type || 'false' }} 93 | linux: ${{ github.event.inputs.linux || 'false' }} 94 | windows: ${{ github.event.inputs.windows || 'false' }} 95 | osx: ${{ github.event.inputs.osx || 'false' }} 96 | skip_rerun: ${{ github.event.inputs.skip_rerun || 'false' }} 97 | retries: ${{ github.event.inputs.retries || '1' }} 98 | steps: 99 | - name: Setting Outputs from inputs 100 | run: | 101 | printf '%b\n\n' "Setting Outputs from Inputs" 102 | 103 | printf '%b\n\n' "Checking required secrets are set" >> $GITHUB_STEP_SUMMARY 104 | 105 | if [[ -z "${{ secrets.VT_API_KEY }}" ]]; then 106 | printf '%b\n\n' "VT_API_KEY is not set. Exiting..." >> $GITHUB_STEP_SUMMARY 107 | exit 1 108 | fi 109 | 110 | show_outputs: 111 | if: needs.skip_duplicate_job.outputs.should_skip != 'true' 112 | needs: scheduled_defaults 113 | runs-on: ubuntu-24.04-arm 114 | env: 115 | source_repo: ${{ needs.scheduled_defaults.outputs.source_repo }} 116 | source_branch: ${{ needs.scheduled_defaults.outputs.source_branch }} 117 | artifacts_only: ${{ needs.scheduled_defaults.outputs.artifacts_only }} 118 | skip_new_tag_check: ${{ needs.scheduled_defaults.outputs.skip_new_tag_check }} 119 | linux_build_type: ${{ needs.scheduled_defaults.outputs.linux_build_type }} 120 | linux: ${{ needs.scheduled_defaults.outputs.linux }} 121 | windows: ${{ needs.scheduled_defaults.outputs.windows }} 122 | osx: ${{ needs.scheduled_defaults.outputs.osx }} 123 | skip_rerun: ${{ needs.scheduled_defaults.outputs.skip_rerun }} 124 | retries: ${{ needs.scheduled_defaults.outputs.retries }} 125 | steps: 126 | - name: Set output 127 | run: | 128 | printf '%b\n' "# Scheduled Defaults Outputs Summary" >> $GITHUB_STEP_SUMMARY 129 | printf '\n%b\n' ":octocat: Here is a summary of inputs set as string outputs that are used in workflows." >> $GITHUB_STEP_SUMMARY 130 | 131 | printf '\n%b\n' "source_repo: \`${source_repo}\`" >> $GITHUB_STEP_SUMMARY 132 | printf '\n%b\n' "source_branch: \`${source_branch}\`" >> $GITHUB_STEP_SUMMARY 133 | printf '\n%b\n' "artifacts_only: \`${artifacts_only}\`" >> $GITHUB_STEP_SUMMARY 134 | printf '\n%b\n' "skip_new_tag_check: \`${skip_new_tag_check}\`" >> $GITHUB_STEP_SUMMARY 135 | printf '\n%b\n' "linux_build_type: \`${linux_build_type}\`" >> $GITHUB_STEP_SUMMARY 136 | printf '\n%b\n' "linux: \`${linux}\`" >> $GITHUB_STEP_SUMMARY 137 | printf '\n%b\n' "windows: \`${windows}\`" >> $GITHUB_STEP_SUMMARY 138 | printf '\n%b\n' "osx: \`${osx}\`" >> $GITHUB_STEP_SUMMARY 139 | printf '\n%b\n' "skip_rerun: \`${skip_rerun}\`" >> $GITHUB_STEP_SUMMARY 140 | printf '\n%b\n' "retries: \`${retries}\`" >> $GITHUB_STEP_SUMMARY 141 | 142 | iperf3_tag: 143 | needs: scheduled_defaults 144 | if: needs.scheduled_defaults.outputs.skip_new_tag_check == 'false' && needs.skip_duplicate_job.outputs.should_skip != 'true' 145 | uses: ./.github/workflows/ci-check-for-new-release-tag.yml 146 | 147 | linux_emulation: 148 | needs: [scheduled_defaults, iperf3_tag] 149 | if: > 150 | always() && !failure() && !cancelled() && 151 | ( needs.iperf3_tag.outputs.continue_build == 'yes' || needs.scheduled_defaults.outputs.skip_new_tag_check == 'true' ) && 152 | ( needs.scheduled_defaults.outputs.linux == 'false' && needs.scheduled_defaults.outputs.linux_build_type == 'false' && needs.skip_duplicate_job.outputs.should_skip != 'true' ) 153 | permissions: 154 | id-token: write 155 | attestations: write 156 | contents: read 157 | uses: ./.github/workflows/ci-linux-emulation.yml 158 | secrets: 159 | VT_API_KEY: ${{ secrets.VT_API_KEY || '' }} 160 | with: 161 | source_repo: ${{ needs.scheduled_defaults.outputs.source_repo }} 162 | source_branch: ${{ needs.iperf3_tag.outputs.iperf3_tag || needs.scheduled_defaults.outputs.source_branch }} 163 | 164 | linux_crossbuild: 165 | needs: [scheduled_defaults, iperf3_tag] 166 | if: > 167 | always() && !failure() && !cancelled() && 168 | ( needs.iperf3_tag.outputs.continue_build == 'yes' || needs.scheduled_defaults.outputs.skip_new_tag_check == 'true' ) && 169 | ( needs.scheduled_defaults.outputs.linux == 'false' && needs.scheduled_defaults.outputs.linux_build_type == 'true' && needs.skip_duplicate_job.outputs.should_skip != 'true' ) 170 | permissions: 171 | id-token: write 172 | attestations: write 173 | contents: read 174 | uses: ./.github/workflows/ci-linux-crossbuild.yml 175 | secrets: 176 | VT_API_KEY: ${{ secrets.VT_API_KEY || '' }} 177 | with: 178 | source_repo: ${{ needs.scheduled_defaults.outputs.source_repo }} 179 | source_branch: ${{ needs.iperf3_tag.outputs.iperf3_tag || needs.scheduled_defaults.outputs.source_branch }} 180 | 181 | windows: 182 | needs: [scheduled_defaults, iperf3_tag] 183 | if: > 184 | always() && !failure() && !cancelled() && 185 | ( needs.iperf3_tag.outputs.continue_build == 'yes' || needs.scheduled_defaults.outputs.skip_new_tag_check == 'true' ) && 186 | ( needs.scheduled_defaults.outputs.windows == 'false' && needs.skip_duplicate_job.outputs.should_skip != 'true' ) 187 | permissions: 188 | id-token: write 189 | attestations: write 190 | contents: read 191 | uses: ./.github/workflows/ci-windows.yml 192 | secrets: 193 | VT_API_KEY: ${{ secrets.VT_API_KEY || '' }} 194 | with: 195 | source_repo: ${{ needs.scheduled_defaults.outputs.source_repo }} 196 | source_branch: ${{ needs.iperf3_tag.outputs.iperf3_tag || needs.scheduled_defaults.outputs.source_branch }} 197 | artifacts_only: ${{ needs.scheduled_defaults.outputs.artifacts_only }} 198 | 199 | osx: 200 | needs: [scheduled_defaults, iperf3_tag] 201 | if: > 202 | always() && !failure() && !cancelled() && 203 | ( needs.iperf3_tag.outputs.continue_build == 'yes' || needs.scheduled_defaults.outputs.skip_new_tag_check == 'true' ) && 204 | ( needs.scheduled_defaults.outputs.osx == 'false' && needs.skip_duplicate_job.outputs.should_skip != 'true' ) 205 | permissions: 206 | id-token: write 207 | attestations: write 208 | contents: read 209 | strategy: 210 | matrix: 211 | target: [macos-13, macos-latest] 212 | include: 213 | - target: macos-13 214 | binary_filename: amd64-osx-13 215 | brew_cellar: "/usr/local/Cellar" 216 | brew_install: "brew install automake" 217 | - target: macos-latest 218 | binary_filename: arm64-osx-14 219 | brew_cellar: "/opt/homebrew/Cellar" 220 | brew_install: "brew install autoconf automake libtool" 221 | uses: ./.github/workflows/ci-osx.yml 222 | secrets: 223 | VT_API_KEY: ${{ secrets.VT_API_KEY }} 224 | with: 225 | brew_cellar: ${{ matrix.brew_cellar }} 226 | brew_install: ${{ matrix.brew_install }} 227 | target: ${{ matrix.target }} 228 | source_repo: ${{ needs.scheduled_defaults.outputs.source_repo }} 229 | source_branch: ${{ needs.iperf3_tag.outputs.iperf3_tag || needs.scheduled_defaults.outputs.source_branch }} 230 | binary_filename: ${{ matrix.binary_filename }} 231 | 232 | release: 233 | needs: [scheduled_defaults, linux_emulation, linux_crossbuild, windows, osx] 234 | if: > 235 | always() && !failure() && !cancelled() && 236 | ( needs.linux_emulation.result == 'success' || needs.linux_crossbuild.result == 'success' || needs.windows.result == 'success' || needs.osx.result == 'success' ) && 237 | !contains(needs.*.result, 'failure') && 238 | needs.scheduled_defaults.outputs.artifacts_only == 'false' && 239 | needs.skip_duplicate_job.outputs.should_skip != 'true' 240 | permissions: 241 | contents: write 242 | uses: ./.github/workflows/ci-release.yml 243 | with: 244 | release_tags: ${{ needs.linux_emulation.outputs.release_tags || needs.linux_crossbuild.outputs.release_tags || needs.windows.outputs.release_tags || needs.osx.outputs.release_tags }} 245 | test_linux_emulation: ${{ needs.linux_emulation.result }} 246 | test_linux_crossbuild: ${{ needs.linux_crossbuild.result }} 247 | test_windows: ${{ needs.windows.result }} 248 | test_osx: ${{ needs.osx.result }} 249 | 250 | docker: 251 | needs: [scheduled_defaults, linux_emulation, linux_crossbuild, release] 252 | if: > 253 | always() && !failure() && !cancelled() && 254 | ( needs.linux_emulation.result == 'success' || needs.linux_crossbuild.result == 'success' ) && 255 | !contains(needs.*.result, 'failure') && 256 | needs.scheduled_defaults.outputs.linux == 'false' && 257 | needs.scheduled_defaults.outputs.artifacts_only == 'false' && 258 | needs.skip_duplicate_job.outputs.should_skip != 'true' 259 | permissions: 260 | packages: write 261 | uses: ./.github/workflows/ci-docker.yml 262 | 263 | rerun_on_failure: 264 | needs: 265 | [ 266 | skip_duplicate_job, 267 | scheduled_defaults, 268 | show_outputs, 269 | iperf3_tag, 270 | linux_emulation, 271 | linux_crossbuild, 272 | windows, 273 | osx, 274 | release, 275 | docker, 276 | ] 277 | if: > 278 | failure() && 279 | ( needs.scheduled_defaults.outputs.skip_rerun == 'false' && needs.skip_duplicate_job.outputs.should_skip != 'true' ) 280 | concurrency: 281 | group: ci-auto-rerun-failed-jobs 282 | cancel-in-progress: true 283 | permissions: 284 | actions: write 285 | runs-on: ubuntu-24.04-arm 286 | env: 287 | GH_TOKEN: "${{ secrets.AUTO_RERUN || github.token }}" 288 | github_repo: "" # To use ci-auto-rerun-failed-jobs.yml hosted in a remote repository else default to the current repository. Requires PAT token AUTO_RERUN 289 | retries: ${{ github.event.inputs.retries || '1' }} 290 | distinct_id: ${{ github.event.inputs.distinct_id }} 291 | steps: 292 | - uses: actions/checkout@v4 293 | with: 294 | persist-credentials: false 295 | - name: ci-auto-rerun-failed-jobs via ${{ env.github_repo || github.repository }} 296 | run: > 297 | gh workflow run ci-auto-rerun-failed-jobs-action.yml 298 | --repo "${github_repo:-$GITHUB_REPOSITORY}" 299 | -f github_repo=${GITHUB_REPOSITORY} 300 | -f run_id=${GITHUB_RUN_ID} 301 | -f attempts=${GITHUB_RUN_ATTEMPT} 302 | -f retries=${retries} 303 | -f distinct_id=${distinct_id} 304 | -------------------------------------------------------------------------------- /.github/workflows/ci-osx.yml: -------------------------------------------------------------------------------- 1 | name: ci - osx 2 | 3 | on: 4 | workflow_call: 5 | outputs: 6 | release_tags: 7 | value: ${{ jobs.build.outputs.release_tags }} 8 | inputs: 9 | source_repo: 10 | type: string 11 | required: true 12 | source_branch: 13 | type: string 14 | required: true 15 | brew_cellar: 16 | type: string 17 | required: true 18 | brew_install: 19 | type: string 20 | required: true 21 | target: 22 | type: string 23 | required: true 24 | binary_filename: 25 | type: string 26 | required: true 27 | secrets: 28 | VT_API_KEY: 29 | required: false 30 | 31 | env: 32 | GH_TOKEN: "${{ github.TOKEN }}" 33 | binary_filename: ${{ inputs.binary_filename }} 34 | source_repo: ${{ inputs.source_repo }} 35 | source_branch: ${{ inputs.source_branch }} 36 | brew_cellar: ${{ inputs.brew_cellar }} 37 | brew_install: ${{ inputs.brew_install }} 38 | target: ${{ inputs.target }} 39 | 40 | jobs: 41 | build: 42 | runs-on: ${{ inputs.target }} 43 | outputs: 44 | release_tags: ${{ steps.release_tags.outputs.release_tag }} 45 | steps: 46 | - name: Clone repository 47 | uses: actions/checkout@v4 48 | with: 49 | persist-credentials: false 50 | 51 | - name: Install packages 52 | run: | 53 | brew update || brew update-reset 54 | ${brew_install} 55 | 56 | - name: Check openssl 57 | run: ls -la ${brew_cellar}/openssl@3/*/lib 58 | 59 | - name: Copy Openssl Static Libraries to openssl_libs 60 | run: | 61 | mkdir -p ${{ github.workspace }}/openssl_libs 62 | cp -fv ${brew_cellar}/openssl@3/*/lib/libcrypto.a ${{ github.workspace }}/openssl_libs/ 63 | cp -fv ${brew_cellar}/openssl@3/*/lib/libssl.a ${{ github.workspace }}/openssl_libs/ 64 | 65 | - name: Check openssl_libs 66 | run: ls -la openssl_libs 67 | 68 | - name: Clone iperf3 repository 69 | run: git clone --no-tags --single-branch --branch ${source_branch} --shallow-submodules --recurse-submodule --depth 1 ${source_repo} iperf3 70 | 71 | - name: Bootstrap 72 | working-directory: iperf3 73 | run: ./bootstrap.sh 74 | 75 | - name: Set CC 76 | run: printf '%s\n' "LDFLAGS=-L${{ github.workspace }}/openssl_libs" >> "$GITHUB_ENV" 77 | 78 | - name: Configure 79 | working-directory: iperf3 80 | run: ./configure --enable-shared=no --disable-silent-rules --disable-profiling --prefix=${{ github.workspace }}/build 81 | 82 | - name: Make 83 | working-directory: iperf3 84 | run: make -j"$(sysctl -n hw.logicalcpu)" 85 | 86 | - name: Make install 87 | working-directory: iperf3 88 | run: make install 89 | 90 | - name: Test iperf3 build 91 | run: | 92 | printf '\n%b\n\n' "🟦" 93 | ${{ github.workspace }}/build/bin/iperf3 --version 94 | printf '\n%b\n\n' "🟦" 95 | file ${{ github.workspace }}/build/bin/iperf3 96 | printf '\n%b\n\n' "🟦" 97 | otool -L ${{ github.workspace }}/build/bin/iperf3 98 | 99 | - name: Process iperf3 build 100 | run: mv -f ${{ github.workspace }}/build/bin/iperf3 ${{ github.workspace }}/iperf3-${binary_filename} 101 | 102 | - name: Create path to binary env 103 | run: printf '%s\n' "binary_path=${{ github.workspace }}/iperf3-${binary_filename}" >> $GITHUB_ENV 104 | 105 | - name: VirusTotal Scan 106 | id: virustotal 107 | uses: crazy-max/ghaction-virustotal@v4 108 | with: 109 | vt_api_key: ${{ secrets.VT_API_KEY }} 110 | files: ${{ env.binary_path }} 111 | 112 | - name: sha256sum 113 | run: | 114 | printf '%s' https://www.virustotal.com/gui/file/$(shasum -a 256 ${{ env.binary_path }} | awk '{print $1}') > iperf3-${binary_filename}.url 115 | cat iperf3-${binary_filename}.url 116 | 117 | - name: Create tag env 118 | run: printf '%s\n' "release_tag=$(sed -rn 's|(.*)\[(.*)],\[https://github.com/esnet/iperf],(.*)|\2|p' iperf3/configure.ac)" >> $GITHUB_ENV 119 | 120 | - name: Set tag env to output 121 | id: release_tags 122 | run: printf '%s\n' "release_tag=${{ env.release_tag }}" >> "$GITHUB_OUTPUT" 123 | 124 | - name: Generate artifact attestation 125 | uses: actions/attest-build-provenance@v2 126 | with: 127 | subject-path: ${{ env.binary_path }} 128 | 129 | - name: Upload artifact 130 | uses: actions/upload-artifact@v4 131 | with: 132 | name: iperf3-${{ inputs.binary_filename }} 133 | path: | 134 | ${{ env.binary_path }} 135 | iperf3-${binary_filename}.url 136 | 137 | - name: Upload artifact 138 | if: failure() 139 | uses: actions/upload-artifact@v4 140 | with: 141 | name: iperf3-${{ inputs.binary_filename }}-config.log 142 | path: ${{ github.workspace }}/iperf3/config.log 143 | -------------------------------------------------------------------------------- /.github/workflows/ci-release.yml: -------------------------------------------------------------------------------- 1 | name: ci - release 2 | 3 | on: 4 | workflow_call: 5 | inputs: 6 | release_tags: 7 | type: string 8 | test_linux_emulation: 9 | type: string 10 | test_linux_crossbuild: 11 | type: string 12 | test_windows: 13 | type: string 14 | test_osx: 15 | type: string 16 | 17 | env: 18 | GH_TOKEN: "${{ github.TOKEN }}" 19 | release_tags: ${{ inputs.release_tags }} 20 | test_linux_emulation: ${{ inputs.test_linux_emulation }} 21 | test_linux_crossbuild: ${{ inputs.test_linux_crossbuild }} 22 | test_windows: ${{ inputs.test_windows }} 23 | test_osx: ${{ inputs.test_osx }} 24 | 25 | jobs: 26 | release: 27 | runs-on: ubuntu-24.04-arm 28 | steps: 29 | - name: Checkout 30 | uses: actions/checkout@v4 31 | with: 32 | persist-credentials: false 33 | 34 | - name: Summary - needs results 35 | run: | 36 | printf '%s\n\n' "## Summary - needs results" 37 | printf '%s\n\n' "release_tags: \`${release_tags}\`" >> $GITHUB_STEP_SUMMARY 38 | printf '\n%s\n' "test_linux_emulation: \`${test_linux_emulation}\`" >> $GITHUB_STEP_SUMMARY 39 | printf '\n%s\n' "test_linux_crossbuild: \`${test_linux_crossbuild}\`" >> $GITHUB_STEP_SUMMARY 40 | printf '\n%s\n' "test_windows: \`${test_windows}\`" >> $GITHUB_STEP_SUMMARY 41 | printf '\n%s\n' "test_osx: \`${test_osx}\`" >> $GITHUB_STEP_SUMMARY 42 | 43 | - name: Download artifacts 44 | uses: actions/download-artifact@v4 45 | with: 46 | path: "release-artifacts" 47 | pattern: iperf3-* 48 | merge-multiple: true 49 | 50 | - name: Virustotal scan results 51 | run: | 52 | pushd release-artifacts || exit 1 53 | 54 | for virus_total_urls in iperf3-*\.url; do 55 | dependency_version+=("${virus_total_urls}") 56 | done 57 | 58 | readarray -t release_sorted < <(printf '%s\n' "${dependency_version[@]}" | sort) 59 | 60 | if command_output="$(gh release view "${release_tags}" --repo "${{ github.repository }}" --json body -q .body 2>&1)"; then 61 | if [[ -n "${command_output}" ]]; then 62 | sed '// {q}' ${{ github.workspace }}/ci-release-body.md > ci-release-body.md 63 | printf '%s\n' "$command_output" | sed -n '//,$p' >> ci-release-body.md 64 | else 65 | cp -f ${{ github.workspace }}/ci-release-body.md ci-release-body.md 66 | fi 67 | else 68 | cp -f ${{ github.workspace }}/ci-release-body.md ci-release-body.md 69 | fi 70 | 71 | for filenames in "${release_sorted[@]}"; do 72 | virustotal_url="$(head -1 "${filenames}" | tr -d '\n' | tr -d '\r' | tr -d '\r\n')" 73 | sed -i -r 's|(\['${filenames//\.url/}'\])\((.*)\)|\1('${virustotal_url}')|' ci-release-body.md 74 | done 75 | 76 | - name: "Publish release ${{ inputs.release_tags }}" 77 | uses: ncipollo/release-action@v1 78 | with: 79 | prerelease: false 80 | artifacts: release-artifacts/iperf3-*[!\.url] 81 | replacesArtifacts: true 82 | tag: ${{ inputs.release_tags }} 83 | name: iperf3 ${{ inputs.release_tags }} 84 | allowUpdates: true 85 | bodyFile: release-artifacts/ci-release-body.md 86 | token: ${{ github.token }} 87 | -------------------------------------------------------------------------------- /.github/workflows/ci-windows.yml: -------------------------------------------------------------------------------- 1 | name: ci - windows binary build 2 | 3 | on: 4 | workflow_call: 5 | outputs: 6 | release_tags: 7 | value: ${{ jobs.build.outputs.release_tags }} 8 | inputs: 9 | source_repo: 10 | type: string 11 | required: true 12 | source_branch: 13 | type: string 14 | required: true 15 | artifacts_only: 16 | type: string 17 | required: true 18 | secrets: 19 | VT_API_KEY: 20 | required: false 21 | 22 | env: 23 | GH_TOKEN: "${{ github.TOKEN }}" 24 | 25 | jobs: 26 | build: 27 | runs-on: windows-latest 28 | outputs: 29 | release_tags: ${{ steps.release_tags.outputs.release_tag }} 30 | strategy: 31 | fail-fast: false 32 | matrix: 33 | name: [iperf3] 34 | build: [basic, openssl] 35 | arch: [amd64] 36 | include: 37 | - build: "basic" 38 | filename: "" 39 | openssl: "no" 40 | - build: "openssl" 41 | filename: "-openssl" 42 | openssl: "yes" 43 | 44 | name: ${{ matrix.name }}-${{ matrix.arch }}-win${{ matrix.filename }}.zip 45 | 46 | env: 47 | cygwin_path: "cygwin" 48 | source_branch: ${{ inputs.source_branch }} 49 | source_repo: ${{ inputs.source_repo }} 50 | 51 | steps: 52 | - run: git config --global core.autocrlf input 53 | 54 | - name: Checkout 55 | uses: actions/checkout@v4 56 | with: 57 | persist-credentials: false 58 | 59 | - name: Install ci-cygwin-installer.cmd 60 | run: .\ci-cygwin-installer.cmd 61 | 62 | - name: Build static 63 | 64 | run: .\cygwin\bin\bash.exe -l ci-windows-cygwin-build.sh "${{ matrix.openssl }}" "$env:cygwin_path" "$env:source_repo" "$env:source_branch" 65 | 66 | - name: VirusTotal Scan 67 | id: virustotal 68 | uses: crazy-max/ghaction-virustotal@v4 69 | with: 70 | vt_api_key: ${{ secrets.VT_API_KEY }} 71 | files: | 72 | ${{ matrix.name }}/bin/iperf3.exe 73 | ${{ matrix.name }}/bin/cygwin1.dll 74 | 75 | - name: sha256sum 76 | run: | 77 | printf '%s' https://www.virustotal.com/gui/file/$(sha256sum ${{ matrix.name }}/bin/iperf3.exe | awk '{print $1}') > ${{ matrix.name }}-${{ matrix.arch }}-win${{ matrix.filename }}.url 78 | cat ${{ matrix.name }}-${{ matrix.arch }}-win${{ matrix.filename }}.url 79 | 80 | - name: Archive build 81 | run: Compress-Archive -Path "${{ matrix.name }}/bin/*" -DestinationPath "${{ matrix.name }}-${{ matrix.arch }}-win${{ matrix.filename }}.zip" 82 | 83 | - name: Generate artifact attestation 84 | uses: actions/attest-build-provenance@v2 85 | with: 86 | subject-path: | 87 | ${{ matrix.name }}-${{ matrix.arch }}-win${{ matrix.filename }}.zip 88 | ${{ matrix.name }}/bin/iperf3.exe 89 | ${{ matrix.name }}/bin/cygwin1.dll 90 | 91 | - name: Create tag env 92 | run: printf '%s\n' "release_tag=$(Get-Content -Path iperf3_version)" | Out-File -FilePath $Env:GITHUB_ENV -Encoding utf8 -Append 93 | 94 | - name: Set tag env to output 95 | id: release_tags 96 | run: printf '%s\n' "release_tag=${{ env.release_tag }}" >> $env:GITHUB_OUTPUT 97 | 98 | - name: "Release - Create artifacts" 99 | if: inputs.artifacts_only == 'false' 100 | uses: actions/upload-artifact@v4 101 | with: 102 | name: "${{ matrix.name }}-amd64-win${{ matrix.filename }}" 103 | path: | 104 | ${{ matrix.name }}-${{ matrix.arch }}-win${{ matrix.filename }}.zip 105 | ${{ matrix.name }}-${{ matrix.arch }}-win${{ matrix.filename }}.url 106 | 107 | - name: "Dev - Create artifacts" 108 | if: inputs.artifacts_only == 'true' 109 | uses: actions/upload-artifact@v4 110 | with: 111 | name: "${{ matrix.name }}-amd64-win${{ matrix.filename }}" 112 | path: "${{ matrix.name }}" 113 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: test iperf3 release binaries for windows and osx 2 | 3 | on: 4 | workflow_dispatch: 5 | 6 | permissions: {} 7 | 8 | jobs: 9 | test-osx-amd64: 10 | runs-on: macos-13 11 | permissions: 12 | contents: read 13 | 14 | steps: 15 | - name: brew install 16 | run: brew install coreutils 17 | 18 | - name: test iperf3 version 19 | run: | 20 | wget -O ~/iperf3 "https://github.com/${{ github.repository }}/releases/latest/download/iperf3-amd64-osx-13" 21 | chmod +x ~/iperf3 22 | 23 | printf '\n%b\n\n' "🟦" 24 | file ~/iperf3 25 | 26 | printf '\n%b\n\n' "🟦" 27 | otool -L ~/iperf3 28 | 29 | printf '\n%b\n\n' "🟦" 30 | ~/iperf3 --version 31 | 32 | - name: test iperf3 servers 33 | run: | 34 | ~/$(wget -qO- https://db.iperf3serverlist.net/api/v1/db/public/shared-view/b111407c-43c4-48af-a828-301b698064a3/rows/export/csv | awk -F, 'NR>1 { print $1 }' | shuf -n1) 35 | 36 | test-osx-arm64: 37 | runs-on: macos-latest 38 | permissions: 39 | contents: read 40 | 41 | steps: 42 | - name: brew install 43 | run: brew install coreutils 44 | 45 | - name: test iperf3 version 46 | run: | 47 | wget -O ~/iperf3 "https://github.com/${{ github.repository }}/releases/latest/download/iperf3-arm64-osx-14" 48 | chmod +x ~/iperf3 49 | 50 | printf '\n%b\n\n' "🟦" 51 | file ~/iperf3 52 | 53 | printf '\n%b\n\n' "🟦" 54 | otool -L ~/iperf3 55 | 56 | printf '\n%b\n\n' "🟦" 57 | ~/iperf3 --version 58 | 59 | - name: test iperf3 servers 60 | run: | 61 | ~/$(wget -qO- https://db.iperf3serverlist.net/api/v1/db/public/shared-view/b111407c-43c4-48af-a828-301b698064a3/rows/export/csv | awk -F, 'NR>1 { print $1 }' | shuf -n1) 62 | 63 | test-windows: 64 | runs-on: windows-latest 65 | permissions: 66 | contents: read 67 | defaults: 68 | run: 69 | shell: bash 70 | 71 | steps: 72 | - name: test iperf3 version 73 | run: | 74 | curl -sL "https://github.com/${{ github.repository }}/releases/latest/download/iperf3-amd64-win.zip" -o iperf3.zip 75 | unzip iperf3.zip 76 | ls -la 77 | chmod +x iperf3.exe 78 | ./iperf3.exe --version 79 | 80 | - name: test iperf3 servers 81 | run: ./$(curl -sL https://db.iperf3serverlist.net/api/v1/db/public/shared-view/b111407c-43c4-48af-a828-301b698064a3/rows/export/csv | awk -F, 'NR>1 { print $1 }' | shuf -n1) 82 | 83 | test-windows-openssl: 84 | runs-on: windows-latest 85 | defaults: 86 | run: 87 | shell: bash 88 | 89 | steps: 90 | - name: Download iperf3 91 | run: | 92 | curl -sL "https://github.com/${{ github.repository }}/releases/latest/download/iperf3-amd64-win-openssl.zip" -o iperf3.zip 93 | unzip iperf3.zip 94 | ls -la 95 | chmod +x iperf3.exe 96 | ./iperf3.exe --version 97 | 98 | - name: test iperf3 servers 99 | run: ./$(curl -sL https://db.iperf3serverlist.net/api/v1/db/public/shared-view/b111407c-43c4-48af-a828-301b698064a3/rows/export/csv | awk -F, 'NR>1 { print $1 }' | shuf -n1) 100 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/* 2 | package-lock.json 3 | package.json 4 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM alpine:latest AS builder 2 | 3 | ARG ARCH="amd64" 4 | ARG REPO="userdocs/iperf3-static" 5 | 6 | RUN apk update \ 7 | && apk upgrade \ 8 | && apk add sudo \ 9 | && adduser -Ds /bin/bash -u 1000 username \ 10 | && printf '%s' 'username ALL=(ALL) NOPASSWD: ALL' > /etc/sudoers.d/github 11 | 12 | ADD --chown=username:username --chmod=700 "https://github.com/${REPO}/releases/latest/download/iperf3-${ARCH}" /usr/local/bin/iperf3 13 | 14 | USER username 15 | 16 | WORKDIR /home/username 17 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # iperf3 static builds 2 | 3 | - iperf3 windows builds 4 | - iperf3 linux builds 5 | - iperf3 macosx builds 6 | 7 | The only resource providing multiplatform distro independent iperf3 latest releases that has a 100% transparent build process from end to end. Complete accountability and verified chain of custody. No hidden parts. 8 | 9 | - [Chain of custody and build provenance](https://github.com/userdocs/iperf3-static?tab=readme-ov-file#gh-attestation-verify) - easily verify the archive or binary was created here. 10 | - [Transparent build process from source code to binary](https://github.com/userdocs/iperf3-static/actions) - source code > workflow > verification > release. 11 | - [Virustotal scan and details during the build process](https://github.com/userdocs/iperf3-static?tab=readme-ov-file#gh-attestation-verify) - scanned before release. 12 | - [Zizmor workflow auditing](https://github.com/woodruffw/zizmor) - helping ensure the worklow itself is not poisoned. 13 | - Powerful build system with ability to specify repo and branches to easily build patches or custom builds. 14 | 15 | ![](.github/assets/images/inputs.png) 16 | 17 | ## Build Platforms 18 | 19 | - [Alpine linux](https://alpinelinux.org) edge using [qemu emulation](https://www.qemu.org) 20 | - Windows on [Github Actions runners](https://github.com/actions/runner-images?tab=readme-ov-file#available-images) for x86_64 using a custom [Cywgin installer script](https://github.com/userdocs/iperf3-static/blob/master/cygwin-installer.cmd) 21 | - MacOS on [Github Actions runners](https://github.com/actions/runner-images?tab=readme-ov-file#available-images) for amd64 (mmacos-13) and arm64 (macos-14) with static openssl and iperf libraries. 22 | 23 | ## Available architectures 24 | 25 | Linux: 26 | 27 | - Arch: `amd64` `arm32v6` `arm32v7` `arm64v8` `i386` `ppc64le` `riscv64` `s390x` 28 | - Docker: yes 29 | - Static binaries: yes 30 | - Openssl latest release - https://github.com/openssl/openssl/releases/latest 31 | 32 | Windows: 33 | 34 | - Arch: `amd64` 35 | - Docker: no 36 | - Static binaries: yes 37 | - Openssl 3.1.x - Releases after this don't work with cygwin / iperf3 for windows builds. 38 | 39 | MacOS: 40 | 41 | - Arch: `amd64` `arm64` 42 | - Docker: no 43 | - Static binaries: yes 44 | - Openssl@3 - https://formulae.brew.sh/formula/openssl@3 45 | 46 | > [!NOTE] 47 | > Windows and MacOS binaries are not fully static in terms of their dependency and `cygwin1.dll` (Windows) `libSystem.B.dylib` (MasOS). 48 | > They are statically linked with `libcrypo.a` `libssl.a` (openssl) and `iperf3.a` (iperf3) so there should be no other system dependency required to run them on the target hosts. 49 | > 50 | > On Windows openssl is built from Github source to get static libs and on MacOS we get them from the brew cellar installation of `openssl@3` 51 | 52 | ## Download - Static Binaries 53 | 54 | Static binaries for Linux and Windows are available here: https://github.com/userdocs/iperf3-static/releases/latest 55 | 56 | Example: 57 | 58 | ``` 59 | curl -sLo- iperf3 https://github.com/userdocs/iperf3-static/releases/latest/download/iperf3-amd64 60 | chmod +x iperf3 61 | iperf3 --version 62 | ``` 63 | 64 | ## Download - Docker 65 | 66 | Multiarch Docker images are available via https://github.com/users/userdocs/packages/container/package/iperf3-static 67 | 68 | Example: 69 | 70 | ```bash 71 | docker pull ghcr.io/userdocs/iperf3-static:latest 72 | ``` 73 | 74 | To used the image dynamically 75 | 76 | ```bash 77 | docker run -it ghcr.io/userdocs/iperf3-static:latest iperf3 --version 78 | ``` 79 | 80 | ## Alpine multiarch info 81 | 82 |
83 | Expand for details 84 | 85 | | Alpine Arch | Docker platform arch | Source of Build Dockers | ghcr.io image | 86 | | :---------: | :------------------: | :-------------------------------------: | :-----------------: | 87 | | armhf | linux/arm/v6 | https://hub.docker.com/r/arm32v6/alpine | arm32v6/alpine:edge | 88 | | armv7 | linux/arm/v7 | https://hub.docker.com/r/arm32v7/alpine | arm32v7/alpine:edge | 89 | | aarch64 | linux/arm64 | https://hub.docker.com/r/arm64v8/alpine | arm64v8/alpine:edge | 90 | | ppc64le | linux/ppc64le | https://hub.docker.com/r/ppc64le/alpine | ppc64le/alpine:edge | 91 | | s390x | linux/s390x | https://hub.docker.com/r/s390x/alpine | s390x/alpine:edge | 92 | | riscv64 | linux/riscv64 | https://hub.docker.com/r/riscv64/alpine | riscv64/alpine:edge | 93 | | x86 | linux/i386 | https://hub.docker.com/r/i386/alpine | i386/alpine:edge | 94 | | x86_64 | linux/amd64 | https://hub.docker.com/r/amd64/alpine | amd64/alpine:edge | 95 | 96 |
97 | 98 | ## Windows x86_64 info 99 | 100 |
101 | Expand for details 102 | 103 | Static Cygwin builds created via cygwin64 using this custom installer 104 | 105 | https://github.com/userdocs/iperf3-static/blob/master/cygwin-installer.cmd 106 | 107 |
108 | 109 | ## Generic Build dependencies 110 | 111 |
112 | Expand for details 113 | 114 | ``` 115 | apk add build-base pkgconf autoconf automake curl libtool git perl openssl-libs-static openssl-dev linux-headers 116 | ``` 117 | 118 | #### Debian linux 119 | 120 | ``` 121 | apt install -y build-essential pkg-config automake libtool libssl-dev git perl 122 | ``` 123 | 124 | #### Cygwin packages 125 | 126 | Without openssl 127 | 128 | ```bash 129 | automake,gcc-core,gcc-g++,git,libtool,make,pkg-config 130 | ``` 131 | 132 | With openssl 133 | 134 | ```bash 135 | automake,gcc-core,gcc-g++,git,libtool,make,pkg-config,libssl-devel,zlib-devel 136 | ``` 137 | 138 | ### Generic Build Instructions 139 | 140 | Clone the git repo - linux + Cygwin 141 | 142 | ```bash 143 | git clone https://github.com/esnet/iperf.git ~/iperf3 && cd ~/iperf3 144 | ``` 145 | 146 | Bootstrap - If you cloned the repo 147 | 148 | ```bash 149 | ./bootstrap.sh 150 | ``` 151 | 152 | Configure - linux + Cygwin 153 | 154 | Note: Cygwin requires requires compiling openssl and zlib static libs to link statically. Otherwise you compile dynamically 155 | 156 | Static 157 | 158 | ```bash 159 | ./configure --disable-shared --enable-static-bin --prefix=$HOME 160 | ``` 161 | 162 | Dynamic 163 | 164 | ```bash 165 | ./configure --prefix=$HOME 166 | ``` 167 | 168 | Cygwin openssl requires compiling openssl and zlib 169 | 170 | Build - linux + Cygwin 171 | 172 | ``` 173 | make -j$(nproc) 174 | make install 175 | ``` 176 | 177 | ### Check the linking was done properly 178 | 179 | ``` 180 | ldd ~/bin/iperf3 181 | ``` 182 | 183 | ### Version 184 | 185 | Use this command to check the version. 186 | 187 | ``` 188 | ~/bin/iperf3 -v 189 | ``` 190 | 191 | Will show something like this. 192 | 193 | ``` 194 | iperf 3.10.1 (cJSON 1.7.13) 195 | Optional features available: CPU affinity setting, IPv6 flow label, TCP congestion algorithm setting, sendfile / zerocopy, socket pacing, authentication, bind to device, support IPv4 don't fragment 196 | ``` 197 | 198 | ### Use the static binaries from this repo 199 | 200 | Download and install to the bin directory of your local user (for root this may not be in the `$PATH`) 201 | 202 | Pick the platform URL you need: 203 | 204 | i386 / x86 205 | 206 | ```bash 207 | mkdir -p ~/bin && source ~/.profile 208 | wget -qO ~/bin/iperf3 https://github.com/userdocs/iperf3-static/releases/latest/download/iperf3-i386 209 | chmod 700 ~/bin/iperf3 210 | ``` 211 | 212 | amd64 213 | 214 | ```bash 215 | mkdir -p ~/bin && source ~/.profile 216 | wget -qO ~/bin/iperf3 https://github.com/userdocs/iperf3-static/releases/latest/download/iperf3-amd64 217 | chmod 700 ~/bin/iperf3 218 | ``` 219 | 220 | arm32v6 221 | 222 | ```bash 223 | mkdir -p ~/bin && source ~/.profile 224 | wget -qO ~/bin/iperf3 https://github.com/userdocs/iperf3-static/releases/latest/download/iperf3-arm32v6 225 | chmod 700 ~/bin/iperf3 226 | ``` 227 | 228 | arm32v7 229 | 230 | ```bash 231 | mkdir -p ~/bin && source ~/.profile 232 | wget -qO ~/bin/iperf3 https://github.com/userdocs/iperf3-static/releases/latest/download/iperf3-arm32v7 233 | chmod 700 ~/bin/iperf3 234 | ``` 235 | 236 | aarch64 / arm64 237 | 238 | ```bash 239 | mkdir -p ~/bin && source ~/.profile 240 | wget -qO ~/bin/iperf3 https://github.com/userdocs/iperf3-static/releases/latest/download/iperf3-arm64v8 241 | chmod 700 ~/bin/iperf3 242 | ``` 243 | 244 | ppc64le 245 | 246 | ```bash 247 | mkdir -p ~/bin && source ~/.profile 248 | wget -qO ~/bin/iperf3 https://github.com/userdocs/iperf3-static/releases/latest/download/iperf3-ppc64le 249 | chmod 700 ~/bin/iperf3 250 | ``` 251 | 252 | s390x 253 | 254 | ```bash 255 | mkdir -p ~/bin && source ~/.profile 256 | wget -qO ~/bin/iperf3 https://github.com/userdocs/iperf3-static/releases/latest/download/iperf3-s390x 257 | chmod 700 ~/bin/iperf3 258 | ``` 259 | 260 | Windows builds required being bundled with Cygwin dlls to work so these are not single static binaries. They have a directory structure like this. 261 | 262 | ``` 263 | iperf3.exe 264 | cygwin1.dll 265 | ``` 266 | 267 | Windows x64 no openssl 268 | 269 | https://github.com/userdocs/iperf3-static/releases/latest/download/iperf3-amd64-win.zip 270 | 271 | Windows x64 with openssl 272 | 273 | https://github.com/userdocs/iperf3-static/releases/latest/download/iperf3-amd64-win-openssl.zip 274 | 275 | Check the version: 276 | 277 | ``` 278 | ~/bin/iperf3 -v 279 | ``` 280 | 281 |
282 | 283 | ## MacOS amd64 and arm64 info 284 | 285 |
286 | Expand for details 287 | 288 | amd64 macos-13 intel 289 | 290 | ```bash 291 | mkdir -p ~/bin && source ~/.profile 292 | wget -qO ~/bin/iperf3 https://github.com/userdocs/iperf3-static/releases/latest/download/iperf3-amd64-osx-13 293 | chmod 700 ~/bin/iperf3 294 | ``` 295 | 296 | arm64 macos-14 apple M1 297 | 298 | ```bash 299 | mkdir -p ~/bin && source ~/.profile 300 | wget -qO ~/bin/iperf3 https://github.com/userdocs/iperf3-static/releases/latest/download/iperf3-arm64-osx-14 301 | chmod 700 ~/bin/iperf3 302 | ``` 303 | 304 |
305 | 306 | ## gh attestation verify 307 | 308 |
309 | Expand for details 310 | 311 | Binaries built from the release of `3.17.1+` use [actions/attest-build-provenance](https://github.com/actions/attest-build-provenance) 312 | 313 | Verify the integrity and provenance of an artifact using its associated cryptographically signed attestations. 314 | 315 | https://cli.github.com/manual/gh_attestation_verify 316 | 317 | For example: 318 | 319 | ```bash 320 | gh attestation verify iperf3-amd64 -o userdocs 321 | ``` 322 | 323 | Will give you this result for the `release-5.0.0_v2.0.10` revision `1` binary. 324 | 325 | ```bash 326 | Loaded digest sha256:84f9851d0647d3d618c66d64cac10ed1eb37583b3aaf3bb0baac88bf446fb10a for file://iperf3-amd64 327 | Loaded 6 attestations from GitHub API 328 | ✓ Verification succeeded! 329 | 330 | sha256:84f9851d0647d3d618c66d64cac10ed1eb37583b3aaf3bb0baac88bf446fb10a was attested by: 331 | REPO PREDICATE_TYPE WORKFLOW 332 | userdocs/iperf3-static https://slsa.dev/provenance/v1 .github/workflows/alpine_multi.yml@refs/heads/master 333 | ``` 334 | 335 |
336 | 337 | ## Virustotal scanning 338 | 339 |
340 | Expand for details 341 | 342 | All binaries and dlls are scanned by virus total and the results uploaded using this action 343 | 344 | https://github.com/crazy-max/ghaction-virustotal 345 | 346 | The results url is uploaded to the release body and you can see them here https://github.com/userdocs/iperf3-static/releases/latest 347 | 348 |
349 | 350 | ### Credits and acknowledgements 351 | 352 |
353 | Expand for details 354 | 355 | Other contributions have helped inspire the creation of a GitHub action for a Windows build and release. 356 | 357 | [www.neowin.net](https://www.neowin.net/forum/topic/1234695-iperf-313-windows-build) via [budman](https://www.neowin.net/forum/profile/14624-budman/) 358 | 359 | https://github.com/ar51an/iperf3-win-builds via [cryptanalyst](https://www.neowin.net/forum/profile/170754-cryptanalyst/) 360 | 361 |
362 | 363 | ## Forking and using this repo 364 | 365 |
366 | Expand for details 367 | 368 | Step 1: Fork the repo: https://github.com/userdocs/iperf3-static/fork 369 | 370 | Step 2: Under the repo `/settings/secrets/actions` you will need to set a the `VT_API_KEY` using your 371 | 372 | You can find it here if you have created an account: https://www.virustotal.com/gui/my-apikey 373 | 374 | Step 3: Under the Actions tab, enable workflows. The `check_new_release.yml` defaults to a scheduled check but can be run manually. 375 | 376 | https://github.com/userdocs/iperf3-static/blob/0571ce60cba18d2b67303b71d31009f83bae36c8/.github/workflows/check_new_release.yml#L11-L12 377 | 378 |
379 | 380 | ## Test Servers 381 | 382 | https://github.com/R0GGER/public-iperf3-servers?tab=readme-ov-file#servers-per-continent 383 | 384 | Linux one liner for an example output of `./iperf3 -c speedtest.ip-projects.de` for a random Europe server 385 | 386 | ```shell 387 | ./$(curl -sL https://db.iperf3serverlist.net/api/v1/db/public/shared-view/b111407c-43c4-48af-a828-301b698064a3/rows/export/csv | awk -F, 'NR>1 { print $1 }' | shuf -n1) 388 | ``` 389 | -------------------------------------------------------------------------------- /ci-cygwin-installer-packages.cmd: -------------------------------------------------------------------------------- 1 | automake,curl,gcc-core,gcc-g++,git,libtool,make,pkg-config,tar -------------------------------------------------------------------------------- /ci-cygwin-installer.cmd: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | :: Copyright 2023 by userdocs and contributors for LFTP4WIN installer derived from https://github.com/vegardit/cygwin-portable-installer 4 | :: Copyright 2017-2023 by Vegard IT GmbH (https://vegardit.com) and the cygwin-portable-installer contributors. 5 | :: 6 | :: LFTP4WIN installer derived from cygwin-portable-installer 7 | :: SPDX-FileCopyrightText: © userdocs and contributors 8 | :: SPDX-FileContributor: userdocs 9 | :: SPDX-License-Identifier: Apache-2.0 10 | :: 11 | :: cygwin-portable-installer 12 | :: SPDX-FileCopyrightText: © Vegard IT GmbH (https://vegardit.com) and contributors 13 | :: SPDX-FileContributor: Sebastian Thomschke, Vegard IT GmbH 14 | :: SPDX-License-Identifier: Apache-2.0 15 | 16 | :: ABOUT 17 | :: ===== 18 | :: LFTP4WIN installer 19 | :: 20 | :: A heavily modified and re-targeted version of this project https://github.com/vegardit/cygwin-portable-installer 21 | :: Original code has been 1: removed where not relevant 2: Modified to work with LFTP4WIN CORE 3: Unmodified where applicable. 22 | :: It installs a portable Cygwin installation to be used specifically with the https://github.com/userdocs/LFTP4WIN-CORE skeleton. 23 | :: The LFTP4WIN-CORE is applied to the Cygwin installation with minimal modification to the Cygwin environment or core files. 24 | :: This provides a a fully functional Cygwin portable platform for use with the LFTP4WIN project. 25 | :: Environment customization is no longer designed to be fully self contained and is partially provided via the LFTP4WIN-CORE 26 | :: There are still some critical configuration options available below for the installation. 27 | :: if executed with "--debug" print all executed commands 28 | for %%a in (%*) do ( 29 | if [%%~a]==[--debug] echo on 30 | ) 31 | 32 | :: ============================================================================================================ 33 | :: CONFIG CUSTOMIZATION START 34 | :: ============================================================================================================ 35 | 36 | :: You can customize the following variables to your needs before running the batch file: 37 | 38 | :: set proxy if required (unfortunately Cygwin setup.exe does not have commandline options to specify proxy user credentials) 39 | set PROXY_HOST= 40 | set PROXY_PORT=8080 41 | 42 | :: Choose a user name that will be used to configure Cygwin. This user will be a clone of the account running the installation script renamed as the setting chosen. 43 | set LFTP4WIN_USERNAME=IPERF3_BUILD 44 | 45 | :: Show the packet manager if you need to specify a program version during installation instead of using the current release (default), like openssh 7.9 instead of 8.0 for Lftp. 46 | set CYGWIN_PACKET_MANAGER= 47 | 48 | :: Packages are loaded from the packages_basic.cmd and packages_openssl.cmd. The action matrix copies the one it needs to ci-cygwin-installer-packages.cmd 49 | echo Loading package dependencies from ci-cygwin-installer-packages.cmd 50 | set /p CYGWIN_PACKAGES= "%LFTP4WIN_ROOT%\etc\fstab" 165 | 166 | :: Configure our Cygwin Environment 167 | "%LFTP4WIN_ROOT%\bin\mkgroup.exe" -c > cygwin/etc/group || goto :fail 168 | "%LFTP4WIN_ROOT%\bin\bash.exe" -c "echo ""$USERNAME:*:1001:$(cygwin/bin/mkpasswd -c | cygwin/bin/cut -d':' -f 4):$(cygwin/bin/mkpasswd -c | cygwin/bin/cut -d':' -f 5):$(cygwin/bin/cygpath.exe -u ""%~dp0""):/bin/bash""" > cygwin/etc/passwd || goto :fail 169 | :: Fix a symlink bug in Cygwin 170 | "%LFTP4WIN_ROOT%\bin\ln.exe" -fsn '../usr/share/terminfo' '/lib/terminfo' || goto :fail 171 | 172 | if "%INSTALL_LFTP4WIN_CORE%" == "yes" ( 173 | "%LFTP4WIN_ROOT%\bin\bsdtar.exe" -xmf "%INSTALL_TEMP%\lftp4win_core.zip" --strip-components=1 -C "%LFTP4WIN_BASE%\" || goto :fail 174 | "%LFTP4WIN_ROOT%\bin\touch.exe" "%LFTP4WIN_ROOT%\.core-installed" 175 | ) 176 | 177 | set Init_sh=%LFTP4WIN_ROOT%\portable-init.sh 178 | echo Creating [%Init_sh%] 179 | echo. 180 | ( 181 | echo #!/usr/bin/env bash 182 | echo. 183 | echo ## Map Current Windows User to root user 184 | echo. 185 | echo unset HISTFILE 186 | echo. 187 | echo rm -f /etc/{passwd,group} 188 | echo sed -ri "s@# db_home: (.*)@db_home: ${HOME}@" /etc/nsswitch.conf 189 | echo. 190 | echo ## Adjust the Cygwin packages cache path 191 | echo. 192 | echo pkg_cache_dir=$(cygpath -w "$LFTP4WIN_ROOT/.pkg-cache"^) 193 | echo. 194 | echo sed -ri 's#(.*^)\.pkg-cache$#'"\t${pkg_cache_dir//\\/\\\\}"'#' /etc/setup/setup.rc 195 | echo. 196 | echo set HISTFILE 197 | ) > "%Init_sh%" || goto :fail 198 | 199 | "%LFTP4WIN_ROOT%\bin\sed" -i 's/\r$//' "%Init_sh%" || goto :fail 200 | 201 | IF EXIST "%LFTP4WIN_ROOT%\etc\fstab" "%LFTP4WIN_ROOT%\bin\sed" -i 's/\r$//' "%LFTP4WIN_ROOT%\etc\fstab" 202 | 203 | IF EXIST "%LFTP4WIN_ROOT%\portable-init.sh" "%LFTP4WIN_ROOT%\bin\bash" -li "%LFTP4WIN_ROOT%\portable-init.sh" 204 | 205 | echo ########################################################### 206 | echo # Installing [LFTP4WIN Portable] succeeded. 207 | echo ########################################################### 208 | echo. 209 | 210 | del /q "%INSTALL_TEMP%\%CYGWIN_SETUP_EXE%" "%LFTP4WIN_ROOT%\Cygwin.bat" "%LFTP4WIN_ROOT%\Cygwin.ico" "%LFTP4WIN_ROOT%\Cygwin-Terminal.ico" 211 | 212 | if "%INSTALL_LFTP4WIN_CORE%" == "yes" ( 213 | DEL /Q "%LFTP4WIN_BASE%\.gitattributes" "%LFTP4WIN_BASE%\README.md" "%LFTP4WIN_BASE%\LICENSE.txt" "%INSTALL_TEMP%\lftp4win_core.zip" 214 | RMDIR /S /Q "%LFTP4WIN_BASE%\docs" 215 | ) 216 | 217 | goto :eof 218 | 219 | :fail 220 | set exit_code=%ERRORLEVEL% 221 | if exist "%DOWNLOADER%" ( 222 | del "%DOWNLOADER%" 223 | ) 224 | echo. 225 | echo ########################################################### 226 | echo # Installing [LFTP4WIN Portable] FAILED! 227 | echo ########################################################### 228 | echo. 229 | exit /B %exit_code% 230 | 231 | :download 232 | if exist "%2" ( 233 | echo Deleting existing [%2] 234 | del "%2" || goto :fail 235 | ) 236 | 237 | where /q curl 238 | if %ERRORLEVEL% EQU 0 ( 239 | call :download_with_curl "%1" "%2" 240 | ) 241 | 242 | if errorlevel 1 ( 243 | call :download_with_powershell "%1" "%2" 244 | ) 245 | 246 | if errorlevel 1 ( 247 | call :download_with_vbs "%1" "%2" || goto :fail 248 | ) 249 | 250 | exit /B 0 251 | 252 | :download_with_curl 253 | if "%PROXY_HOST%" == "" ( 254 | set "http_proxy=" 255 | set "https_proxy=" 256 | ) else ( 257 | set http_proxy=http://%PROXY_HOST%:%PROXY_PORT% 258 | set https_proxy=http://%PROXY_HOST%:%PROXY_PORT% 259 | ) 260 | echo Downloading %1 to %2 using curl 261 | curl -sL %1 -# -o %2 || exit /B 1 262 | exit /B 0 263 | 264 | :download_with_vbs 265 | :: create VB script that can download files 266 | :: not using PowerShell which may be blocked by group policies 267 | set DOWNLOADER=%INSTALL_ROOT%downloader.vbs 268 | echo Creating [%DOWNLOADER%] script 269 | if "%PROXY_HOST%" == "" ( 270 | set DOWNLOADER_PROXY=. 271 | ) else ( 272 | set DOWNLOADER_PROXY= req.SetProxy 2, "%PROXY_HOST%:%PROXY_PORT%", "" 273 | ) 274 | 275 | ( 276 | echo url = Wscript.Arguments(0^) 277 | echo target = Wscript.Arguments(1^) 278 | echo On Error Resume Next 279 | echo reqType = "WinHttp.WinHttpRequest.5.1" 280 | echo Set req = CreateObject(reqType^) 281 | echo If req Is Nothing Then 282 | echo reqType = "MSXML2.XMLHTTP.6.0" 283 | echo Set req = CreateObject(reqType^) 284 | echo End If 285 | echo WScript.Echo "Downloading '" ^& url ^& "' to '" ^& target ^& "' using '" ^& reqType ^& "'" 286 | echo%DOWNLOADER_PROXY% 287 | echo req.Open "GET", url, False 288 | echo req.Send 289 | echo If Err.Number ^<^> 0 Then 290 | echo WScript.Quit 1 291 | echo End If 292 | echo If req.Status ^<^> 200 Then 293 | echo WScript.Echo "FAILED to download: HTTP Status " ^& req.Status 294 | echo WScript.Quit 1 295 | echo End If 296 | echo Set buff = CreateObject("ADODB.Stream"^) 297 | echo buff.Open 298 | echo buff.Type = 1 299 | echo buff.Write req.ResponseBody 300 | echo buff.Position = 0 301 | echo buff.SaveToFile target 302 | echo buff.Close 303 | echo. 304 | ) >"%DOWNLOADER%" || goto :fail 305 | 306 | cscript //Nologo "%DOWNLOADER%" %1 %2 || exit /B 1 307 | del "%DOWNLOADER%" 308 | exit /B 0 309 | 310 | :download_with_powershell 311 | if "%PROXY_HOST%" == "" ( 312 | set "http_proxy=" 313 | set "https_proxy=" 314 | ) else ( 315 | set http_proxy=http://%PROXY_HOST%:%PROXY_PORT% 316 | set https_proxy=http://%PROXY_HOST%:%PROXY_PORT% 317 | ) 318 | echo Downloading %1 to %2 using powershell 319 | powershell "[Net.ServicePointManager]::SecurityProtocol = 'tls12, tls11, tls'; (New-Object Net.WebClient).DownloadFile('%1', '%2')" || exit /B 1 320 | exit /B 0 321 | -------------------------------------------------------------------------------- /ci-linux-crossbuild.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # A very simple script to cross-compile iperf3 with openssl for variety of targets using ghcr.io/userdocs/qbt-musl-cross-make docker images 4 | # 5 | # Example - to cross-compile iperf3 for aarch64-linux-musl save the script in ~/iperf3 then use the following command: 6 | # 7 | # docker run -it -w /home/gh -v ~/iperf3:/home/gh ghcr.io/userdocs/qbt-musl-cross-make:aarch64-linux-musl /bin/bash crossbuild.sh 8 | 9 | github_repo="${1:-"https://github.com/esnet/iperf.git"}" 10 | github_branch="${2:-"master"}" 11 | crossbuild_target="${3:-${CC/-gcc/}}" 12 | arch="${4:-x86_64}" 13 | 14 | printf '\n%s\n' "Building iperf3 for $crossbuild_target" 15 | printf '%s\n\n' "repo: $github_repo branch:$github_branch" 16 | 17 | sudo apk update 18 | 19 | CXXFLAGS="--static -static -I/home/gh/local/include" 20 | LDFLAGS="--static -static -L/home/gh/local/lib" 21 | 22 | cd || exit 23 | mkdir -p /home/gh/local 24 | 25 | repo="$(cat /etc/apk/repositories | sed -rn 's|https://dl-cdn.alpinelinux.org/alpine/(.*)/(.*)|\1|p' | head -1)" 26 | openssl_libs_static="$(apk info openssl-libs-static | head -1 | awk '{ print $1 }')" 27 | openssl_dev="$(apk info openssl-dev | head -1 | awk '{ print $1 }')" 28 | 29 | curl -sLO "https://dl-cdn.alpinelinux.org/alpine/${repo}/main/${arch}/${openssl_dev}.apk" 30 | curl -sLO "https://dl-cdn.alpinelinux.org/alpine/${repo}/main/${arch}/${openssl_libs_static}.apk" 31 | tar -xzf "${openssl_dev}.apk" --strip-components=1 -C /home/gh/local 32 | tar -xzf "${openssl_libs_static}.apk" --strip-components=1 -C /home/gh/local 33 | 34 | rm -rf /home/gh/iperf3 35 | git clone --no-tags --single-branch --branch "${github_branch}" --shallow-submodules --recurse-submodules -j"$(nproc)" --depth 1 "${github_repo}" /home/gh/iperf3 36 | cd /home/gh/iperf3 || exit 37 | 38 | ./configure --with-openssl="/home/gh/local" --disable-shared --enable-static-bin --prefix="/home/gh/local" 39 | make -j$(nproc) 40 | make install 41 | -------------------------------------------------------------------------------- /ci-release-body.md: -------------------------------------------------------------------------------- 1 | ## Software provenance 2 | 3 | > [!NOTE] 4 | > These release assets were transparently built for easy verification of their provenance. 5 | 6 | Using GitHub actions and workflows, binaries are verified using GitHub attestation and VirusTotal scanning, at build time, so that you can be certain the release assets you are using were transparently built from the source code. 7 | 8 | - GitHub attestation will show where when and how the binary was built - [example](https://github.com/userdocs/iperf3-static/attestations/2474371) 9 | - VirusTotal scanning will show the binary is malware free before release - [example](https://www.virustotal.com/gui/file/42647b55aae08c3b581e78e1a6bcadf2c7715d4edfc2c842ecbb194b0b47b084) 10 | 11 | > [!TIP] 12 | > The sha256sum of the GitHub attestations and VirusTotal scan should be the same for any release assets. 13 | 14 | ## GitHub artifact-attestations 15 | 16 |
17 | Expand for details 18 | 19 | Binaries built from the release of `3.17.1+` use [actions/attest-build-provenance](https://github.com/actions/attest-build-provenance) - [Github Docs](https://docs.github.com/en/actions/security-for-github-actions/using-artifact-attestations/using-artifact-attestations-to-establish-provenance-for-builds#verifying-artifact-attestations-with-the-github-cli) 20 | 21 | For example: using `gh` cli - [manual](https://cli.github.com/manual/gh_attestation_verify) 22 | 23 | ```bash 24 | gh attestation verify iperf3-amd64 -o userdocs 25 | ``` 26 | 27 |
28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | ## VirusTotal scan results 36 | 37 |
38 | Expand for details 39 | 40 | Links to scan results 41 | 42 | [iperf3-amd64]() 43 | 44 | [iperf3-amd64-win]() 45 | 46 | [iperf3-amd64-win-openssl]() 47 | 48 | [iperf3-amd64-osx-13]() 49 | 50 | [iperf3-arm64-osx-14]() 51 | 52 | [iperf3-arm32v6]() 53 | 54 | [iperf3-arm32v7]() 55 | 56 | [iperf3-arm64v8]() 57 | 58 | [iperf3-i386]() 59 | 60 | [iperf3-ppc64le]() 61 | 62 | [iperf3-riscv64]() 63 | 64 | [iperf3-s390x]() 65 | 66 |
67 | -------------------------------------------------------------------------------- /ci-windows-cygwin-build.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | HOME="$(pwd)" 4 | with_openssl="${1:-no}" 5 | if [[ "${2}" =~ ^/ ]]; then 6 | cygwin_path="${2}" 7 | else 8 | cygwin_path="${HOME}/${2:-cygwin}" 9 | fi 10 | source_repo="${3:-https://github.com/esnet/iperf.git}" 11 | source_branch="${4:-master}" 12 | 13 | printf '\n%b\n' " \e[93m\U25cf\e[0m With openssl = ${with_openssl}" 14 | printf '%b\n' " \e[93m\U25cf\e[0m Build path = ${HOME}" 15 | printf '%b\n' " \e[93m\U25cf\e[0m Cygwin path = ${cygwin_path}" 16 | 17 | printf '\n%b\n' " \e[93m\U25cf\e[0m parameters = ${*}" 18 | 19 | printf '\n%b\n' " \e[93m\U25cf\e[0m with_openssl = ${with_openssl}" 20 | printf '\n%b\n' " \e[93m\U25cf\e[0m cygwin_path = ${cygwin_path}" 21 | printf '\n%b\n' " \e[93m\U25cf\e[0m source_repo = ${source_repo}" 22 | printf '\n%b\n' " \e[93m\U25cf\e[0m source_branch = ${source_branch}" 23 | 24 | if [[ "${with_openssl}" == 'yes' ]]; then 25 | printf '\n%b\n' " \e[94m\U25cf\e[0m Downloading zlib" 26 | curl -sLO "https://github.com/userdocs/qbt-workflow-files/releases/latest/download/zlib.tar.xz" 27 | 28 | openssl_version="$(git ls-remote -q -t --refs "https://github.com/openssl/openssl.git" | awk '/openssl-3\.1\./{sub("refs/tags/", "");sub("(.*)(v6|rc|alpha|beta)(.*)", ""); print $2 }' | awk '!/^$/' | sort -rV | head -n1)" 29 | 30 | printf '\n%b\n' " \e[94m\U25cf\e[0m Downloading openssl ${openssl_version}" 31 | curl -sLO "https://github.com/openssl/openssl/releases/download/${openssl_version}/${openssl_version}.tar.gz" 32 | 33 | printf '\n%b\n' " \e[94m\U25cf\e[0m Extracting zlib" 34 | rm -rf "zlib" && tar xf "zlib.tar.xz" 35 | 36 | printf '\n%b\n' " \e[94m\U25cf\e[0m Extracting openssl" 37 | rm -rf "openssl" && mkdir -p "openssl" 38 | tar xf "${openssl_version}.tar.gz" --strip-components=1 -C "openssl" 39 | 40 | printf '\n%b\n\n' " \e[94m\U25cf\e[0m Configuring zlib" 41 | pushd "zlib" || exit 1 42 | ./configure --prefix="${cygwin_path}" --static --zlib-compat 43 | 44 | printf '\n%b\n\n' " \e[94m\U25cf\e[0m Building with zlib" 45 | make -j"$(nproc)" 46 | make install 47 | 48 | popd || exit 1 49 | 50 | printf '\n%b\n\n' " \e[94m\U25cf\e[0m Configuring openssl" 51 | pushd "${HOME}/openssl" || exit 1 52 | ./config --prefix="${cygwin_path}" --libdir=lib threads no-shared no-dso no-comp 53 | 54 | printf '\n%b\n\n' " \e[94m\U25cf\e[0m Building openssl" 55 | make -j"$(nproc)" 56 | make install_sw 57 | 58 | popd || exit 1 59 | fi 60 | 61 | printf '\n%b\n\n' " \e[94m\U25cf\e[0m Cloning iperf3 git repo" 62 | 63 | [[ -d "$HOME/iperf3_build" ]] && rm -rf "$HOME/iperf3_build" 64 | printf '\n%b\n\n' " \e[94m\U25cf\e[0m git clone --no-tags --single-branch --branch ${source_branch} --shallow-submodules --recurse-submodules -j$(nproc) --depth 1 ${source_repo} $HOME/iperf3_build" 65 | git clone --no-tags --single-branch --branch "${source_branch}" --shallow-submodules --recurse-submodules -j"$(nproc)" --depth 1 "${source_repo}" "$HOME/iperf3_build" 66 | cd "$HOME/iperf3_build" || exit 1 67 | 68 | printf '\n%b\n\n' " \e[94m\U25cf\e[0m Repo Info" 69 | 70 | git remote show origin 71 | 72 | printf '\n%b\n' " \e[92m\U25cf\e[0m Setting iperf3 version to file iperf3_version" 73 | sed -rn 's|(.*)\[(.*)],\[https://github.com/esnet/iperf],(.*)|\2|p' configure.ac > "$HOME/iperf3_version" 74 | 75 | printf '\n%b\n\n' " \e[94m\U25cf\e[0m Bootstrapping iperf3" 76 | 77 | ./bootstrap.sh 78 | 79 | printf '\n%b\n\n' " \e[94m\U25cf\e[0m Configuring iperf3" 80 | ./configure --disable-shared --enable-static --enable-static-bin --prefix="$HOME/iperf3" 81 | 82 | printf '\n%b\n\n' " \e[94m\U25cf\e[0m make" 83 | make -j"$(nproc)" 84 | 85 | printf '\n%b\n\n' " \e[94m\U25cf\e[0m make install" 86 | [[ -d "$HOME/iperf3" ]] && rm -rf "$HOME/iperf3" 87 | make install 88 | 89 | if [[ -d "$HOME/iperf3/bin" ]]; then 90 | printf '\n%b\n' " \e[94m\U25cf\e[0m Copy dll dependencies" 91 | [[ -f "${cygwin_path}/bin/cygwin1.dll" ]] && cp -f "${cygwin_path}/bin/cygwin1.dll" "$HOME/iperf3/bin" 92 | printf '\n%b\n' " \e[92m\U25cf\e[0m Copied the dll dependencies" 93 | fi 94 | -------------------------------------------------------------------------------- /pwsh-here.cmd: -------------------------------------------------------------------------------- 1 | powershell.exe -noexit -command Set-Location -literalPath "%~dp0." -------------------------------------------------------------------------------- /zizmor.yml: -------------------------------------------------------------------------------- 1 | rules: 2 | unpinned-uses: # https://woodruffw.github.io/zizmor/audits/#unpinned-uses 3 | config: 4 | policies: 5 | "*": ref-pin 6 | --------------------------------------------------------------------------------