Skip to content

Commit

Permalink
Add cross compilation support (#85)
Browse files Browse the repository at this point in the history
Add support for cross-compiling curl-impersonate.

Cross compiling can now be done using the '--host' flag to the configure
script. This will make sure that all sub-components are cross-compiled.
In addition, compiling for a different system requires explicitly
specifying multiple paths used by curl (e.g. for certificates). These
options were added to the configure script as well.

The build and test CI workflow will now attempt to cross-compile
curl-impersonate to ARM64 (aarch64), and upload this binary to the
GitHub release page.

Add the 'configure' script generated by autoconf and its dependencies to
the repository to save the users from having to run 'autoconf' manually.
  • Loading branch information
lwthiker committed Jul 14, 2022
1 parent 6572db8 commit 72f30c9
Show file tree
Hide file tree
Showing 8 changed files with 9,539 additions and 87 deletions.
88 changes: 75 additions & 13 deletions .github/workflows/build-and-test-make.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,23 @@ jobs:
strategy:
matrix:
os: [ubuntu-20.04, macos-11]
arch: [x86_64]
include:
- os: ubuntu-20.04
arch: x86_64
host: x86_64-linux-gnu
capture_interface: eth0
make: make
- os: ubuntu-20.04
arch: aarch64
host: aarch64-linux-gnu
capture_interface: eth0
make: make
release_name: x86_64-linux-gnu
- os: macos-11
arch: x86_64
host: x86_64-macos
capture_interface: en0
make: gmake
release_name: x86_64-macos
steps:
- uses: actions/setup-python@v3

Expand All @@ -45,6 +53,11 @@ jobs:
# More dependencies for the tests
sudo apt-get install tcpdump nghttp2-server libnss3
- name: Install Ubuntu dependencies (aarch64)
if: matrix.arch == 'aarch64'
run: |
sudo apt-get install gcc-aarch64-linux-gnu g++-aarch64-linux-gnu
- name: Install macOS dependencies
if: matrix.os == 'macos-11'
run: |
Expand All @@ -69,12 +82,38 @@ jobs:
run: |
pip3 install -r tests/requirements.txt
# When cross compiling we need to build zlib first.
- name: Build zlib
run: |
curl -LO https://zlib.net/zlib-1.2.12.tar.gz
tar xf zlib-1.2.12.tar.gz
cd zlib-1.2.12
CHOST=${{ matrix.host }} ./configure --prefix=${{ runner.temp }}/zlib
make
make install
# Make sure curl will link with libz.so.1 and not libz.so
rm -f ${{ runner.temp }}/zlib/lib/libz.so
- name: Run configure script
if: matrix.arch == 'x86_64'
run: |
autoconf
mkdir ${{ runner.temp }}/install
./configure --prefix=${{ runner.temp }}/install
# When cross compiling a more complicated configuration is needed, since
# curl's configure script can't figure out where some files and libraries
# are located. The locations used here are the ones used by Ubuntu.
- name: Run configure script (cross compiling)
if: matrix.arch != 'x86_64'
run: |
mkdir ${{ runner.temp }}/install
./configure --prefix=${{ runner.temp }}/install \
--host=${{ matrix.host }} \
--with-zlib=${{ runner.temp }}/zlib \
--with-ca-path=/etc/ssl/certs \
--with-ca-bundle=/etc/ssl/certs/ca-certificates.crt \
--with-libnssckbi=/usr/lib/${{ matrix.host }}/nss
# Cache the build of BoringSSL, which is the longest part of the build
# We must cache the .zip as well, otherwise the Makefile will
# rebuild BoringSSL. This whole thing is a bit hacky, but necessary to
Expand All @@ -83,14 +122,14 @@ jobs:
uses: actions/cache@v3
with:
path: boringssl.zip
key: ${{ runner.os }}-boring-source-${{ env.BORING_SSL_COMMIT }}
key: ${{ runner.os }}-${{ matrix.arch }}-boring-source-${{ env.BORING_SSL_COMMIT }}

- name: Cache BoringSSL build
id: cache-boringssl
uses: actions/cache@v3
with:
path: boringssl/build
key: ${{ runner.os }}-boring-build-${{ env.BORING_SSL_COMMIT }}-${{ hashFiles('chrome/patches/boringssl*.patch') }}
key: ${{ runner.os }}-${{ matrix.arch }}-boring-build-${{ env.BORING_SSL_COMMIT }}-${{ hashFiles('chrome/patches/boringssl*.patch') }}

# Trick the Makefile into skipping the BoringSSL build step
# if it was found in the cache. See Makefile.in
Expand All @@ -114,14 +153,14 @@ jobs:
uses: actions/cache@v3
with:
path: ${{ env.NSS_VERSION }}.tar.gz
key: ${{ runner.os }}-nss-source-${{ env.NSS_VERSION }}
key: ${{ runner.os }}-${{ matrix.arch }}-nss-source-${{ env.NSS_VERSION }}

- name: Cache NSS build
id: cache-nss
uses: actions/cache@v3
with:
path: ${{ env.NSS_VERSION }}/dist
key: ${{ runner.os }}-nss-build-${{ env.NSS_VERSION }}
key: ${{ runner.os }}-${{ matrix.arch }}-nss-build-${{ env.NSS_VERSION }}

# Trick the Makefile into skipping the NSS build step
# if it was found in the cache.
Expand All @@ -138,11 +177,15 @@ jobs:
${{ matrix.make }} firefox-install
- name: Prepare the tests
if: matrix.arch == 'x86_64'
run: |
# Compile 'minicurl' which is used by the tests
gcc -Wall -Werror -o ${{ runner.temp }}/install/bin/minicurl tests/minicurl.c `curl-config --libs`
# For now we can only run the tests when not cross compiling, since the
# tests run the curl-impersonate binary locally.
- name: Run the tests
if: matrix.arch == 'x86_64'
run: |
cd tests
# sudo is needed for capturing packets
Expand All @@ -154,18 +197,37 @@ jobs:
if: startsWith(github.ref, 'refs/tags/')
run: |
cd ${{ runner.temp }}/install/lib
tar -c -z -f ${{ runner.temp }}/libcurl-impersonate-${{ github.ref_name }}.${{ matrix.release_name }}.tar.gz libcurl-impersonate*
echo "release_file_lib=${{ runner.temp }}/libcurl-impersonate-${{ github.ref_name }}.${{ matrix.release_name }}.tar.gz" >> $GITHUB_ENV
tar -c -z -f ${{ runner.temp }}/libcurl-impersonate-${{ github.ref_name }}.${{ matrix.host }}.tar.gz libcurl-impersonate*
echo "release_file_lib=${{ runner.temp }}/libcurl-impersonate-${{ github.ref_name }}.${{ matrix.host }}.tar.gz" >> $GITHUB_ENV
# Recompile curl-impersonate statically.
- name: Recompile statically
- name: Clean build
if: startsWith(github.ref, 'refs/tags/')
run: |
${{ matrix.make }} chrome-clean
${{ matrix.make }} firefox-clean
rm -Rf ${{ runner.temp }}/install
mkdir ${{ runner.temp }}/install
# Recompile curl-impersonate statically when doing a release.
- name: Reconfigure statically
if: startsWith(github.ref, 'refs/tags/') && matrix.arch == 'x86_64'
run: |
./configure --prefix=${{ runner.temp }}/install --enable-static
- name: Reconfigure statically (cross compiling)
if: startsWith(github.ref, 'refs/tags/') && matrix.arch != 'x86_64'
run: |
./configure --prefix=${{ runner.temp }}/install \
--enable-static \
--host=${{ matrix.host }} \
--with-zlib=${{ runner.temp }}/zlib \
--with-ca-path=/etc/ssl/certs \
--with-ca-bundle=/etc/ssl/certs/ca-certificates.crt \
--with-libnssckbi=/usr/lib/${{ matrix.host }}/nss
- name: Rebuild statically
if: startsWith(github.ref, 'refs/tags/')
run: |
${{ matrix.make }} chrome-build
${{ matrix.make }} chrome-checkbuild
${{ matrix.make }} chrome-install-strip
Expand All @@ -177,8 +239,8 @@ jobs:
if: startsWith(github.ref, 'refs/tags/')
run: |
cd ${{ runner.temp }}/install/bin
tar -c -z -f ${{ runner.temp }}/curl-impersonate-${{ github.ref_name }}.${{ matrix.release_name }}.tar.gz curl-impersonate-ff curl-impersonate-chrome curl_*
echo "release_file_bin=${{ runner.temp }}/curl-impersonate-${{ github.ref_name }}.${{ matrix.release_name }}.tar.gz" >> $GITHUB_ENV
tar -c -z -f ${{ runner.temp }}/curl-impersonate-${{ github.ref_name }}.${{ matrix.host }}.tar.gz curl-impersonate-ff curl-impersonate-chrome curl_*
echo "release_file_bin=${{ runner.temp }}/curl-impersonate-${{ github.ref_name }}.${{ matrix.host }}.tar.gz" >> $GITHUB_ENV
- name: Upload release files
uses: softprops/action-gh-release@v1
Expand Down
43 changes: 30 additions & 13 deletions INSTALL.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@

This guide shows how to compile and install curl-impersonate and libcurl-impersonate from source.
The build process takes care of downloading dependencies, patching them, compiling them and finally compiling curl itself with the needed patches.
There are currently two build options depending on your use case:
* Native build using Makefile
* Docker container build
There are currently three build options depending on your use case:
* [Native build](#Native-build) using an autotools-based Makefile
* [Cross compiling](#Cross-compiling) using an autotools-based Makefile
* [Docker container build](#Docker-build)

There are two versions of `curl-impersonate` for technical reasons. The **chrome** version is used to impersonate Chrome, Edge and Safari. The **firefox** version is used to impersonate Firefox.

Expand All @@ -29,11 +30,6 @@ git clone https://github.com/lwthiker/curl-impersonate.git
cd curl-impersonate
```

Generate the configure script:
```
autoconf
```

Configure and compile:
```
mkdir build && cd build
Expand Down Expand Up @@ -102,11 +98,6 @@ pip3 install gyp-next
brew install go
```

Generate the configure script:
```
autoconf
```

Configure and compile:
```
mkdir build && cd build
Expand Down Expand Up @@ -135,6 +126,32 @@ Make sure that NSS is installed (see above).
If the issue persists it might be that NSS is installed in a non-standard location on your system.
Please open an issue in that case.

## Cross compiling

There is some basic support for cross compiling curl-impersonate.
It is currently being used to build curl-impersonate for ARM64 (aarch64) systems from x86-64 systems.
Cross compiling is similar to the usual build but a bit trickier:
* You'd have to build zlib for the target architecture so that curl can link with it.
* Some paths have to be specified manually since curl's own build system can't determine their location.

An example build for aarch64 on Ubuntu x86_64:
```
sudo apt-get install gcc-aarch64-linux-gnu g++-aarch64-linux-gnu
./configure --host=aarch64-linux-gnu \
--with-zlib=/path/to/compiled/zlib \
--with-ca-path=/etc/ssl/certs \
--with-ca-bundle=/etc/ssl/certs/ca-certificates.crt \
--with-libnssckbi=/usr/lib/aarch64-linux-gnu/nss
make chrome-build
make firefox-build
```
The flags mean as follows:
`--with-zlib` is the location of a compiled zlib library for the target architecture.
`--with-ca-path` and `--with-ca-bundle` will be passed to curl's configure script as is.
`--with-libnssckbi` indicates the location of libnssckbi.so on the target system. This file contains the certificates needed by curl. This must be supplied if NSS is not installed in a standard location (i.e. not in `/usr/lib`).

## Docker build
The Docker build is a bit more reproducible and serves as the reference implementation. It creates a Debian-based Docker image with the binaries.

Expand Down
Loading

0 comments on commit 72f30c9

Please sign in to comment.