mirror of
https://github.com/3proxy/3proxy.git
synced 2026-10-17 08:55:49 +08:00
Compare commits
36 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
371d8396b4 | ||
|
|
0f720bb44d | ||
|
|
3feb6df00d | ||
|
|
7e0ee5bace | ||
|
|
be619898c6 | ||
|
|
9d0dcaf63f | ||
|
|
a07665c01f | ||
|
|
3bd7cee5b7 | ||
|
|
b61ae3feac | ||
|
|
e6efa331b5 | ||
|
|
dd45805fce | ||
|
|
661631138a | ||
|
|
3422f780bf | ||
|
|
0df93bfab7 | ||
|
|
36979639b7 | ||
|
|
a11427afe9 | ||
|
|
d281b69209 | ||
|
|
a4ac85efc5 | ||
|
|
754ba7115a | ||
|
|
ff77d222e4 | ||
|
|
da99424eac | ||
|
|
95eb9f2a9f | ||
|
|
8fba7ffc40 | ||
|
|
b19e310956 | ||
|
|
34722c031f | ||
|
|
6c9c4d51aa | ||
|
|
a3605b8289 | ||
|
|
39bc8b065c | ||
|
|
63cc737b62 | ||
|
|
aeee37998e | ||
|
|
a830104238 | ||
|
|
b5e75daee4 | ||
|
|
db2f57fdd2 | ||
|
|
d53fdbc536 | ||
|
|
3dfd9052be | ||
|
|
8e2732b323 |
139
.github/workflows/build-ipk.yml
vendored
Normal file
139
.github/workflows/build-ipk.yml
vendored
Normal file
@ -0,0 +1,139 @@
|
||||
name: OpenWrt ipk build
|
||||
|
||||
on:
|
||||
release:
|
||||
types: [published]
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
env:
|
||||
OPENWRT_RELEASE: 24.10.0
|
||||
|
||||
jobs:
|
||||
ipk:
|
||||
permissions:
|
||||
contents: write
|
||||
id-token: write
|
||||
attestations: write
|
||||
name: "${{ matrix.arch }}"
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- target: ramips/mt7621
|
||||
arch: mipsel_24kc
|
||||
- target: ath79/generic
|
||||
arch: mips_24kc
|
||||
- target: ipq40xx/generic
|
||||
arch: arm_cortex-a7_neon-vfpv4
|
||||
- target: mediatek/filogic
|
||||
arch: aarch64_cortex-a53
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
|
||||
- name: env
|
||||
run: echo "RELEASE=$(tr -d ' \t\r\n' < RELEASE)" >> $GITHUB_ENV
|
||||
|
||||
- name: Install build dependencies
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y build-essential libncurses-dev zlib1g-dev gawk git \
|
||||
gettext libssl-dev xsltproc wget unzip python3 rsync file zstd
|
||||
|
||||
- name: Fetch SDK
|
||||
run: |
|
||||
BASE="https://downloads.openwrt.org/releases/$OPENWRT_RELEASE/targets/${{ matrix.target }}"
|
||||
# The SDK file name carries the toolchain flavour, which differs between
|
||||
# targets (musl vs musl_eabi), so take it from the directory listing.
|
||||
NAME=$(curl -fsSL "$BASE/" | grep -oE 'openwrt-sdk-[^"]*\.tar\.zst' | head -1)
|
||||
if [ -z "$NAME" ]; then echo "no SDK for ${{ matrix.target }}"; exit 1; fi
|
||||
echo "fetching $NAME"
|
||||
curl -fsSL "$BASE/$NAME" -o sdk.tar.zst
|
||||
tar --zstd -xf sdk.tar.zst
|
||||
mv "${NAME%.tar.zst}" sdk
|
||||
rm sdk.tar.zst
|
||||
|
||||
- name: Stage the package
|
||||
run: |
|
||||
mkdir -p sdk/package/3proxy sdk/dl
|
||||
cp -a scripts/openwrt/. sdk/package/3proxy/
|
||||
# Build the checkout rather than a published tarball, so the workflow
|
||||
# does not depend on the release archive existing yet.
|
||||
git archive --format=tar.gz --prefix="3proxy-$RELEASE/" -o "sdk/dl/3proxy-$RELEASE.tar.gz" HEAD
|
||||
HASH=$(sha256sum "sdk/dl/3proxy-$RELEASE.tar.gz" | cut -d' ' -f1)
|
||||
sed -i "s|^PKG_VERSION:=.*|PKG_VERSION:=$RELEASE|" sdk/package/3proxy/Makefile
|
||||
sed -i "s|^PKG_HASH:=.*|PKG_HASH:=$HASH|" sdk/package/3proxy/Makefile
|
||||
|
||||
- name: Build
|
||||
run: |
|
||||
cd sdk
|
||||
./scripts/feeds update base packages
|
||||
./scripts/feeds install libopenssl libpcre2
|
||||
echo CONFIG_PACKAGE_3proxy=m >> .config
|
||||
make defconfig
|
||||
make package/3proxy/compile -j$(nproc)
|
||||
|
||||
- name: Collect
|
||||
run: |
|
||||
find sdk/bin -name '3proxy_*.ipk' -exec cp {} . \;
|
||||
ls -l *.ipk
|
||||
for f in *.ipk; do echo "$f"; done
|
||||
|
||||
- name: Get artifact ipk
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: "3proxy-${{ env.RELEASE }}-${{ matrix.arch }}.ipk"
|
||||
path: "*.ipk"
|
||||
|
||||
- name: Import signing key
|
||||
if: github.event_name == 'release'
|
||||
env:
|
||||
GPG_PRIVATE_KEY: ${{ secrets.GPG_PRIVATE_KEY }}
|
||||
GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }}
|
||||
run: |
|
||||
if [ -z "$GPG_PRIVATE_KEY" ]; then echo "GPG_PRIVATE_KEY is not set"; exit 1; fi
|
||||
mkdir -p ~/.gnupg && chmod 700 ~/.gnupg
|
||||
printf 'allow-loopback-pinentry\ndefault-cache-ttl 7200\nmax-cache-ttl 7200\n' > ~/.gnupg/gpg-agent.conf
|
||||
gpgconf --kill gpg-agent || true
|
||||
printf '%s' "$GPG_PRIVATE_KEY" | gpg --batch --import
|
||||
KEYID=$(gpg --list-secret-keys --with-colons | awk -F: '/^sec:/{print $5; exit}')
|
||||
echo "GPG_KEYID=$KEYID" >> $GITHUB_ENV
|
||||
echo prime > /tmp/prime.txt
|
||||
gpg --batch --yes --pinentry-mode loopback --passphrase "$GPG_PASSPHRASE" \
|
||||
-u "$KEYID" --detach-sign -o /dev/null /tmp/prime.txt
|
||||
rm -f /tmp/prime.txt
|
||||
|
||||
- name: Checksums and detached signatures
|
||||
if: github.event_name == 'release'
|
||||
env:
|
||||
GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }}
|
||||
run: |
|
||||
# opkg verifies the signature of a feed index, never of a package file,
|
||||
# so the checksums and their signature are what a manual install can be
|
||||
# checked against.
|
||||
sha256sum *.ipk > SHA256SUMS-openwrt-${{ matrix.arch }}
|
||||
for f in *.ipk SHA256SUMS-openwrt-${{ matrix.arch }}; do
|
||||
gpg --batch --yes --pinentry-mode loopback --passphrase "$GPG_PASSPHRASE" \
|
||||
-u "$GPG_KEYID" --armor --detach-sign "$f"
|
||||
done
|
||||
sha256sum -c SHA256SUMS-openwrt-${{ matrix.arch }}
|
||||
gpg --verify SHA256SUMS-openwrt-${{ matrix.arch }}.asc SHA256SUMS-openwrt-${{ matrix.arch }}
|
||||
|
||||
- name: Attest build provenance
|
||||
if: github.event_name == 'release'
|
||||
uses: actions/attest-build-provenance@v2
|
||||
with:
|
||||
subject-path: |
|
||||
*.ipk
|
||||
|
||||
- name: Upload to release
|
||||
if: github.event_name == 'release'
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
TAG: ${{ github.event.release.tag_name }}
|
||||
run: |
|
||||
gh release upload "$TAG" *.ipk *.ipk.asc \
|
||||
SHA256SUMS-openwrt-${{ matrix.arch }} SHA256SUMS-openwrt-${{ matrix.arch }}.asc
|
||||
153
.github/workflows/build-rpm-arm64.yml
vendored
153
.github/workflows/build-rpm-arm64.yml
vendored
@ -6,10 +6,14 @@ on:
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
ci:
|
||||
permissions:
|
||||
contents: write
|
||||
id-token: write
|
||||
attestations: write
|
||||
name: "${{ matrix.target }}"
|
||||
strategy:
|
||||
matrix:
|
||||
@ -22,7 +26,11 @@ jobs:
|
||||
run: |
|
||||
pwd
|
||||
echo "RELEASE=$(cat RELEASE)" >> $GITHUB_ENV
|
||||
echo "VERSION=$(date +%y%m%d%H%M%S)" >> $GITHUB_ENV
|
||||
BUILDDATE=$(sed -n 's/^#define BUILDDATE "\(.*\)"$/\1/p' src/version.h)
|
||||
[ -n "$BUILDDATE" ] || BUILDDATE=$(date -u +%y%m%d%H%M%S)
|
||||
echo "VERSION=$BUILDDATE" >> $GITHUB_ENV
|
||||
SOURCE_DATE_EPOCH=$(date -u -d "20${BUILDDATE:0:2}-${BUILDDATE:2:2}-${BUILDDATE:4:2} ${BUILDDATE:6:2}:${BUILDDATE:8:2}:${BUILDDATE:10:2}" +%s)
|
||||
echo "SOURCE_DATE_EPOCH=$SOURCE_DATE_EPOCH" >> $GITHUB_ENV
|
||||
- name: echo env
|
||||
run: echo "release $RELEASE version $VERSION"
|
||||
- name: Linux libraries
|
||||
@ -39,45 +47,142 @@ jobs:
|
||||
cp ~/rpmbuild/SOURCES/3proxy-$RELEASE.tar.gz ~/debian/3proxy_$RELEASE.orig.tar.gz
|
||||
- name: rpmbuild
|
||||
run: |
|
||||
ret=`pwd`
|
||||
mkdir -p rpmout
|
||||
for EL in 8 9 10; do
|
||||
docker run --rm \
|
||||
-v "$HOME/rpmbuild/SOURCES/3proxy-$RELEASE.tar.gz:/src.tar.gz:ro" \
|
||||
-v "$PWD/scripts/rh/3proxy.spec:/3proxy.spec:ro" \
|
||||
-v "$PWD/rpmout:/out" \
|
||||
-e RELEASE="$RELEASE" -e HOSTUID="$(id -u)" -e HOSTGID="$(id -g)" \
|
||||
-e SOURCE_DATE_EPOCH="$SOURCE_DATE_EPOCH" \
|
||||
"almalinux:$EL" bash -c '
|
||||
set -e
|
||||
dnf -y install rpm-build gcc make openssl-devel pcre2-devel pam-devel tar gzip
|
||||
mkdir -p ~/rpmbuild/{BUILD,RPMS,SOURCES,SPECS,SRPMS}
|
||||
cp /src.tar.gz ~/rpmbuild/SOURCES/3proxy-$RELEASE.tar.gz
|
||||
ln -sf ~/rpmbuild/SOURCES/3proxy-$RELEASE.tar.gz ~/rpmbuild/SOURCES/$RELEASE.tar.gz
|
||||
cp /3proxy.spec ~/rpmbuild/SPECS/3proxy-$RELEASE.spec
|
||||
cd ~/rpmbuild/SPECS
|
||||
rpmbuild -ba 3proxy-$RELEASE.spec
|
||||
cd $ret
|
||||
mv ~/rpmbuild/RPMS/aarch64/3proxy-$RELEASE-1.aarch64.rpm 3proxy-$RELEASE.arm64.rpm
|
||||
rpmbuild -ba \
|
||||
--define "use_source_date_epoch_as_buildtime 1" \
|
||||
--define "clamp_mtime_to_source_date_epoch 1" \
|
||||
--define "_buildhost 3proxy.org" \
|
||||
3proxy-$RELEASE.spec
|
||||
cp ~/rpmbuild/RPMS/*/*.rpm /out/
|
||||
chown "$HOSTUID:$HOSTGID" /out/*.rpm || chmod 0666 /out/*.rpm'
|
||||
done
|
||||
for f in rpmout/*.rpm; do
|
||||
dist=$(rpm -qp --qf '%{RELEASE}' "$f" | sed 's/^1\.//')
|
||||
arch=$(rpm -qp --qf '%{ARCH}' "$f")
|
||||
mv "$f" "3proxy-$RELEASE.$dist.$arch.rpm"
|
||||
done
|
||||
rmdir rpmout
|
||||
ls -l *.rpm
|
||||
- name: Get artifact rpm
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: "3proxy-${{ env.RELEASE }}-arm64.rpm"
|
||||
path: "*.rpm"
|
||||
- name: Upload rpm to release
|
||||
if: github.event_name == 'release'
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
TAG: ${{ github.event.release.tag_name }}
|
||||
run: gh release upload "$TAG" 3proxy-${{ env.RELEASE }}.arm64.rpm
|
||||
- name: debbuild
|
||||
run: |
|
||||
ret=`pwd`
|
||||
cd ~/debian/
|
||||
docker run --rm \
|
||||
-v "$HOME/debian:/debian" \
|
||||
-e RELEASE="$RELEASE" -e VERSION="$VERSION" \
|
||||
-e SOURCE_DATE_EPOCH="$SOURCE_DATE_EPOCH" \
|
||||
ubuntu:22.04 bash -c '
|
||||
set -e
|
||||
export DEBIAN_FRONTEND=noninteractive
|
||||
apt-get update
|
||||
apt-get install -y build-essential debhelper fakeroot libssl-dev libpcre2-dev libpam0g-dev
|
||||
cd /debian
|
||||
tar xzf 3proxy_$RELEASE.orig.tar.gz
|
||||
cd 3proxy-$RELEASE
|
||||
echo "3proxy ($RELEASE-$VERSION) buster; urgency=medium" >debian/changelog
|
||||
echo " " >>debian/changelog
|
||||
echo " *3proxy $RELEASE build" >>debian/changelog
|
||||
echo " " >>debian/changelog
|
||||
echo " -- z3APA3A <3apa3a@3proxy.org> "`date "+%a, %d %b %Y %H:%M:%S %z"` >>debian/changelog
|
||||
echo "">>debian/changelog
|
||||
dpkg-buildpackage
|
||||
cd $ret
|
||||
{ echo "3proxy ($RELEASE-$VERSION) buster; urgency=medium"
|
||||
echo " "
|
||||
echo " *3proxy $RELEASE build"
|
||||
echo " "
|
||||
echo " -- z3APA3A <3apa3a@3proxy.org> $(date -R -u -d @$SOURCE_DATE_EPOCH)"
|
||||
echo ""
|
||||
} > debian/changelog
|
||||
dpkg-buildpackage'
|
||||
cp ~/debian/3proxy_$RELEASE-"$VERSION"_arm64.deb ./3proxy-$RELEASE.arm64.deb
|
||||
- name: Get artifact deb
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: "3proxy-${{ env.RELEASE }}-arm64.deb"
|
||||
path: "*.deb"
|
||||
- name: Upload deb to release
|
||||
- name: Import signing key
|
||||
if: github.event_name == 'release'
|
||||
env:
|
||||
GPG_PRIVATE_KEY: ${{ secrets.GPG_PRIVATE_KEY }}
|
||||
GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }}
|
||||
run: |
|
||||
if [ -z "$GPG_PRIVATE_KEY" ]; then echo "GPG_PRIVATE_KEY is not set"; exit 1; fi
|
||||
mkdir -p ~/.gnupg && chmod 700 ~/.gnupg
|
||||
printf 'allow-loopback-pinentry\ndefault-cache-ttl 7200\nmax-cache-ttl 7200\n' > ~/.gnupg/gpg-agent.conf
|
||||
gpgconf --kill gpg-agent || true
|
||||
printf '%s' "$GPG_PRIVATE_KEY" | gpg --batch --import
|
||||
KEYID=$(gpg --list-secret-keys --with-colons | awk -F: '/^sec:/{print $5; exit}')
|
||||
echo "GPG_KEYID=$KEYID" >> $GITHUB_ENV
|
||||
echo prime > /tmp/prime.txt
|
||||
gpg --batch --yes --pinentry-mode loopback --passphrase "$GPG_PASSPHRASE" \
|
||||
-u "$KEYID" --detach-sign -o /dev/null /tmp/prime.txt
|
||||
rm -f /tmp/prime.txt
|
||||
- name: Sign rpm
|
||||
if: github.event_name == 'release'
|
||||
env:
|
||||
GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }}
|
||||
run: |
|
||||
GPGBIN=$(command -v gpg)
|
||||
if [ -z "$GPGBIN" ]; then echo "gpg not found"; exit 1; fi
|
||||
umask 077
|
||||
printf '%s' "$GPG_PASSPHRASE" > /tmp/gpgpass
|
||||
echo test > /tmp/signtest
|
||||
gpg --batch --yes --pinentry-mode loopback --passphrase-file /tmp/gpgpass \
|
||||
-u "$GPG_KEYID" --detach-sign -o /tmp/signtest.sig /tmp/signtest
|
||||
echo "key can sign"
|
||||
{ echo "%_gpg_name $GPG_KEYID"
|
||||
echo "%__gpg $GPGBIN"
|
||||
echo '%__gpg_sign_cmd %{__gpg} gpg --batch --no-armor --pinentry-mode loopback --passphrase-file /tmp/gpgpass --no-secmem-warning --digest-algo sha256 -u "%{_gpg_name}" -sbo %{__signature_filename} %{__plaintext_filename}'
|
||||
} > ~/.rpmmacros
|
||||
rpm --addsign *.rpm
|
||||
rm -f /tmp/gpgpass /tmp/signtest /tmp/signtest.sig
|
||||
for f in *.rpm; do
|
||||
sig=$(rpm -qp --qf '%{RSAHEADER:pgpsig}' "$f" 2>/dev/null)
|
||||
case "$sig" in ""|"(none)")
|
||||
sig=$(rpm -qp --qf '%{DSAHEADER:pgpsig}' "$f" 2>/dev/null) ;;
|
||||
esac
|
||||
case "$sig" in ""|"(none)")
|
||||
echo "$f is not signed"
|
||||
echo "--- rpm version ---"; rpm --version
|
||||
echo "--- sign cmd ---"; rpm --eval '%{__gpg_sign_cmd}'
|
||||
echo "--- secret keys ---"; gpg --list-secret-keys --with-colons | grep -E '^(sec|ssb):' || true
|
||||
exit 1 ;;
|
||||
esac
|
||||
echo "$f: $sig"
|
||||
done
|
||||
- name: Checksums and detached signatures
|
||||
if: github.event_name == 'release'
|
||||
env:
|
||||
GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }}
|
||||
run: |
|
||||
sha256sum *.rpm *.deb > SHA256SUMS-arm64
|
||||
for f in *.deb SHA256SUMS-arm64; do
|
||||
gpg --batch --yes --pinentry-mode loopback --passphrase "$GPG_PASSPHRASE" \
|
||||
-u "$GPG_KEYID" --armor --detach-sign "$f"
|
||||
done
|
||||
sha256sum -c SHA256SUMS-arm64
|
||||
gpg --verify SHA256SUMS-arm64.asc SHA256SUMS-arm64
|
||||
- name: Attest build provenance
|
||||
if: github.event_name == 'release'
|
||||
uses: actions/attest-build-provenance@v2
|
||||
with:
|
||||
subject-path: |
|
||||
*.rpm
|
||||
*.deb
|
||||
- name: Upload to release
|
||||
if: github.event_name == 'release'
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
TAG: ${{ github.event.release.tag_name }}
|
||||
run: gh release upload "$TAG" 3proxy-${{ env.RELEASE }}.arm64.deb
|
||||
run: gh release upload "$TAG" *.rpm *.deb *.deb.asc SHA256SUMS-arm64 SHA256SUMS-arm64.asc
|
||||
|
||||
147
.github/workflows/build-rpm-armhf.yml
vendored
147
.github/workflows/build-rpm-armhf.yml
vendored
@ -1,4 +1,4 @@
|
||||
name: RPM/DEB build armhf
|
||||
name: DEB build armhf
|
||||
|
||||
on:
|
||||
release:
|
||||
@ -6,10 +6,14 @@ on:
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
ci:
|
||||
permissions:
|
||||
contents: write
|
||||
id-token: write
|
||||
attestations: write
|
||||
name: "${{ matrix.target }}"
|
||||
strategy:
|
||||
matrix:
|
||||
@ -22,35 +26,12 @@ jobs:
|
||||
run: |
|
||||
pwd
|
||||
echo "RELEASE=$(cat RELEASE)" >> $GITHUB_ENV
|
||||
echo "VERSION=$(date +%y%m%d%H%M%S)" >> $GITHUB_ENV
|
||||
- name: Linux libraries
|
||||
run: |
|
||||
sudo apt update
|
||||
sudo dpkg --add-architecture armhf
|
||||
echo "Types: deb" > ~/ubuntu.sources
|
||||
echo "URIs: http://archive.ubuntu.com/ubuntu/" >> ~/ubuntu.sources
|
||||
echo "Suites: noble noble-updates noble-backports" >> ~/ubuntu.sources
|
||||
echo "Components: main restricted universe multiverse" >> ~/ubuntu.sources
|
||||
echo "Signed-By: /usr/share/keyrings/ubuntu-archive-keyring.gpg" >> ~/ubuntu.sources
|
||||
echo "Architectures: amd64" >> ~/ubuntu.sources
|
||||
echo "" >> ~/ubuntu.sources
|
||||
echo "Types: deb" >> ~/ubuntu.sources
|
||||
echo "URIs: http://security.ubuntu.com/ubuntu/" >> ~/ubuntu.sources
|
||||
echo "Suites: noble-security" >> ~/ubuntu.sources
|
||||
echo "Components: main restricted universe multiverse" >> ~/ubuntu.sources
|
||||
echo "Architectures: amd64" >> ~/ubuntu.sources
|
||||
echo "Signed-By: /usr/share/keyrings/ubuntu-archive-keyring.gpg" >> ~/ubuntu.sources
|
||||
echo "" >> ~/ubuntu.sources
|
||||
echo "Types: deb" >>~/ubuntu.sources
|
||||
echo "URIs: http://ports.ubuntu.com/ubuntu-ports/" >>~/ubuntu.sources
|
||||
echo "Suites: noble noble-updates" >>~/ubuntu.sources
|
||||
echo "Components: main restricted universe multiverse" >>~/ubuntu.sources
|
||||
echo "Architectures: armhf" >>~/ubuntu.sources
|
||||
echo "Signed-By: /usr/share/keyrings/ubuntu-archive-keyring.gpg" >>~/ubuntu.sources
|
||||
sudo cp ~/ubuntu.sources /etc/apt/sources.list.d/ubuntu.sources
|
||||
sudo apt update
|
||||
sudo apt install libssl3t64:armhf openssl:armhf libssl-dev:armhf libpam0g:armhf libpam0g-dev:armhf libpcre2-dev:armhf rpm crossbuild-essential-armhf build-essential debhelper
|
||||
- name: configure rpm env
|
||||
BUILDDATE=$(sed -n 's/^#define BUILDDATE "\(.*\)"$/\1/p' src/version.h)
|
||||
[ -n "$BUILDDATE" ] || BUILDDATE=$(date -u +%y%m%d%H%M%S)
|
||||
echo "VERSION=$BUILDDATE" >> $GITHUB_ENV
|
||||
SOURCE_DATE_EPOCH=$(date -u -d "20${BUILDDATE:0:2}-${BUILDDATE:2:2}-${BUILDDATE:4:2} ${BUILDDATE:6:2}:${BUILDDATE:8:2}:${BUILDDATE:10:2}" +%s)
|
||||
echo "SOURCE_DATE_EPOCH=$SOURCE_DATE_EPOCH" >> $GITHUB_ENV
|
||||
- name: configure deb env
|
||||
run: |
|
||||
mkdir ~/debian
|
||||
mkdir -p ~/rpmbuild/{BUILD,RPMS,SOURCES,SPECS,SRPMS}
|
||||
@ -58,59 +39,81 @@ jobs:
|
||||
ln -s ~/rpmbuild/SOURCES/3proxy-$RELEASE.tar.gz ~/rpmbuild/SOURCES/$RELEASE.tar.gz
|
||||
cp scripts/rh/3proxy.spec ~/rpmbuild/SPECS/3proxy-$RELEASE.spec
|
||||
cp ~/rpmbuild/SOURCES/3proxy-$RELEASE.tar.gz ~/debian/3proxy_$RELEASE.orig.tar.gz
|
||||
- name: rpmbuild
|
||||
run: |
|
||||
ret=`pwd`
|
||||
cd ~/rpmbuild/SPECS
|
||||
PATH=/usr/arm-linux-gnueabihf/bin:$PATH
|
||||
export PATH=$PATH
|
||||
CC=arm-linux-gnueabihf-gcc
|
||||
export CC=$CC
|
||||
export RPATH=/usr/arm-linux-gnueabihf/lib:$RPATH
|
||||
export LD_LIBRARY_PATH=/usr/arm-linux-gnueabihf/lib:$LD_LIBRARY_PATH
|
||||
rpmbuild -ba --define "PAMLIB pam0g" --define "_arch arm" --define "cross yes" --target=arm-linux-gnueabihf 3proxy-$RELEASE.spec
|
||||
cd $ret
|
||||
mv ~/rpmbuild/RPMS/arm/3proxy-$RELEASE-1.arm.rpm 3proxy-$RELEASE.arm.rpm
|
||||
- name: Get artifact rpm
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: "3proxy-${{ env.RELEASE }}-arm.rpm"
|
||||
path: "*.rpm"
|
||||
- name: Upload rpm to release
|
||||
if: github.event_name == 'release'
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
TAG: ${{ github.event.release.tag_name }}
|
||||
run: gh release upload "$TAG" 3proxy-${{ env.RELEASE }}.arm.rpm
|
||||
- name: debbuild
|
||||
run: |
|
||||
ret=`pwd`
|
||||
cd ~/debian/
|
||||
docker run --rm \
|
||||
-v "$HOME/debian:/debian" \
|
||||
-e RELEASE="$RELEASE" -e VERSION="$VERSION" \
|
||||
-e SOURCE_DATE_EPOCH="$SOURCE_DATE_EPOCH" \
|
||||
ubuntu:22.04 bash -c '
|
||||
set -e
|
||||
export DEBIAN_FRONTEND=noninteractive
|
||||
dpkg --add-architecture armhf
|
||||
sed -i "s|^deb |deb [arch=amd64] |" /etc/apt/sources.list
|
||||
{ echo "deb [arch=armhf] http://ports.ubuntu.com/ubuntu-ports jammy main restricted universe multiverse"
|
||||
echo "deb [arch=armhf] http://ports.ubuntu.com/ubuntu-ports jammy-updates main restricted universe multiverse"
|
||||
} >> /etc/apt/sources.list
|
||||
apt-get update
|
||||
apt-get install -y crossbuild-essential-armhf build-essential debhelper fakeroot \
|
||||
libssl-dev:armhf libpcre2-dev:armhf libpam0g-dev:armhf
|
||||
cd /debian
|
||||
tar xzf 3proxy_$RELEASE.orig.tar.gz
|
||||
cd 3proxy-$RELEASE
|
||||
echo "3proxy ($RELEASE-$VERSION) buster; urgency=medium" >debian/changelog
|
||||
echo " " >>debian/changelog
|
||||
echo " *3proxy $RELEASE build" >>debian/changelog
|
||||
echo " " >>debian/changelog
|
||||
echo " -- z3APA3A <3apa3a@3proxy.org> "`date "+%a, %d %b %Y %H:%M:%S %z"` >>debian/changelog
|
||||
echo "">>debian/changelog
|
||||
PATH=/usr/arm-linux-gnueabihf/bin:$PATH
|
||||
export PATH=$PATH
|
||||
CC=arm-linux-gnueabihf-gcc
|
||||
export CC=$CC
|
||||
export RPATH=/usr/arm-linux-gnueabihf/lib:$RPATH
|
||||
{ echo "3proxy ($RELEASE-$VERSION) buster; urgency=medium"
|
||||
echo " "
|
||||
echo " *3proxy $RELEASE build"
|
||||
echo " "
|
||||
echo " -- z3APA3A <3apa3a@3proxy.org> $(date -R -u -d @$SOURCE_DATE_EPOCH)"
|
||||
echo ""
|
||||
} > debian/changelog
|
||||
export PATH=/usr/arm-linux-gnueabihf/bin:$PATH
|
||||
export CC=arm-linux-gnueabihf-gcc
|
||||
export LD_LIBRARY_PATH=/usr/arm-linux-gnueabihf/lib:$LD_LIBRARY_PATH
|
||||
dpkg-buildpackage
|
||||
cd $ret
|
||||
dpkg-buildpackage'
|
||||
cp ~/debian/3proxy_$RELEASE-"$VERSION"_armhf.deb ./3proxy-$RELEASE.arm.deb
|
||||
- name: Get artifact deb
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: "3proxy-${{ env.RELEASE }}-arm.deb"
|
||||
path: "*.deb"
|
||||
- name: Upload deb to release
|
||||
- name: Import signing key
|
||||
if: github.event_name == 'release'
|
||||
env:
|
||||
GPG_PRIVATE_KEY: ${{ secrets.GPG_PRIVATE_KEY }}
|
||||
GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }}
|
||||
run: |
|
||||
if [ -z "$GPG_PRIVATE_KEY" ]; then echo "GPG_PRIVATE_KEY is not set"; exit 1; fi
|
||||
mkdir -p ~/.gnupg && chmod 700 ~/.gnupg
|
||||
printf 'allow-loopback-pinentry\ndefault-cache-ttl 7200\nmax-cache-ttl 7200\n' > ~/.gnupg/gpg-agent.conf
|
||||
gpgconf --kill gpg-agent || true
|
||||
printf '%s' "$GPG_PRIVATE_KEY" | gpg --batch --import
|
||||
KEYID=$(gpg --list-secret-keys --with-colons | awk -F: '/^sec:/{print $5; exit}')
|
||||
echo "GPG_KEYID=$KEYID" >> $GITHUB_ENV
|
||||
echo prime > /tmp/prime.txt
|
||||
gpg --batch --yes --pinentry-mode loopback --passphrase "$GPG_PASSPHRASE" \
|
||||
-u "$KEYID" --detach-sign -o /dev/null /tmp/prime.txt
|
||||
rm -f /tmp/prime.txt
|
||||
- name: Checksums and detached signatures
|
||||
if: github.event_name == 'release'
|
||||
env:
|
||||
GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }}
|
||||
run: |
|
||||
sha256sum *.deb > SHA256SUMS-arm
|
||||
for f in *.deb SHA256SUMS-arm; do
|
||||
gpg --batch --yes --pinentry-mode loopback --passphrase "$GPG_PASSPHRASE" \
|
||||
-u "$GPG_KEYID" --armor --detach-sign "$f"
|
||||
done
|
||||
sha256sum -c SHA256SUMS-arm
|
||||
gpg --verify SHA256SUMS-arm.asc SHA256SUMS-arm
|
||||
- name: Attest build provenance
|
||||
if: github.event_name == 'release'
|
||||
uses: actions/attest-build-provenance@v2
|
||||
with:
|
||||
subject-path: |
|
||||
*.deb
|
||||
- name: Upload to release
|
||||
if: github.event_name == 'release'
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
TAG: ${{ github.event.release.tag_name }}
|
||||
run: gh release upload "$TAG" 3proxy-${{ env.RELEASE }}.arm.deb
|
||||
run: gh release upload "$TAG" *.deb *.deb.asc SHA256SUMS-arm SHA256SUMS-arm.asc
|
||||
|
||||
155
.github/workflows/build-rpm-x86-64.yml
vendored
155
.github/workflows/build-rpm-x86-64.yml
vendored
@ -6,10 +6,14 @@ on:
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
ci:
|
||||
permissions:
|
||||
contents: write
|
||||
id-token: write
|
||||
attestations: write
|
||||
name: "${{ matrix.target }}"
|
||||
strategy:
|
||||
matrix:
|
||||
@ -22,7 +26,11 @@ jobs:
|
||||
run: |
|
||||
pwd
|
||||
echo "RELEASE=$(cat RELEASE)" >> $GITHUB_ENV
|
||||
echo "VERSION=$(date +%y%m%d%H%M%S)" >> $GITHUB_ENV
|
||||
BUILDDATE=$(sed -n 's/^#define BUILDDATE "\(.*\)"$/\1/p' src/version.h)
|
||||
[ -n "$BUILDDATE" ] || BUILDDATE=$(date -u +%y%m%d%H%M%S)
|
||||
echo "VERSION=$BUILDDATE" >> $GITHUB_ENV
|
||||
SOURCE_DATE_EPOCH=$(date -u -d "20${BUILDDATE:0:2}-${BUILDDATE:2:2}-${BUILDDATE:4:2} ${BUILDDATE:6:2}:${BUILDDATE:8:2}:${BUILDDATE:10:2}" +%s)
|
||||
echo "SOURCE_DATE_EPOCH=$SOURCE_DATE_EPOCH" >> $GITHUB_ENV
|
||||
- name: echo env
|
||||
run: echo "release $RELEASE version $VERSION"
|
||||
- name: Linux libraries
|
||||
@ -39,46 +47,143 @@ jobs:
|
||||
cp ~/rpmbuild/SOURCES/3proxy-$RELEASE.tar.gz ~/debian/3proxy_$RELEASE.orig.tar.gz
|
||||
- name: rpmbuild
|
||||
run: |
|
||||
ret=`pwd`
|
||||
mkdir -p rpmout
|
||||
for EL in 8 9 10; do
|
||||
docker run --rm \
|
||||
-v "$HOME/rpmbuild/SOURCES/3proxy-$RELEASE.tar.gz:/src.tar.gz:ro" \
|
||||
-v "$PWD/scripts/rh/3proxy.spec:/3proxy.spec:ro" \
|
||||
-v "$PWD/rpmout:/out" \
|
||||
-e RELEASE="$RELEASE" -e HOSTUID="$(id -u)" -e HOSTGID="$(id -g)" \
|
||||
-e SOURCE_DATE_EPOCH="$SOURCE_DATE_EPOCH" \
|
||||
"almalinux:$EL" bash -c '
|
||||
set -e
|
||||
dnf -y install rpm-build gcc make openssl-devel pcre2-devel pam-devel tar gzip
|
||||
mkdir -p ~/rpmbuild/{BUILD,RPMS,SOURCES,SPECS,SRPMS}
|
||||
cp /src.tar.gz ~/rpmbuild/SOURCES/3proxy-$RELEASE.tar.gz
|
||||
ln -sf ~/rpmbuild/SOURCES/3proxy-$RELEASE.tar.gz ~/rpmbuild/SOURCES/$RELEASE.tar.gz
|
||||
cp /3proxy.spec ~/rpmbuild/SPECS/3proxy-$RELEASE.spec
|
||||
cd ~/rpmbuild/SPECS
|
||||
rpmbuild -ba 3proxy-$RELEASE.spec
|
||||
cd $ret
|
||||
mv ~/rpmbuild/RPMS/x86_64/3proxy-$RELEASE-1.x86_64.rpm 3proxy-$RELEASE.x86_64.rpm
|
||||
rpmbuild -ba \
|
||||
--define "use_source_date_epoch_as_buildtime 1" \
|
||||
--define "clamp_mtime_to_source_date_epoch 1" \
|
||||
--define "_buildhost 3proxy.org" \
|
||||
3proxy-$RELEASE.spec
|
||||
cp ~/rpmbuild/RPMS/*/*.rpm /out/
|
||||
chown "$HOSTUID:$HOSTGID" /out/*.rpm || chmod 0666 /out/*.rpm'
|
||||
done
|
||||
for f in rpmout/*.rpm; do
|
||||
dist=$(rpm -qp --qf '%{RELEASE}' "$f" | sed 's/^1\.//')
|
||||
arch=$(rpm -qp --qf '%{ARCH}' "$f")
|
||||
mv "$f" "3proxy-$RELEASE.$dist.$arch.rpm"
|
||||
done
|
||||
rmdir rpmout
|
||||
ls -l *.rpm
|
||||
- name: Get artifact rpm
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: "3proxy-${{ env.RELEASE }}-x86_64.rpm"
|
||||
path: "*.rpm"
|
||||
- name: Upload rpm to release
|
||||
if: github.event_name == 'release'
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
TAG: ${{ github.event.release.tag_name }}
|
||||
run: gh release upload "$TAG" 3proxy-${{ env.RELEASE }}.x86_64.rpm
|
||||
- name: debbuild
|
||||
run: |
|
||||
ret=`pwd`
|
||||
cd ~/debian/
|
||||
docker run --rm \
|
||||
-v "$HOME/debian:/debian" \
|
||||
-e RELEASE="$RELEASE" -e VERSION="$VERSION" \
|
||||
-e SOURCE_DATE_EPOCH="$SOURCE_DATE_EPOCH" \
|
||||
ubuntu:22.04 bash -c '
|
||||
set -e
|
||||
export DEBIAN_FRONTEND=noninteractive
|
||||
apt-get update
|
||||
apt-get install -y build-essential debhelper fakeroot libssl-dev libpcre2-dev libpam0g-dev
|
||||
cd /debian
|
||||
tar xzf 3proxy_$RELEASE.orig.tar.gz
|
||||
cd 3proxy-$RELEASE
|
||||
echo "3proxy ($RELEASE-$VERSION) buster; urgency=medium" >debian/changelog
|
||||
echo " " >>debian/changelog
|
||||
echo " *3proxy $RELEASE build" >>debian/changelog
|
||||
echo " " >>debian/changelog
|
||||
echo " -- z3APA3A <3apa3a@3proxy.org> "`date "+%a, %d %b %Y %H:%M:%S %z"` >>debian/changelog
|
||||
echo "">>debian/changelog
|
||||
dpkg-buildpackage
|
||||
cd $ret
|
||||
{ echo "3proxy ($RELEASE-$VERSION) buster; urgency=medium"
|
||||
echo " "
|
||||
echo " *3proxy $RELEASE build"
|
||||
echo " "
|
||||
echo " -- z3APA3A <3apa3a@3proxy.org> $(date -R -u -d @$SOURCE_DATE_EPOCH)"
|
||||
echo ""
|
||||
} > debian/changelog
|
||||
dpkg-buildpackage'
|
||||
cp ~/debian/3proxy_$RELEASE-"$VERSION"_amd64.deb ./3proxy-$RELEASE.x86_64.deb
|
||||
- name: Get artifact deb
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: "3proxy-${{ env.RELEASE }}-x86_64.deb"
|
||||
path: "*.deb"
|
||||
- name: Upload deb to release
|
||||
|
||||
- name: Import signing key
|
||||
if: github.event_name == 'release'
|
||||
env:
|
||||
GPG_PRIVATE_KEY: ${{ secrets.GPG_PRIVATE_KEY }}
|
||||
GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }}
|
||||
run: |
|
||||
if [ -z "$GPG_PRIVATE_KEY" ]; then echo "GPG_PRIVATE_KEY is not set"; exit 1; fi
|
||||
mkdir -p ~/.gnupg && chmod 700 ~/.gnupg
|
||||
printf 'allow-loopback-pinentry\ndefault-cache-ttl 7200\nmax-cache-ttl 7200\n' > ~/.gnupg/gpg-agent.conf
|
||||
gpgconf --kill gpg-agent || true
|
||||
printf '%s' "$GPG_PRIVATE_KEY" | gpg --batch --import
|
||||
KEYID=$(gpg --list-secret-keys --with-colons | awk -F: '/^sec:/{print $5; exit}')
|
||||
echo "GPG_KEYID=$KEYID" >> $GITHUB_ENV
|
||||
echo prime > /tmp/prime.txt
|
||||
gpg --batch --yes --pinentry-mode loopback --passphrase "$GPG_PASSPHRASE" \
|
||||
-u "$KEYID" --detach-sign -o /dev/null /tmp/prime.txt
|
||||
rm -f /tmp/prime.txt
|
||||
- name: Sign rpm
|
||||
if: github.event_name == 'release'
|
||||
env:
|
||||
GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }}
|
||||
run: |
|
||||
GPGBIN=$(command -v gpg)
|
||||
if [ -z "$GPGBIN" ]; then echo "gpg not found"; exit 1; fi
|
||||
umask 077
|
||||
printf '%s' "$GPG_PASSPHRASE" > /tmp/gpgpass
|
||||
echo test > /tmp/signtest
|
||||
gpg --batch --yes --pinentry-mode loopback --passphrase-file /tmp/gpgpass \
|
||||
-u "$GPG_KEYID" --detach-sign -o /tmp/signtest.sig /tmp/signtest
|
||||
echo "key can sign"
|
||||
{ echo "%_gpg_name $GPG_KEYID"
|
||||
echo "%__gpg $GPGBIN"
|
||||
echo '%__gpg_sign_cmd %{__gpg} gpg --batch --no-armor --pinentry-mode loopback --passphrase-file /tmp/gpgpass --no-secmem-warning --digest-algo sha256 -u "%{_gpg_name}" -sbo %{__signature_filename} %{__plaintext_filename}'
|
||||
} > ~/.rpmmacros
|
||||
rpm --addsign *.rpm
|
||||
rm -f /tmp/gpgpass /tmp/signtest /tmp/signtest.sig
|
||||
for f in *.rpm; do
|
||||
sig=$(rpm -qp --qf '%{RSAHEADER:pgpsig}' "$f" 2>/dev/null)
|
||||
case "$sig" in ""|"(none)")
|
||||
sig=$(rpm -qp --qf '%{DSAHEADER:pgpsig}' "$f" 2>/dev/null) ;;
|
||||
esac
|
||||
case "$sig" in ""|"(none)")
|
||||
echo "$f is not signed"
|
||||
echo "--- rpm version ---"; rpm --version
|
||||
echo "--- sign cmd ---"; rpm --eval '%{__gpg_sign_cmd}'
|
||||
echo "--- secret keys ---"; gpg --list-secret-keys --with-colons | grep -E '^(sec|ssb):' || true
|
||||
exit 1 ;;
|
||||
esac
|
||||
echo "$f: $sig"
|
||||
done
|
||||
- name: Checksums and detached signatures
|
||||
if: github.event_name == 'release'
|
||||
env:
|
||||
GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }}
|
||||
run: |
|
||||
sha256sum *.rpm *.deb > SHA256SUMS-x86_64
|
||||
for f in *.deb SHA256SUMS-x86_64; do
|
||||
gpg --batch --yes --pinentry-mode loopback --passphrase "$GPG_PASSPHRASE" \
|
||||
-u "$GPG_KEYID" --armor --detach-sign "$f"
|
||||
done
|
||||
sha256sum -c SHA256SUMS-x86_64
|
||||
gpg --verify SHA256SUMS-x86_64.asc SHA256SUMS-x86_64
|
||||
- name: Attest build provenance
|
||||
if: github.event_name == 'release'
|
||||
uses: actions/attest-build-provenance@v2
|
||||
with:
|
||||
subject-path: |
|
||||
*.rpm
|
||||
*.deb
|
||||
- name: Upload to release
|
||||
if: github.event_name == 'release'
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
TAG: ${{ github.event.release.tag_name }}
|
||||
run: gh release upload "$TAG" 3proxy-${{ env.RELEASE }}.x86_64.deb
|
||||
|
||||
run: gh release upload "$TAG" *.rpm *.deb *.deb.asc SHA256SUMS-x86_64 SHA256SUMS-x86_64.asc
|
||||
|
||||
41
.github/workflows/build-watcom.yml
vendored
41
.github/workflows/build-watcom.yml
vendored
@ -6,10 +6,14 @@ on:
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
ci:
|
||||
permissions:
|
||||
contents: write
|
||||
id-token: write
|
||||
attestations: write
|
||||
name: "${{ matrix.target }}"
|
||||
strategy:
|
||||
matrix:
|
||||
@ -34,19 +38,8 @@ jobs:
|
||||
- name: make Watcom
|
||||
shell: cmd
|
||||
run: |
|
||||
echo "volatile char VerSion[]=^"3APA3A-3proxy-Internal-Build: 3proxy-%RELEASE%-%NOW%\r\nCode certificate: https://3proxy.org/3proxy.cer\r\n^";" >>src/3proxy.c
|
||||
echo "volatile char VerSion[]=^"3APA3A-3proxy-Internal-Build: 3proxy-%RELEASE%-%NOW%\r\n^";" >>src/3proxy.c
|
||||
nmake /F Makefile.watcom
|
||||
- name: Decode Certificate
|
||||
shell: pwsh
|
||||
run: |
|
||||
$pfx_cert_byte = [System.Convert]::FromBase64String("${{ secrets.WINDOWS_CERTIFICATE }}")
|
||||
[System.IO.File]::WriteAllBytes("${{ github.workspace }}\cert.pfx", $pfx_cert_byte)
|
||||
- name: Sign
|
||||
shell: pwsh
|
||||
run: |
|
||||
$signtool = (Get-ChildItem "C:\Program Files (x86)\Windows Kits\10\bin\*\x64\signtool.exe" | Sort-Object { [version]$_.Directory.Parent.Name } -Descending | Select-Object -First 1).FullName
|
||||
& $signtool sign /f "${{ github.workspace }}\cert.pfx" /p "${{ secrets.WINDOWS_CERTIFICATE_PASSWORD }}" /tr http://timestamp.digicert.com /td sha256 /fd sha256 "bin\3proxy.exe"
|
||||
& $signtool sign /f "${{ github.workspace }}\cert.pfx" /p "${{ secrets.WINDOWS_CERTIFICATE_PASSWORD }}" /tr http://timestamp.digicert.com /td sha256 /fd sha256 "bin\3proxy_crypt.exe"
|
||||
- name: make dist dir
|
||||
shell: cmd
|
||||
run: |
|
||||
@ -86,10 +79,30 @@ jobs:
|
||||
if: github.event_name == 'release'
|
||||
shell: pwsh
|
||||
run: Compress-Archive -Path dist/* -DestinationPath 3proxy-${{ env.RELEASE }}-lite.zip
|
||||
- name: Checksums and detached signature
|
||||
if: github.event_name == 'release'
|
||||
shell: bash
|
||||
env:
|
||||
GPG_PRIVATE_KEY: ${{ secrets.GPG_PRIVATE_KEY }}
|
||||
GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }}
|
||||
run: |
|
||||
if [ -z "$GPG_PRIVATE_KEY" ]; then echo "GPG_PRIVATE_KEY is not set"; exit 1; fi
|
||||
printf '%s' "$GPG_PRIVATE_KEY" | gpg --batch --import
|
||||
KEYID=$(gpg --list-secret-keys --with-colons | awk -F: '/^sec:/{print $5; exit}')
|
||||
sha256sum *.zip > SHA256SUMS-win-lite
|
||||
gpg --batch --yes --pinentry-mode loopback --passphrase "$GPG_PASSPHRASE" \
|
||||
-u "$KEYID" --armor --detach-sign SHA256SUMS-win-lite
|
||||
sha256sum -c SHA256SUMS-win-lite
|
||||
- name: Attest build provenance
|
||||
if: github.event_name == 'release'
|
||||
uses: actions/attest-build-provenance@v2
|
||||
with:
|
||||
subject-path: |
|
||||
*.zip
|
||||
- name: Upload to release
|
||||
if: github.event_name == 'release'
|
||||
shell: bash
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
TAG: ${{ github.event.release.tag_name }}
|
||||
run: gh release upload "$TAG" 3proxy-${{ env.RELEASE }}-lite.zip
|
||||
run: gh release upload "$TAG" *.zip SHA256SUMS-win-lite SHA256SUMS-win-lite.asc
|
||||
|
||||
50
.github/workflows/build-win32.yml
vendored
50
.github/workflows/build-win32.yml
vendored
@ -6,10 +6,14 @@ on:
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
ci:
|
||||
permissions:
|
||||
contents: write
|
||||
id-token: write
|
||||
attestations: write
|
||||
name: "${{ matrix.target }}"
|
||||
strategy:
|
||||
matrix:
|
||||
@ -40,27 +44,8 @@ jobs:
|
||||
cd "D:/a/3proxy/3proxy"
|
||||
set "LIB=%LIB%;c:/vcpkg/installed/x86-windows-static/lib"
|
||||
set "INCLUDE=%INCLUDE%;c:/vcpkg/installed/x86-windows-static/include"
|
||||
echo "volatile char VerSion[]=^"3APA3A-3proxy-Internal-Build: 3proxy-%RELEASE%-%NOW%\r\nCode certificate: https://3proxy.org/3proxy.cer\r\n^";" >>src/3proxy.c
|
||||
echo "volatile char VerSion[]=^"3APA3A-3proxy-Internal-Build: 3proxy-%RELEASE%-%NOW%\r\n^";" >>src/3proxy.c
|
||||
nmake /F Makefile.msvc WOLFSSL=1
|
||||
- name: Decode Certificate
|
||||
shell: pwsh
|
||||
run: |
|
||||
$pfx_cert_byte = [System.Convert]::FromBase64String("${{ secrets.WINDOWS_CERTIFICATE }}")
|
||||
[System.IO.File]::WriteAllBytes("${{ github.workspace }}\cert.pfx", $pfx_cert_byte)
|
||||
- name: Extract public certificate
|
||||
shell: pwsh
|
||||
env:
|
||||
CERT_PASSWORD: ${{ secrets.WINDOWS_CERTIFICATE_PASSWORD }}
|
||||
run: |
|
||||
$cert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2("${{ github.workspace }}\cert.pfx", "$env:CERT_PASSWORD")
|
||||
[System.IO.File]::WriteAllBytes("${{ github.workspace }}\3proxy.crt", $cert.Export("Cert"))
|
||||
- name: Sign
|
||||
shell: pwsh
|
||||
env:
|
||||
CERT_PASSWORD: ${{ secrets.WINDOWS_CERTIFICATE_PASSWORD }}
|
||||
run: |
|
||||
$signtool = (Get-ChildItem "C:\Program Files (x86)\Windows Kits\10\bin\*\x64\signtool.exe" | Sort-Object { [version]$_.Directory.Parent.Name } -Descending | Select-Object -First 1).FullName
|
||||
Get-ChildItem bin\*.exe, bin\*.dll | ForEach-Object { & $signtool sign /f "${{ github.workspace }}\cert.pfx" /p "$env:CERT_PASSWORD" /tr http://timestamp.digicert.com /td sha256 /fd sha256 $_.FullName }
|
||||
- name: make dist dir
|
||||
shell: cmd
|
||||
run: |
|
||||
@ -91,7 +76,6 @@ jobs:
|
||||
copy authors dist\3proxy\
|
||||
copy README.md dist\3proxy\
|
||||
copy rus.3ps dist\3proxy\
|
||||
copy 3proxy.crt dist\3proxy\
|
||||
- name: Get artifact
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
@ -101,10 +85,30 @@ jobs:
|
||||
if: github.event_name == 'release'
|
||||
shell: pwsh
|
||||
run: Compress-Archive -Path dist/* -DestinationPath 3proxy-${{ env.RELEASE }}-x86.zip
|
||||
- name: Checksums and detached signature
|
||||
if: github.event_name == 'release'
|
||||
shell: bash
|
||||
env:
|
||||
GPG_PRIVATE_KEY: ${{ secrets.GPG_PRIVATE_KEY }}
|
||||
GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }}
|
||||
run: |
|
||||
if [ -z "$GPG_PRIVATE_KEY" ]; then echo "GPG_PRIVATE_KEY is not set"; exit 1; fi
|
||||
printf '%s' "$GPG_PRIVATE_KEY" | gpg --batch --import
|
||||
KEYID=$(gpg --list-secret-keys --with-colons | awk -F: '/^sec:/{print $5; exit}')
|
||||
sha256sum *.zip > SHA256SUMS-win-x86
|
||||
gpg --batch --yes --pinentry-mode loopback --passphrase "$GPG_PASSPHRASE" \
|
||||
-u "$KEYID" --armor --detach-sign SHA256SUMS-win-x86
|
||||
sha256sum -c SHA256SUMS-win-x86
|
||||
- name: Attest build provenance
|
||||
if: github.event_name == 'release'
|
||||
uses: actions/attest-build-provenance@v2
|
||||
with:
|
||||
subject-path: |
|
||||
*.zip
|
||||
- name: Upload to release
|
||||
if: github.event_name == 'release'
|
||||
shell: bash
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
TAG: ${{ github.event.release.tag_name }}
|
||||
run: gh release upload "$TAG" 3proxy-${{ env.RELEASE }}-x86.zip
|
||||
run: gh release upload "$TAG" *.zip SHA256SUMS-win-x86 SHA256SUMS-win-x86.asc
|
||||
|
||||
50
.github/workflows/build-win64.yml
vendored
50
.github/workflows/build-win64.yml
vendored
@ -6,10 +6,14 @@ on:
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
ci:
|
||||
permissions:
|
||||
contents: write
|
||||
id-token: write
|
||||
attestations: write
|
||||
name: "${{ matrix.target }}"
|
||||
strategy:
|
||||
matrix:
|
||||
@ -40,28 +44,9 @@ jobs:
|
||||
cd "D:/a/3proxy/3proxy"
|
||||
set "LIB=%LIB%;c:/vcpkg/installed/x64-windows-static/lib"
|
||||
set "INCLUDE=%INCLUDE%;c:/vcpkg/installed/x64-windows-static/include"
|
||||
echo "volatile char VerSion[]=^"3APA3A-3proxy-Internal-Build: 3proxy-%RELEASE%-%NOW%\r\nCode certificate: https://3proxy.org/3proxy.cer\r\n^";" >>src/3proxy.c
|
||||
echo "volatile char VerSion[]=^"3APA3A-3proxy-Internal-Build: 3proxy-%RELEASE%-%NOW%\r\n^";" >>src/3proxy.c
|
||||
echo %NOW% / %RELEASE% / %BUILDDATE% / %VERSION%
|
||||
nmake /F Makefile.msvc WOLFSSL=1
|
||||
- name: Decode Certificate
|
||||
shell: pwsh
|
||||
run: |
|
||||
$pfx_cert_byte = [System.Convert]::FromBase64String("${{ secrets.WINDOWS_CERTIFICATE }}")
|
||||
[System.IO.File]::WriteAllBytes("${{ github.workspace }}\cert.pfx", $pfx_cert_byte)
|
||||
- name: Extract public certificate
|
||||
shell: pwsh
|
||||
env:
|
||||
CERT_PASSWORD: ${{ secrets.WINDOWS_CERTIFICATE_PASSWORD }}
|
||||
run: |
|
||||
$cert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2("${{ github.workspace }}\cert.pfx", "$env:CERT_PASSWORD")
|
||||
[System.IO.File]::WriteAllBytes("${{ github.workspace }}\3proxy.crt", $cert.Export("Cert"))
|
||||
- name: Sign
|
||||
shell: pwsh
|
||||
env:
|
||||
CERT_PASSWORD: ${{ secrets.WINDOWS_CERTIFICATE_PASSWORD }}
|
||||
run: |
|
||||
$signtool = (Get-ChildItem "C:\Program Files (x86)\Windows Kits\10\bin\*\x64\signtool.exe" | Sort-Object { [version]$_.Directory.Parent.Name } -Descending | Select-Object -First 1).FullName
|
||||
Get-ChildItem bin\*.exe, bin\*.dll | ForEach-Object { & $signtool sign /f "${{ github.workspace }}\cert.pfx" /p "$env:CERT_PASSWORD" /tr http://timestamp.digicert.com /td sha256 /fd sha256 $_.FullName }
|
||||
- name: make dist dir
|
||||
shell: cmd
|
||||
run: |
|
||||
@ -92,7 +77,6 @@ jobs:
|
||||
copy authors dist\3proxy\
|
||||
copy README.md dist\3proxy\
|
||||
copy rus.3ps dist\3proxy\
|
||||
copy 3proxy.crt dist\3proxy\
|
||||
- name: Get artifact
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
@ -102,10 +86,30 @@ jobs:
|
||||
if: github.event_name == 'release'
|
||||
shell: pwsh
|
||||
run: Compress-Archive -Path dist/* -DestinationPath 3proxy-${{ env.RELEASE }}-x64.zip
|
||||
- name: Checksums and detached signature
|
||||
if: github.event_name == 'release'
|
||||
shell: bash
|
||||
env:
|
||||
GPG_PRIVATE_KEY: ${{ secrets.GPG_PRIVATE_KEY }}
|
||||
GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }}
|
||||
run: |
|
||||
if [ -z "$GPG_PRIVATE_KEY" ]; then echo "GPG_PRIVATE_KEY is not set"; exit 1; fi
|
||||
printf '%s' "$GPG_PRIVATE_KEY" | gpg --batch --import
|
||||
KEYID=$(gpg --list-secret-keys --with-colons | awk -F: '/^sec:/{print $5; exit}')
|
||||
sha256sum *.zip > SHA256SUMS-win-x64
|
||||
gpg --batch --yes --pinentry-mode loopback --passphrase "$GPG_PASSPHRASE" \
|
||||
-u "$KEYID" --armor --detach-sign SHA256SUMS-win-x64
|
||||
sha256sum -c SHA256SUMS-win-x64
|
||||
- name: Attest build provenance
|
||||
if: github.event_name == 'release'
|
||||
uses: actions/attest-build-provenance@v2
|
||||
with:
|
||||
subject-path: |
|
||||
*.zip
|
||||
- name: Upload to release
|
||||
if: github.event_name == 'release'
|
||||
shell: bash
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
TAG: ${{ github.event.release.tag_name }}
|
||||
run: gh release upload "$TAG" 3proxy-${{ env.RELEASE }}-x64.zip
|
||||
run: gh release upload "$TAG" *.zip SHA256SUMS-win-x64 SHA256SUMS-win-x64.asc
|
||||
|
||||
50
.github/workflows/build-winarm64.yml
vendored
50
.github/workflows/build-winarm64.yml
vendored
@ -6,10 +6,14 @@ on:
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
ci:
|
||||
permissions:
|
||||
contents: write
|
||||
id-token: write
|
||||
attestations: write
|
||||
name: "${{ matrix.target }}"
|
||||
strategy:
|
||||
matrix:
|
||||
@ -40,27 +44,8 @@ jobs:
|
||||
cd "D:/a/3proxy/3proxy"
|
||||
set "LIB=%LIB%;c:/vcpkg/installed/arm64-windows-static/lib"
|
||||
set "INCLUDE=%INCLUDE%;c:/vcpkg/installed/arm64-windows-static/include"
|
||||
echo "volatile char VerSion[]=^"3APA3A-3proxy-Internal-Build: 3proxy-%RELEASE%-%NOW%\r\nCode certificate: https://3proxy.org/3proxy.cer\r\n^";" >>src/3proxy.c
|
||||
echo "volatile char VerSion[]=^"3APA3A-3proxy-Internal-Build: 3proxy-%RELEASE%-%NOW%\r\n^";" >>src/3proxy.c
|
||||
nmake /F Makefile.msvc WOLFSSL=1
|
||||
- name: Decode Certificate
|
||||
shell: pwsh
|
||||
run: |
|
||||
$pfx_cert_byte = [System.Convert]::FromBase64String("${{ secrets.WINDOWS_CERTIFICATE }}")
|
||||
[System.IO.File]::WriteAllBytes("${{ github.workspace }}\cert.pfx", $pfx_cert_byte)
|
||||
- name: Extract public certificate
|
||||
shell: pwsh
|
||||
env:
|
||||
CERT_PASSWORD: ${{ secrets.WINDOWS_CERTIFICATE_PASSWORD }}
|
||||
run: |
|
||||
$cert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2("${{ github.workspace }}\cert.pfx", "$env:CERT_PASSWORD")
|
||||
[System.IO.File]::WriteAllBytes("${{ github.workspace }}\3proxy.crt", $cert.Export("Cert"))
|
||||
- name: Sign
|
||||
shell: pwsh
|
||||
env:
|
||||
CERT_PASSWORD: ${{ secrets.WINDOWS_CERTIFICATE_PASSWORD }}
|
||||
run: |
|
||||
$signtool = (Get-ChildItem "C:\Program Files (x86)\Windows Kits\10\bin\*\x64\signtool.exe" | Sort-Object { [version]$_.Directory.Parent.Name } -Descending | Select-Object -First 1).FullName
|
||||
Get-ChildItem bin\*.exe, bin\*.dll | ForEach-Object { & $signtool sign /f "${{ github.workspace }}\cert.pfx" /p "$env:CERT_PASSWORD" /tr http://timestamp.digicert.com /td sha256 /fd sha256 $_.FullName }
|
||||
- name: make dist dir
|
||||
shell: cmd
|
||||
run: |
|
||||
@ -91,7 +76,6 @@ jobs:
|
||||
copy authors dist\3proxy\
|
||||
copy README.md dist\3proxy\
|
||||
copy rus.3ps dist\3proxy\
|
||||
copy 3proxy.crt dist\3proxy\
|
||||
- name: Get artifact
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
@ -101,10 +85,30 @@ jobs:
|
||||
if: github.event_name == 'release'
|
||||
shell: pwsh
|
||||
run: Compress-Archive -Path dist/* -DestinationPath 3proxy-${{ env.RELEASE }}-arm64.zip
|
||||
- name: Checksums and detached signature
|
||||
if: github.event_name == 'release'
|
||||
shell: bash
|
||||
env:
|
||||
GPG_PRIVATE_KEY: ${{ secrets.GPG_PRIVATE_KEY }}
|
||||
GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }}
|
||||
run: |
|
||||
if [ -z "$GPG_PRIVATE_KEY" ]; then echo "GPG_PRIVATE_KEY is not set"; exit 1; fi
|
||||
printf '%s' "$GPG_PRIVATE_KEY" | gpg --batch --import
|
||||
KEYID=$(gpg --list-secret-keys --with-colons | awk -F: '/^sec:/{print $5; exit}')
|
||||
sha256sum *.zip > SHA256SUMS-win-arm64
|
||||
gpg --batch --yes --pinentry-mode loopback --passphrase "$GPG_PASSPHRASE" \
|
||||
-u "$KEYID" --armor --detach-sign SHA256SUMS-win-arm64
|
||||
sha256sum -c SHA256SUMS-win-arm64
|
||||
- name: Attest build provenance
|
||||
if: github.event_name == 'release'
|
||||
uses: actions/attest-build-provenance@v2
|
||||
with:
|
||||
subject-path: |
|
||||
*.zip
|
||||
- name: Upload to release
|
||||
if: github.event_name == 'release'
|
||||
shell: bash
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
TAG: ${{ github.event.release.tag_name }}
|
||||
run: gh release upload "$TAG" 3proxy-${{ env.RELEASE }}-arm64.zip
|
||||
run: gh release upload "$TAG" *.zip SHA256SUMS-win-arm64 SHA256SUMS-win-arm64.asc
|
||||
|
||||
99
.github/workflows/docker-ghcr.yml
vendored
99
.github/workflows/docker-ghcr.yml
vendored
@ -1,99 +0,0 @@
|
||||
name: Build Docker images (GHCR)
|
||||
|
||||
on:
|
||||
release:
|
||||
types: [published]
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
id-token: write
|
||||
|
||||
env:
|
||||
REGISTRY: ghcr.io
|
||||
IMAGE_NAME: ${{ github.repository }}
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Build and push Docker images
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v7
|
||||
|
||||
- name: Determine tags
|
||||
id: tags
|
||||
env:
|
||||
RELEASE_TAG: ${{ github.event.release.tag_name }}
|
||||
IMAGE: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
|
||||
run: |
|
||||
if [[ "$RELEASE_TAG" != "" ]]; then
|
||||
RELEASE="${RELEASE_TAG#v}"
|
||||
echo "minimal=${IMAGE}:${RELEASE}.minimal,${IMAGE}:minimal" >> "$GITHUB_OUTPUT"
|
||||
echo "busybox=${IMAGE}:${RELEASE}.busybox,${IMAGE}:busybox" >> "$GITHUB_OUTPUT"
|
||||
echo "full=${IMAGE}:${RELEASE},${IMAGE}:latest" >> "$GITHUB_OUTPUT"
|
||||
else
|
||||
DATETIME=$(date +%d%m%y%H%M%S)
|
||||
BRANCH=$(echo "${GITHUB_REF#refs/heads/}" | tr "/" "-")
|
||||
echo "minimal=${IMAGE}:${DATETIME}-${BRANCH}.minimal,${IMAGE}:${BRANCH}.minimal" >> "$GITHUB_OUTPUT"
|
||||
echo "busybox=${IMAGE}:${DATETIME}-${BRANCH}.busybox,${IMAGE}:${BRANCH}.busybox" >> "$GITHUB_OUTPUT"
|
||||
echo "full=${IMAGE}:${DATETIME}-${BRANCH},${IMAGE}:${BRANCH}" >> "$GITHUB_OUTPUT"
|
||||
fi
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v4
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v4
|
||||
|
||||
- name: Install cosign
|
||||
uses: sigstore/cosign-installer@v3
|
||||
|
||||
- name: Login to GHCR
|
||||
if: github.event_name != 'pull_request'
|
||||
uses: docker/login-action@v4
|
||||
with:
|
||||
registry: ${{ env.REGISTRY }}
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Build and push minimal
|
||||
uses: docker/build-push-action@v7
|
||||
with:
|
||||
context: .
|
||||
file: Dockerfile.minimal
|
||||
platforms: linux/amd64,linux/arm64,linux/arm/v7,ppc64le
|
||||
push: ${{ github.event_name != 'pull_request' }}
|
||||
tags: ${{ steps.tags.outputs.minimal }}
|
||||
|
||||
- name: Build and push busybox
|
||||
uses: docker/build-push-action@v7
|
||||
with:
|
||||
context: .
|
||||
file: Dockerfile.busybox
|
||||
platforms: linux/amd64,linux/arm64,linux/arm/v7,ppc64le
|
||||
push: ${{ github.event_name != 'pull_request' }}
|
||||
tags: ${{ steps.tags.outputs.busybox }}
|
||||
|
||||
- name: Build and push full
|
||||
uses: docker/build-push-action@v7
|
||||
with:
|
||||
context: .
|
||||
file: Dockerfile.full
|
||||
platforms: linux/amd64,linux/arm64,linux/arm/v7,ppc64le
|
||||
push: ${{ github.event_name != 'pull_request' }}
|
||||
tags: ${{ steps.tags.outputs.full }}
|
||||
|
||||
- name: Sign images
|
||||
if: github.event_name != 'pull_request'
|
||||
env:
|
||||
TAGS_MINIMAL: ${{ steps.tags.outputs.minimal }}
|
||||
TAGS_BUSYBOX: ${{ steps.tags.outputs.busybox }}
|
||||
TAGS_FULL: ${{ steps.tags.outputs.full }}
|
||||
run: |
|
||||
IFS=',' read -ra TAGS <<< "$TAGS_MINIMAL,$TAGS_BUSYBOX,$TAGS_FULL"
|
||||
for tag in "${TAGS[@]}"; do
|
||||
cosign sign --yes "$tag"
|
||||
done
|
||||
|
||||
206
.github/workflows/docker.yml
vendored
206
.github/workflows/docker.yml
vendored
@ -1,4 +1,4 @@
|
||||
name: Build Docker images (Docker Hub)
|
||||
name: Build Docker images
|
||||
|
||||
on:
|
||||
release:
|
||||
@ -7,89 +7,187 @@ on:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
id-token: write
|
||||
|
||||
env:
|
||||
REGISTRY: docker.io
|
||||
IMAGE_NAME: 3proxy/3proxy
|
||||
DOCKERHUB_IMAGE: docker.io/3proxy/3proxy
|
||||
GHCR_IMAGE: ghcr.io/3proxy/3proxy
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Build and push Docker images
|
||||
runs-on: ubuntu-latest
|
||||
name: ${{ matrix.image }} ${{ matrix.platform }}
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
runs-on: ${{ matrix.runner }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
image: [full, busybox, minimal]
|
||||
platform: [linux/amd64, linux/arm64, linux/arm/v7]
|
||||
include:
|
||||
- platform: linux/amd64
|
||||
runner: ubuntu-latest
|
||||
- platform: linux/arm64
|
||||
runner: ubuntu-24.04-arm
|
||||
- platform: linux/arm/v7
|
||||
runner: ubuntu-24.04-arm
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v7
|
||||
|
||||
- name: Determine tags
|
||||
id: tags
|
||||
env:
|
||||
RELEASE_TAG: ${{ github.event.release.tag_name }}
|
||||
run: |
|
||||
if [[ "$RELEASE_TAG" != "" ]]; then
|
||||
RELEASE="${RELEASE_TAG#v}"
|
||||
echo "minimal=${REGISTRY}/${IMAGE_NAME}:${RELEASE}.minimal,${REGISTRY}/${IMAGE_NAME}:minimal" >> "$GITHUB_OUTPUT"
|
||||
echo "busybox=${REGISTRY}/${IMAGE_NAME}:${RELEASE}.busybox,${REGISTRY}/${IMAGE_NAME}:busybox" >> "$GITHUB_OUTPUT"
|
||||
echo "full=${REGISTRY}/${IMAGE_NAME}:${RELEASE},${REGISTRY}/${IMAGE_NAME}:latest" >> "$GITHUB_OUTPUT"
|
||||
else
|
||||
DATETIME=$(date +%d%m%y%H%M%S)
|
||||
BRANCH=$(echo "${GITHUB_REF#refs/heads/}" | tr "/" "-")
|
||||
echo "minimal=${REGISTRY}/${IMAGE_NAME}:${DATETIME}-${BRANCH}.minimal,${REGISTRY}/${IMAGE_NAME}:${BRANCH}.minimal" >> "$GITHUB_OUTPUT"
|
||||
echo "busybox=${REGISTRY}/${IMAGE_NAME}:${DATETIME}-${BRANCH}.busybox,${REGISTRY}/${IMAGE_NAME}:${BRANCH}.busybox" >> "$GITHUB_OUTPUT"
|
||||
echo "full=${REGISTRY}/${IMAGE_NAME}:${DATETIME}-${BRANCH},${REGISTRY}/${IMAGE_NAME}:${BRANCH}" >> "$GITHUB_OUTPUT"
|
||||
fi
|
||||
- name: Platform name
|
||||
id: platform
|
||||
run: echo "pair=$(echo '${{ matrix.platform }}' | tr / -)" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Set up QEMU
|
||||
if: matrix.platform == 'linux/arm/v7'
|
||||
uses: docker/setup-qemu-action@v4
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v4
|
||||
|
||||
- name: Login to GHCR
|
||||
uses: docker/login-action@v4
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Build and push by digest
|
||||
id: build
|
||||
uses: docker/build-push-action@v7
|
||||
with:
|
||||
context: .
|
||||
file: Dockerfile.${{ matrix.image }}
|
||||
platforms: ${{ matrix.platform }}
|
||||
provenance: false
|
||||
sbom: false
|
||||
outputs: type=image,name=${{ env.GHCR_IMAGE }},push-by-digest=true,name-canonical=true,push=true
|
||||
|
||||
- name: Export digest
|
||||
env:
|
||||
DIGEST: ${{ steps.build.outputs.digest }}
|
||||
run: |
|
||||
mkdir -p /tmp/digests
|
||||
touch "/tmp/digests/${DIGEST#sha256:}"
|
||||
|
||||
- name: Upload digest
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: digests-${{ matrix.image }}-${{ steps.platform.outputs.pair }}
|
||||
path: /tmp/digests/*
|
||||
if-no-files-found: error
|
||||
retention-days: 1
|
||||
|
||||
publish:
|
||||
name: Publish ${{ matrix.image }}
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
id-token: write
|
||||
attestations: write
|
||||
runs-on: ubuntu-latest
|
||||
needs: build
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- image: full
|
||||
suffix: ''
|
||||
floating: lts
|
||||
- image: busybox
|
||||
suffix: .busybox
|
||||
floating: lts-busybox
|
||||
- image: minimal
|
||||
suffix: .minimal
|
||||
floating: lts-minimal
|
||||
steps:
|
||||
- name: Download digests
|
||||
uses: actions/download-artifact@v7
|
||||
with:
|
||||
path: /tmp/digests
|
||||
pattern: digests-${{ matrix.image }}-*
|
||||
merge-multiple: true
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v4
|
||||
|
||||
- name: Install cosign
|
||||
uses: sigstore/cosign-installer@v3
|
||||
with:
|
||||
cosign-release: v2.4.3
|
||||
|
||||
- name: Login to Docker Hub
|
||||
if: github.event_name != 'pull_request'
|
||||
uses: docker/login-action@v4
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
|
||||
- name: Build and push minimal
|
||||
uses: docker/build-push-action@v7
|
||||
- name: Login to GHCR
|
||||
uses: docker/login-action@v4
|
||||
with:
|
||||
context: .
|
||||
file: Dockerfile.minimal
|
||||
platforms: linux/amd64,linux/arm64,linux/arm/v7,ppc64le
|
||||
push: ${{ github.event_name != 'pull_request' }}
|
||||
tags: ${{ steps.tags.outputs.minimal }}
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Build and push busybox
|
||||
uses: docker/build-push-action@v7
|
||||
with:
|
||||
context: .
|
||||
file: Dockerfile.busybox
|
||||
platforms: linux/amd64,linux/arm64,linux/arm/v7,ppc64le
|
||||
push: ${{ github.event_name != 'pull_request' }}
|
||||
tags: ${{ steps.tags.outputs.busybox }}
|
||||
- name: Determine tags
|
||||
id: tags
|
||||
env:
|
||||
RELEASE_TAG: ${{ github.event.release.tag_name }}
|
||||
SUFFIX: ${{ matrix.suffix }}
|
||||
FLOATING: ${{ matrix.floating }}
|
||||
run: |
|
||||
if [[ "$RELEASE_TAG" != "" ]]; then
|
||||
RELEASE="${RELEASE_TAG#v}"
|
||||
echo "versioned=${RELEASE}${SUFFIX}" >> "$GITHUB_OUTPUT"
|
||||
echo "moving=${FLOATING}" >> "$GITHUB_OUTPUT"
|
||||
else
|
||||
DATETIME=$(date +%d%m%y%H%M%S)
|
||||
BRANCH=$(echo "${GITHUB_REF#refs/heads/}" | tr "/" "-")
|
||||
echo "versioned=${DATETIME}-${BRANCH}${SUFFIX}" >> "$GITHUB_OUTPUT"
|
||||
echo "moving=${BRANCH}${SUFFIX}" >> "$GITHUB_OUTPUT"
|
||||
fi
|
||||
|
||||
- name: Build and push full
|
||||
uses: docker/build-push-action@v7
|
||||
- name: Create manifest list and push
|
||||
working-directory: /tmp/digests
|
||||
env:
|
||||
VERSIONED: ${{ steps.tags.outputs.versioned }}
|
||||
MOVING: ${{ steps.tags.outputs.moving }}
|
||||
run: |
|
||||
docker buildx imagetools create \
|
||||
-t "${DOCKERHUB_IMAGE}:${VERSIONED}" \
|
||||
-t "${DOCKERHUB_IMAGE}:${MOVING}" \
|
||||
-t "${GHCR_IMAGE}:${VERSIONED}" \
|
||||
-t "${GHCR_IMAGE}:${MOVING}" \
|
||||
$(printf "${GHCR_IMAGE}@sha256:%s " *)
|
||||
|
||||
- name: Get pushed digest
|
||||
id: digest
|
||||
env:
|
||||
VERSIONED: ${{ steps.tags.outputs.versioned }}
|
||||
run: |
|
||||
DIGEST=$(docker buildx imagetools inspect "${DOCKERHUB_IMAGE}:${VERSIONED}" \
|
||||
--format '{{json .Manifest}}' | jq -r .digest)
|
||||
echo "digest=${DIGEST}" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Attest Docker Hub image
|
||||
uses: actions/attest-build-provenance@v2
|
||||
with:
|
||||
context: .
|
||||
file: Dockerfile.full
|
||||
platforms: linux/amd64,linux/arm64,linux/arm/v7,ppc64le
|
||||
push: ${{ github.event_name != 'pull_request' }}
|
||||
tags: ${{ steps.tags.outputs.full }}
|
||||
subject-name: ${{ env.DOCKERHUB_IMAGE }}
|
||||
subject-digest: ${{ steps.digest.outputs.digest }}
|
||||
push-to-registry: false
|
||||
|
||||
- name: Attest GHCR image
|
||||
uses: actions/attest-build-provenance@v2
|
||||
with:
|
||||
subject-name: ${{ env.GHCR_IMAGE }}
|
||||
subject-digest: ${{ steps.digest.outputs.digest }}
|
||||
push-to-registry: false
|
||||
|
||||
- name: Sign images
|
||||
if: github.event_name != 'pull_request'
|
||||
env:
|
||||
TAGS_MINIMAL: ${{ steps.tags.outputs.minimal }}
|
||||
TAGS_BUSYBOX: ${{ steps.tags.outputs.busybox }}
|
||||
TAGS_FULL: ${{ steps.tags.outputs.full }}
|
||||
DIGEST: ${{ steps.digest.outputs.digest }}
|
||||
run: |
|
||||
IFS=',' read -ra TAGS <<< "$TAGS_MINIMAL,$TAGS_BUSYBOX,$TAGS_FULL"
|
||||
for tag in "${TAGS[@]}"; do
|
||||
cosign sign --yes "$tag"
|
||||
done
|
||||
cosign sign --yes "${DOCKERHUB_IMAGE}@${DIGEST}"
|
||||
cosign sign --yes "${GHCR_IMAGE}@${DIGEST}"
|
||||
|
||||
|
||||
85
.github/workflows/release-tarball.yml
vendored
Normal file
85
.github/workflows/release-tarball.yml
vendored
Normal file
@ -0,0 +1,85 @@
|
||||
name: Release source tarball
|
||||
|
||||
on:
|
||||
release:
|
||||
types: [published]
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
tarball:
|
||||
permissions:
|
||||
contents: write
|
||||
id-token: write
|
||||
attestations: write
|
||||
name: "source tarball"
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
|
||||
- name: env
|
||||
run: |
|
||||
if [ -f RELEASE ]; then
|
||||
RELEASE=$(tr -d ' \t\r\n' < RELEASE)
|
||||
else
|
||||
RELEASE=$(tr -d ' \t\r\n' < DEVEL)
|
||||
fi
|
||||
echo "RELEASE=$RELEASE" >> $GITHUB_ENV
|
||||
|
||||
- name: Create tarball
|
||||
run: |
|
||||
# git archive is reproducible from the tag: anyone can regenerate the
|
||||
# tarball and compare it against the published checksum.
|
||||
git archive --format=tar.gz -9 \
|
||||
--prefix="3proxy-${{ env.RELEASE }}/" \
|
||||
-o "3proxy-${{ env.RELEASE }}.tar.gz" HEAD
|
||||
tar tzf "3proxy-${{ env.RELEASE }}.tar.gz" >/dev/null
|
||||
ls -l *.tar.gz
|
||||
|
||||
- name: Get artifact
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: "3proxy-${{ env.RELEASE }}-src"
|
||||
path: "*.tar.gz"
|
||||
|
||||
- name: Import signing key
|
||||
if: github.event_name == 'release'
|
||||
env:
|
||||
GPG_PRIVATE_KEY: ${{ secrets.GPG_PRIVATE_KEY }}
|
||||
run: |
|
||||
if [ -z "$GPG_PRIVATE_KEY" ]; then echo "GPG_PRIVATE_KEY is not set"; exit 1; fi
|
||||
mkdir -p ~/.gnupg && chmod 700 ~/.gnupg
|
||||
printf 'allow-loopback-pinentry\n' > ~/.gnupg/gpg-agent.conf
|
||||
gpgconf --kill gpg-agent || true
|
||||
printf '%s' "$GPG_PRIVATE_KEY" | gpg --batch --import
|
||||
KEYID=$(gpg --list-secret-keys --with-colons | awk -F: '/^sec:/{print $5; exit}')
|
||||
echo "GPG_KEYID=$KEYID" >> $GITHUB_ENV
|
||||
|
||||
- name: Checksums and detached signatures
|
||||
if: github.event_name == 'release'
|
||||
env:
|
||||
GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }}
|
||||
run: |
|
||||
sha256sum *.tar.gz > SHA256SUMS-src
|
||||
for f in *.tar.gz SHA256SUMS-src; do
|
||||
gpg --batch --yes --pinentry-mode loopback --passphrase "$GPG_PASSPHRASE" \
|
||||
-u "$GPG_KEYID" --armor --detach-sign "$f"
|
||||
done
|
||||
sha256sum -c SHA256SUMS-src
|
||||
gpg --verify SHA256SUMS-src.asc SHA256SUMS-src
|
||||
|
||||
- name: Attest build provenance
|
||||
if: github.event_name == 'release'
|
||||
uses: actions/attest-build-provenance@v4
|
||||
with:
|
||||
subject-path: |
|
||||
*.tar.gz
|
||||
|
||||
- name: Upload to release
|
||||
if: github.event_name == 'release'
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
TAG: ${{ github.event.release.tag_name }}
|
||||
run: gh release upload "$TAG" *.tar.gz *.tar.gz.asc SHA256SUMS-src SHA256SUMS-src.asc
|
||||
94
.github/workflows/update-version.yml
vendored
Normal file
94
.github/workflows/update-version.yml
vendored
Normal file
@ -0,0 +1,94 @@
|
||||
name: Update version files
|
||||
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- RELEASE
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
version:
|
||||
permissions:
|
||||
contents: write
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
|
||||
- name: Regenerate version files
|
||||
run: |
|
||||
RELEASE=$(tr -d ' \t\r\n' < RELEASE)
|
||||
if [ -z "$RELEASE" ]; then echo "RELEASE is empty"; exit 1; fi
|
||||
MAJOR=$(echo "$RELEASE" | cut -d . -f 1)
|
||||
SUBMAJOR=$(echo "$RELEASE" | cut -d . -f 2)
|
||||
MINOR=$(echo "$RELEASE" | cut -d . -f 3)
|
||||
SUBMINOR=$(echo "$RELEASE" | cut -d . -f 4)
|
||||
[ -n "$SUBMAJOR" ] || SUBMAJOR=0
|
||||
[ -n "$MINOR" ] || MINOR=0
|
||||
[ -n "$SUBMINOR" ] || SUBMINOR=0
|
||||
|
||||
# The build date is minted once per release and then carried in
|
||||
# version.h, so that rebuilding the same commit yields the same
|
||||
# version string and the same package names.
|
||||
OLDRELEASE=$(sed -n 's/^#define VERSION "3proxy-\(.*\)"$/\1/p' src/version.h 2>/dev/null)
|
||||
OLDBUILDDATE=$(sed -n 's/^#define BUILDDATE "\(.*\)"$/\1/p' src/version.h 2>/dev/null)
|
||||
if [ "$OLDRELEASE" = "$RELEASE" ] && [ -n "$OLDBUILDDATE" ]; then
|
||||
BUILDDATE="$OLDBUILDDATE"
|
||||
else
|
||||
BUILDDATE=$(date -u +%y%m%d%H%M%S)
|
||||
fi
|
||||
echo "release $RELEASE -> $MAJOR $SUBMAJOR $MINOR $SUBMINOR, build date $BUILDDATE"
|
||||
SOURCE_DATE_EPOCH=$(date -u -d "20${BUILDDATE:0:2}-${BUILDDATE:2:2}-${BUILDDATE:4:2} ${BUILDDATE:6:2}:${BUILDDATE:8:2}:${BUILDDATE:10:2}" +%s)
|
||||
YEAR=$(date -u -d @$SOURCE_DATE_EPOCH +%Y)
|
||||
|
||||
DEBVERSION=$(head -1 debian/changelog | cut -d "(" -f 2 | cut -d ")" -f 1)
|
||||
if [ "$DEBVERSION" != "$RELEASE-1" ]; then
|
||||
mv debian/changelog debian/changelog.old
|
||||
{ echo "3proxy ($RELEASE-1) buster; urgency=medium"
|
||||
echo ""
|
||||
echo " *3proxy $RELEASE initial build"
|
||||
echo ""
|
||||
echo " -- z3APA3A <3apa3a@3proxy.org> $(date -R -u -d @$SOURCE_DATE_EPOCH)"
|
||||
echo ""
|
||||
cat debian/changelog.old
|
||||
} > debian/changelog
|
||||
rm -f debian/changelog.old
|
||||
fi
|
||||
|
||||
mv scripts/rh/3proxy.spec scripts/rh/3proxy.spec.old
|
||||
{ echo "Name: 3proxy"
|
||||
echo "Version: $RELEASE"
|
||||
echo "Release: 1%{?dist}"
|
||||
tail --lines=+4 scripts/rh/3proxy.spec.old
|
||||
} > scripts/rh/3proxy.spec
|
||||
rm -f scripts/rh/3proxy.spec.old
|
||||
|
||||
{ echo "#ifndef VERSION"
|
||||
echo "#define VERSION \"3proxy-$RELEASE\""
|
||||
echo "#endif"
|
||||
echo "#ifndef BUILDDATE"
|
||||
echo "#define BUILDDATE \"$BUILDDATE\""
|
||||
echo "#endif"
|
||||
echo "#define MAJOR3PROXY $MAJOR"
|
||||
echo "#define SUBMAJOR3PROXY $SUBMAJOR"
|
||||
echo "#define MINOR3PROXY $MINOR"
|
||||
echo "#define SUBMINOR3PROXY $SUBMINOR"
|
||||
echo "#define RELEASE3PROXY \"3proxy-$RELEASE(\" BUILDDATE \")\\0\""
|
||||
echo "#ifndef YEAR3PROXY"
|
||||
echo "#define YEAR3PROXY \"$YEAR\""
|
||||
echo "#endif"
|
||||
} > src/version.h
|
||||
|
||||
- name: Commit
|
||||
run: |
|
||||
if [ -z "$(git status --porcelain debian/changelog scripts/rh/3proxy.spec src/version.h)" ]; then
|
||||
echo "version files already up to date"
|
||||
exit 0
|
||||
fi
|
||||
git config user.name "github-actions[bot]"
|
||||
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
|
||||
git add debian/changelog scripts/rh/3proxy.spec src/version.h
|
||||
git commit -m "Update version files for $(tr -d ' \t\r\n' < RELEASE)"
|
||||
git push
|
||||
29
3proxy-release-key.asc
Normal file
29
3proxy-release-key.asc
Normal file
@ -0,0 +1,29 @@
|
||||
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||
|
||||
mQINBGqIZCIBEADF3zxdMo2dvUGAlQm3aIcQiqmpLMHucvLfSK3fHtwagO8f03CO
|
||||
bEx9EfIK/U6BzLwEJ0CxyClzfvgo9COVpi5EjES9sI2LXzcgc4hGaYO0Q4Unj//0
|
||||
W/G8aarDaLF2NRKMLf07eaYGBRJjqHnmeHgOHdr+SnN0JtMSadWMHoliB8esnabz
|
||||
5CO4JabTrhwoez3DMLSgJNIod7wL6PJJv/2BeRahwNr2CjaXmzZKr/j7fc1MKLij
|
||||
bsvJ5OmLmngZr6CHDa9cBhVhiH+7RgWLCsRlEGxEv7w0afp/T0xDwNAPkGzk5ObC
|
||||
BrdXvypTAbNyUoVT8qSVJwkneZ4S0Ts4rRRNfNpaus4tsCmgyGKzsrbxvbiBOTPW
|
||||
jB/fjkgr6X9M/AQ3yGpXrwXRJrM/nSfjUyOEHXttTC9HpGt41NH/mpC4mDWa1Kxi
|
||||
FMxuo1+dw2kpDKl0Bp78IGdCo5akHwftFr8aHgmfZoGXAGJRHPAWbJGjC2ARy8yp
|
||||
QOpxba0S3VlCU6bs8MDKl6cpWItnlXcl/GD/Qc55bjLXjFv1pbn2RUSYZS+n9wDX
|
||||
64syZf3dZ/N5U4ydmybWfiLFUXqKQLtdO8QAWQGt4TSwKptTmI581/MMCTQ8qWZL
|
||||
zgFj6C/8K0SZ4lMOv+5zfc2+QOoWw7E2Ws3stEKTyWjOMm/QMJAGumqvqwARAQAB
|
||||
tCozcHJveHkgcmVsZWFzZSBzaWduaW5nIDwzcHJveHlAM3Byb3h5Lm9yZz6JAm0E
|
||||
EwEIAFcWIQT8EiFEmfzHuhz/bNwDEjhOOnOUCwUCaohkIhsUgAAAAAAEAA5tYW51
|
||||
MiwyLjUrMS4xMiwwLDMCGwMFCwkIBwICIgIGFQoJCAsCBBYCAwECHgcCF4AACgkQ
|
||||
AxI4TjpzlAsCwRAAtH3OO42yCd2B8Od4yS1yBDkaIFwEm8hF68eou6uaSDkKG8YZ
|
||||
C3DUH7qk0nXEMQu/5J6RWZKlW1C8D3AkUR9A1g54o6mUg4IL5196XsrQRdVu64YF
|
||||
nLCk17Piku1lMk+Re6bZ6uJv5UlSv8d0dvxmAYzjusyPyBC2VXy7B0CoDif6AmXt
|
||||
aw2/V6m0dRrfFo4W9mJKUqTAJcdBOKzEiQb7qLnzuwy4CB5qsvnEQTqymoCXFXzg
|
||||
VDCSKRLXnbDPbIs0TvsCmthn/w1hCgftPq4W0s7EUJBOhbrjF59+AuTb+U1wIXNR
|
||||
1+DPF+V+5RlwWjOWMlsOVGk2jaxjVY8wuaD3rE6ISJkt1pRv/WVdY984rT7Eu94J
|
||||
ZHnxPjFrb2ohFKjoBCt60kbgZbuQ6yvEma5lAF9K63gwMNNyGZvq6QWl58iouzuS
|
||||
3B9t7EwGwFstJfaXVhn/rnIHoExgxVZMbbsmXiGJyE2KcfVmlZcEi0MIyqEeBSDD
|
||||
gjpE4yVO6StBtJKfXra8rMwtsbWBw9MptPhcLvdWtN6TG0CxDyTHhdL1pSLNcwX1
|
||||
CTVpwi6+WmGogcv0WFNn5caQUpu9le/v/5qLRK08KWOH8inMJmTfpJg/9869YJuF
|
||||
vDKdzJd6jug5YQRfV/7YVC2hdSOBLvBuDpRINePrj9CKJ34qG+jRSJ5xwYk=
|
||||
=IS3Y
|
||||
-----END PGP PUBLIC KEY BLOCK-----
|
||||
30
CHANGELOG
30
CHANGELOG
@ -1,18 +1,14 @@
|
||||
3proxy-0.9.9 Released August, 20 2026
|
||||
3proxy-0.9.9.1 Released October, 10 2026
|
||||
|
||||
! Fix: DNS replies are validated now: a reply from an address other than the nameserver the query was sent to, and a reply with a question section not matching the query, are dropped; both were accepted before
|
||||
! Fix: socket leak with SOCKSv5 UDP ASSOCIATE through a parent proxy, sockets were accumulated in CLOSE_WAIT state until descriptors ran out
|
||||
! Fix: file descriptor leak in HTTP proxy on the ftp:// request path
|
||||
! Fix: crash with illegal instruction on some platforms (e.g. some musl based Linux builds), caused by a memcpy on overlapping buffers
|
||||
! Fix: extip and ha (HAProxy PROXY protocol) parents are applied to SOCKSv5 UDP ASSOCIATE now
|
||||
! Fix: only socks5 and socks5+ parents are tried for UDP ASSOCIATE, other parent types can not be used for UDP
|
||||
! Fix: udppm through a SOCKSv5 parent did not work
|
||||
! Fix: -Ne and -Ni options were never applied, the option letter was not parsed; -Ne is not applied to the UDP ASSOCIATE reply anymore, -Ni is applied to it
|
||||
! Fix: -4 / -6 handling for UDP in socks; a single UDP association can use both IPv4 and IPv6 destinations now
|
||||
! Fix: a datagram with a null destination address is dropped now
|
||||
! Fix: DNS over TCP: a reply which did not fit a single read was never processed
|
||||
! Documentation: "How to apply ACLs to UDP traffic" added to HOWTO; authentication cache, ACL and UDP notes added to "Optimizing 3proxy for High Load" and to security recommendations
|
||||
+ SOCKSv5 UDP: the destination of every datagram is authorized, so ACLs limiting the destination address, host name or port apply to UDP traffic now; the parent proxy and the external address are selected for the destination of the datagram and not for the UDP ASSOCIATE request
|
||||
+ socks: -U option to control what happens when the destination changes within an UDP association: log it, authorize it, both (default) or neither
|
||||
+ -C option (for TCP services) to terminate the session as soon as any of the sides closes the connection; by default the session is kept until both sides close it (TCP half-close)
|
||||
+ timeouts: LINGER value added (11th, default 5), used to deliver buffered data after one of the sides has closed its sending side and as SO_LINGER value on outgoing connections
|
||||
! Fix: crash (segmentation fault) on configuration reload (SIGUSR1) on a busy server: a closing session could still use its service after the reload had freed it; the race existed since 0.9.7, the 5 second linger added in 0.9.9 made it much more likely (#1278)
|
||||
! Fix: -Di and -De (bind to interface) were not applied to SOCKSv5 UDP ASSOCIATE and BIND sockets, the FTP proxy data connection and connect back (#1277)
|
||||
! Fix: SOCKSv5 UDP ASSOCIATE over IPv6: the source address of a datagram was truncated and the reply was sent to the wrong address (#1279)
|
||||
! Fix: SOCKSv5 UDP ASSOCIATE: an access rule with host names matched any datagram sent to a literal address; the address is used as the host name now, as it is for TCP requests
|
||||
! Fix: buffer could be insufficient for the headers the HTTP proxy adds after a pcre_rewrite had grown the request
|
||||
! Fix: heap buffer overflow in pcre_rewrite: a $N reference to a group which did not match was written out as its digits, which the space allocated for the result did not count
|
||||
! Fix: pcre_extend did nothing, the rules it appended were never consulted
|
||||
! Fix: certificates generated for TLS MitM (openssl) carried no subject and authority key identifiers and were refused by strict verifiers, including macOS clients, OpenSSL with x509_strict and Python 3.13
|
||||
! Fix: null pointer dereference in ftppr on PASS without USER and in smtpp on a user name without a host
|
||||
! Fix: no service started with wolfSSL on glibc: the default thread stack was too small for wolfSSL thread-local storage, pthread_create() failed and the failure was not reported
|
||||
! Fix: dnspr did not work on Windows, the socket it answers from could not be bound
|
||||
- Windows binaries are no longer signed with a self-signed Authenticode certificate, it gave no trust and triggered antivirus false positives
|
||||
|
||||
@ -1,18 +1,14 @@
|
||||
3proxy-0.9.9 Вышел 20 Августа 2026
|
||||
3proxy-0.9.9.1 Вышел 10 Октября 2026
|
||||
|
||||
! Исправление: ответы DNS теперь проверяются: ответ с адреса, отличного от адреса сервера имён, которому был отправлен запрос, а также ответ с секцией вопроса, не совпадающей с запросом, отбрасываются; ранее оба принимались
|
||||
! Исправление: утечка сокетов при SOCKSv5 UDP ASSOCIATE через вышестоящий прокси, сокеты накапливались в состоянии CLOSE_WAIT до исчерпания дескрипторов
|
||||
! Исправление: утечка файловых дескрипторов в HTTP-прокси на пути обработки запроса ftp://
|
||||
! Исправление: аварийное завершение с недопустимой инструкцией на некоторых платформах (например, в некоторых сборках Linux на основе musl) из-за memcpy на перекрывающихся буферах
|
||||
! Исправление: родители типа extip и ha (HAProxy PROXY protocol) теперь применяются к SOCKSv5 UDP ASSOCIATE
|
||||
! Исправление: для UDP ASSOCIATE используются только родители socks5 и socks5+, остальные типы для UDP неприменимы
|
||||
! Исправление: udppm через вышестоящий прокси SOCKSv5 не работал
|
||||
! Исправление: опции -Ne и -Ni никогда не применялись, буква опции не разбиралась; -Ne больше не применяется к ответу на UDP ASSOCIATE, -Ni применяется к нему
|
||||
! Исправление: обработка -4 / -6 для UDP в socks; одна UDP-ассоциация теперь может использовать адреса назначения и IPv4, и IPv6
|
||||
! Исправление: датаграмма с нулевым адресом назначения теперь отбрасывается
|
||||
! Исправление: DNS поверх TCP: ответ, не помещавшийся в одно чтение, никогда не обрабатывался
|
||||
! Документация: в HOWTO добавлен раздел "Как применять ACL к UDP-трафику"; в "Optimizing 3proxy for High Load" и в рекомендации по безопасности добавлены заметки о кэше аутентификации, ACL и UDP
|
||||
+ SOCKSv5 UDP: адрес назначения каждой датаграммы авторизуется, поэтому ACL, ограничивающие адрес назначения, имя хоста или порт, теперь применяются к UDP-трафику; вышестоящий прокси и внешний адрес выбираются для адреса назначения датаграммы, а не для запроса UDP ASSOCIATE
|
||||
+ socks: опция -U для управления тем, что происходит при смене адреса назначения в рамках UDP-ассоциации: журналировать, авторизовать, и то и другое (по умолчанию) или ничего
|
||||
+ Опция -C (для TCP-сервисов) завершает сессию, как только любая из сторон закрывает соединение; по умолчанию сессия сохраняется, пока соединение не закроют обе стороны (полузакрытие TCP)
|
||||
+ timeouts: добавлено значение LINGER (11-е, по умолчанию 5), используется для доставки буферизованных данных после того, как одна из сторон закрыла свою передающую сторону, а также как значение SO_LINGER для исходящих соединений
|
||||
! Исправление: падение (segmentation fault) при перезагрузке конфигурации (SIGUSR1) на нагруженном сервере: закрывающаяся сессия могла обращаться к службе после того, как перезагрузка её освободила; гонка существовала с 0.9.7, а добавленная в 0.9.9 задержка закрытия (linger) в 5 секунд сделала её гораздо вероятнее (#1278)
|
||||
! Исправление: -Di и -De (привязка к интерфейсу) не применялись к сокетам SOCKSv5 UDP ASSOCIATE и BIND, к соединению данных FTP прокси и к обратному соединению (connect back) (#1277)
|
||||
! Исправление: SOCKSv5 UDP ASSOCIATE по IPv6: адрес отправителя датаграммы обрезался, и ответ отправлялся не на тот адрес (#1279)
|
||||
! Исправление: SOCKSv5 UDP ASSOCIATE: правило доступа с именами хостов срабатывало для любой датаграммы, отправленной на адрес, а не на имя; теперь адрес используется как имя хоста, так же как для запросов TCP
|
||||
! Исправление: буфера могло не хватить для заголовков, добавляемых HTTP прокси, после того как pcre_rewrite увеличил запрос
|
||||
! Исправление: переполнение буфера в куче в pcre_rewrite: ссылка $N на группу, не участвовавшую в совпадении, выводилась своими цифрами, которые не учитывались при выделении памяти под результат
|
||||
! Исправление: pcre_extend ничего не делал, добавленные им правила никогда не проверялись
|
||||
! Исправление: сертификаты, создаваемые для TLS MitM (openssl), не содержали идентификаторов ключа субъекта и издателя и отвергались строгой проверкой, в том числе клиентами macOS, OpenSSL с x509_strict и Python 3.13
|
||||
! Исправление: обращение по нулевому указателю в ftppr при PASS без USER и в smtpp при имени пользователя без хоста
|
||||
! Исправление: с wolfSSL на glibc не запускалась ни одна служба: стека потока по умолчанию не хватало для thread-local памяти wolfSSL, pthread_create() завершался ошибкой, о которой не сообщалось
|
||||
! Исправление: dnspr не работал в Windows, сокет, с которого он отвечает, не удавалось привязать
|
||||
- Двоичные файлы для Windows больше не подписываются самоподписанным сертификатом Authenticode: доверия он не давал и вызывал ложные срабатывания антивирусов
|
||||
|
||||
@ -52,14 +52,14 @@ ifeq ($(LIBSTATIC), true)
|
||||
STATIC_SUFFIX = -Wl,-Bdynamic
|
||||
ZLIB = -lz -lzstd
|
||||
endif
|
||||
WOLFSSL_CHECK ?= $(shell echo "\#include <wolfssl/options.h>\\n\#include <wolfssl/openssl/ssl.h>\\n int main(){return 0;}" | tr -d \\\\ | $(CC) -x c $(CFLAGS) -o testwssl.o - 2>/dev/null && $(CC) $(LDFLAGS) -otestwssl testwssl.o $(STATIC_PREFIX) -lwolfssl $(STATIC_SUFFIX) 2>/dev/null && rm testwssl testwssl.o && echo true||echo false)
|
||||
WOLFSSL_CHECK ?= $(shell printf "\#include <wolfssl/options.h>\\n\#include <wolfssl/openssl/ssl.h>\\n int main(){return 0;}" | tr -d \\\\ | $(CC) -x c $(CFLAGS) -o testwssl.o - 2>/dev/null && $(CC) $(LDFLAGS) -otestwssl testwssl.o $(STATIC_PREFIX) -lwolfssl $(STATIC_SUFFIX) 2>/dev/null && rm testwssl testwssl.o && echo true||echo false)
|
||||
ifeq ($(WOLFSSL_CHECK), true)
|
||||
LIBS += $(STATIC_PREFIX) -lwolfssl $(STATIC_SUFFIX)
|
||||
CFLAGS += -DWITH_SSL -DWITH_WOLFSSL
|
||||
SSL_OBJS = ssllib$(OBJSUFFICS) ssl$(OBJSUFFICS)
|
||||
ZLIB :=
|
||||
else
|
||||
OPENSSL_CHECK ?= $(shell echo "\#include <openssl/ssl.h>\\n int main(){return 0;}" | tr -d \\\\ | $(CC) -x c $(CFLAGS) -o testssl.o - 2>/dev/null && $(CC) $(LDFLAGS) -otestssl testssl.o $(STATIC_PREFIX) $(ZLIB) -lcrypto -lssl $(STATIC_SUFFIX) 2>/dev/null && rm testssl testssl.o && echo true||echo false)
|
||||
OPENSSL_CHECK ?= $(shell printf "\#include <openssl/ssl.h>\\n int main(){return 0;}" | tr -d \\\\ | $(CC) -x c $(CFLAGS) -o testssl.o - 2>/dev/null && $(CC) $(LDFLAGS) -otestssl testssl.o $(STATIC_PREFIX) $(ZLIB) -lcrypto -lssl $(STATIC_SUFFIX) 2>/dev/null && rm testssl testssl.o && echo true||echo false)
|
||||
ifeq ($(OPENSSL_CHECK), true)
|
||||
LIBS += $(STATIC_PREFIX) $(ZLIB) -l crypto -l ssl $(STATIC_SUFFIX)
|
||||
CFLAGS += -DWITH_SSL
|
||||
@ -68,13 +68,13 @@ else
|
||||
ZLIB :=
|
||||
endif
|
||||
endif
|
||||
PCRE_CHECK ?= $(shell echo "\#define PCRE2_CODE_UNIT_WIDTH 8\\n\#include <pcre2.h>\\n int main(){return 0;}" | tr -d \\\\ | $(CC) -x c $(CFLAGS) -o testpcre.o - 2>/dev/null && $(CC) -o testpcre testpcre.o $(LDFLAGS) -lpcre2-8 2>/dev/null && rm testpcre testpcre.o && echo true||echo false)
|
||||
PCRE_CHECK ?= $(shell printf "\#define PCRE2_CODE_UNIT_WIDTH 8\\n\#include <pcre2.h>\\n int main(){return 0;}" | tr -d \\\\ | $(CC) -x c $(CFLAGS) -o testpcre.o - 2>/dev/null && $(CC) -o testpcre testpcre.o $(LDFLAGS) -lpcre2-8 2>/dev/null && rm testpcre testpcre.o && echo true||echo false)
|
||||
ifeq ($(PCRE_CHECK), true)
|
||||
CFLAGS += -DWITH_PCRE
|
||||
PCRE_OBJS = pcre$(OBJSUFFICS)
|
||||
PCRE_LIBS = $(STATIC_PREFIX) -lpcre2-8 $(STATIC_SUFFIX)
|
||||
endif
|
||||
PAM_CHECK ?= $(shell echo "\#include <security/pam_appl.h>\\n int main(){return 0;}" | tr -d \\\\ | $(CC) -x c $(CFLAGS) -o testpam.o - 2>/dev/null && $(CC) $(LDFLAGS) -o testpam testpam.o -lpam 2>/dev/null && rm testpam testpam.o && echo true||echo false)
|
||||
PAM_CHECK ?= $(shell printf "\#include <security/pam_appl.h>\\n int main(){return 0;}" | tr -d \\\\ | $(CC) -x c $(CFLAGS) -o testpam.o - 2>/dev/null && $(CC) $(LDFLAGS) -o testpam testpam.o -lpam 2>/dev/null && rm testpam testpam.o && echo true||echo false)
|
||||
ifeq ($(PAM_CHECK), true)
|
||||
PLUGINS += PamAuth
|
||||
endif
|
||||
|
||||
@ -60,14 +60,14 @@ ifeq ($(LIBSTATIC), true)
|
||||
ZLIB = -lz -lzstd
|
||||
endif
|
||||
|
||||
WOLFSSL_CHECK ?= $(shell echo "\#include <wolfssl/options.h>\\n\#include <wolfssl/openssl/ssl.h>\\n int main(){return 0;}" | tr -d \\\\ | $(CC) -x c $(CFLAGS) -o testwssl.o - 2>/dev/null && $(CC) $(LDFLAGS) -otestwssl testwssl.o $(STATIC_PREFIX) -lwolfssl $(STATIC_SUFFIX) 2>/dev/null && rm testwssl testwssl.o && echo true||echo false)
|
||||
WOLFSSL_CHECK ?= $(shell printf "\#include <wolfssl/options.h>\\n\#include <wolfssl/openssl/ssl.h>\\n int main(){return 0;}" | tr -d \\\\ | $(CC) -x c $(CFLAGS) -o testwssl.o - 2>/dev/null && $(CC) $(LDFLAGS) -otestwssl testwssl.o $(STATIC_PREFIX) -lwolfssl $(STATIC_SUFFIX) 2>/dev/null && rm testwssl testwssl.o && echo true||echo false)
|
||||
ifeq ($(WOLFSSL_CHECK), true)
|
||||
LIBS += $(STATIC_PREFIX) -lwolfssl $(STATIC_SUFFIX)
|
||||
CFLAGS += -DWITH_SSL -DWITH_WOLFSSL
|
||||
SSL_OBJS = ssllib$(OBJSUFFICS) ssl$(OBJSUFFICS)
|
||||
ZLIB :=
|
||||
else
|
||||
OPENSSL_CHECK ?= $(shell echo "\#include <openssl/ssl.h>\\n int main(){return 0;}" | tr -d \\\\ | $(CC) -x c $(CFLAGS) -o testssl.o - 2>/dev/null && $(CC) $(LDFLAGS) -otestssl testssl.o $(STATIC_PREFIX) $(ZLIB) -lcrypto -lssl $(STATIC_SUFFIX) 2>/dev/null && rm testssl testssl.o && echo true||echo false)
|
||||
OPENSSL_CHECK ?= $(shell printf "\#include <openssl/ssl.h>\\n int main(){return 0;}" | tr -d \\\\ | $(CC) -x c $(CFLAGS) -o testssl.o - 2>/dev/null && $(CC) $(LDFLAGS) -otestssl testssl.o $(STATIC_PREFIX) $(ZLIB) -lcrypto -lssl $(STATIC_SUFFIX) 2>/dev/null && rm testssl testssl.o && echo true||echo false)
|
||||
ifeq ($(OPENSSL_CHECK), true)
|
||||
LIBS += $(STATIC_PREFIX) $(ZLIB) -lcrypto -lssl $(STATIC_SUFFIX)
|
||||
CFLAGS += -DWITH_SSL
|
||||
@ -76,13 +76,13 @@ else
|
||||
ZLIB :=
|
||||
endif
|
||||
endif
|
||||
PCRE_CHECK ?= $(shell echo "\#define PCRE2_CODE_UNIT_WIDTH 8\\n\#include <pcre2.h>\\n int main(){return 0;}" | tr -d \\\\ | $(CC) -x c $(CFLAGS) -o testpcre.o - 2>/dev/null && $(CC) -o testpcre testpcre.o $(LDFLAGS) $(STATIC_PREFIX) -lpcre2-8 $(STATIC_SUFFIX) 2>/dev/null && rm testpcre testpcre.o && echo true||echo false)
|
||||
PCRE_CHECK ?= $(shell printf "\#define PCRE2_CODE_UNIT_WIDTH 8\\n\#include <pcre2.h>\\n int main(){return 0;}" | tr -d \\\\ | $(CC) -x c $(CFLAGS) -o testpcre.o - 2>/dev/null && $(CC) -o testpcre testpcre.o $(LDFLAGS) $(STATIC_PREFIX) -lpcre2-8 $(STATIC_SUFFIX) 2>/dev/null && rm testpcre testpcre.o && echo true||echo false)
|
||||
ifeq ($(PCRE_CHECK), true)
|
||||
CFLAGS += -DWITH_PCRE
|
||||
PCRE_OBJS = pcre$(OBJSUFFICS)
|
||||
PCRE_LIBS = $(STATIC_PREFIX) -lpcre2-8 $(STATIC_SUFFIX)
|
||||
endif
|
||||
PAM_CHECK ?= $(shell echo "\#include <security/pam_appl.h>\\n int main(){return 0;}" | tr -d \\\\ | $(CC) -x c $(CFLAGS) -o testpam.o - 2>/dev/null && $(CC) $(LDFLAGS) -o testpam testpam.o -lpam 2>/dev/null && rm testpam testpam.o && echo true||echo false)
|
||||
PAM_CHECK ?= $(shell printf "\#include <security/pam_appl.h>\\n int main(){return 0;}" | tr -d \\\\ | $(CC) -x c $(CFLAGS) -o testpam.o - 2>/dev/null && $(CC) $(LDFLAGS) -o testpam testpam.o -lpam 2>/dev/null && rm testpam testpam.o && echo true||echo false)
|
||||
ifeq ($(PAM_CHECK), true)
|
||||
PLUGINS += PamAuth
|
||||
endif
|
||||
|
||||
@ -31,20 +31,20 @@ COMPATLIBS =
|
||||
MAKEFILE = Makefile.Solaris
|
||||
PLUGINS = StringsPlugin TrafficPlugin TransparentPlugin FilePlugin
|
||||
|
||||
WOLFSSL_CHECK = $(shell echo "\#include <wolfssl/options.h>\\n\#include <wolfssl/openssl/ssl.h>\\n int main(){return 0;}" | tr -d \\\\ | $(CC) -x c $(CFLAGS) -o testwssl.o - 2>/dev/null && $(CC) $(LDFLAGS) -o testwssl testwssl.o -lwolfssl 2>/dev/null && rm testwssl testwssl.o && echo true||echo false)
|
||||
WOLFSSL_CHECK = $(shell printf "\#include <wolfssl/options.h>\\n\#include <wolfssl/openssl/ssl.h>\\n int main(){return 0;}" | tr -d \\\\ | $(CC) -x c $(CFLAGS) -o testwssl.o - 2>/dev/null && $(CC) $(LDFLAGS) -o testwssl testwssl.o -lwolfssl 2>/dev/null && rm testwssl testwssl.o && echo true||echo false)
|
||||
ifeq ($(WOLFSSL_CHECK), true)
|
||||
LIBS += -lwolfssl
|
||||
CFLAGS += -DWITH_SSL -DWITH_WOLFSSL
|
||||
SSL_OBJS = ssllib$(OBJSUFFICS) ssl$(OBJSUFFICS)
|
||||
else
|
||||
OPENSSL_CHECK = $(shell echo "\#include <openssl/ssl.h>\\n int main(){return 0;}" | tr -d \\\\ | $(CC) -x c $(CFLAGS) -o testssl.o - 2>/dev/null && $(CC) $(LDFLAGS) -o testssl testssl.o -lcrypto -lssl 2>/dev/null && rm testssl testssl.o && echo true||echo false)
|
||||
OPENSSL_CHECK = $(shell printf "\#include <openssl/ssl.h>\\n int main(){return 0;}" | tr -d \\\\ | $(CC) -x c $(CFLAGS) -o testssl.o - 2>/dev/null && $(CC) $(LDFLAGS) -o testssl testssl.o -lcrypto -lssl 2>/dev/null && rm testssl testssl.o && echo true||echo false)
|
||||
ifeq ($(OPENSSL_CHECK), true)
|
||||
LIBS += -l crypto -l ssl
|
||||
CFLAGS += -DWITH_SSL
|
||||
SSL_OBJS = ssllib$(OBJSUFFICS) ssl$(OBJSUFFICS)
|
||||
endif
|
||||
endif
|
||||
PCRE_CHECK = $(shell echo "\#define PCRE2_CODE_UNIT_WIDTH 8\\n\#include <pcre2.h>\\n int main(){return 0;}" | tr -d \\\\ | $(CC) -x c $(CFLAGS) -o testpcre.o - 2>/dev/null && $(CC) -o testpcre testpcre.o $(LDFLAGS) -Wl,-Bstatic -lpcre2-8 -Wl,-Bdynamic 2>/dev/null && rm testpcre testpcre.o && echo true||echo false)
|
||||
PCRE_CHECK = $(shell printf "\#define PCRE2_CODE_UNIT_WIDTH 8\\n\#include <pcre2.h>\\n int main(){return 0;}" | tr -d \\\\ | $(CC) -x c $(CFLAGS) -o testpcre.o - 2>/dev/null && $(CC) -o testpcre testpcre.o $(LDFLAGS) -Wl,-Bstatic -lpcre2-8 -Wl,-Bdynamic 2>/dev/null && rm testpcre testpcre.o && echo true||echo false)
|
||||
ifeq ($(PCRE_CHECK), true)
|
||||
CFLAGS += -DWITH_PCRE
|
||||
PCRE_OBJS = pcre$(OBJSUFFICS)
|
||||
|
||||
@ -54,14 +54,14 @@ ifeq ($(LIBSTATIC), true)
|
||||
STATIC_SUFFIX = -Wl,-Bdynamic
|
||||
ZLIB = -lz -lzstd
|
||||
endif
|
||||
WOLFSSL_CHECK ?= $(shell echo "\#include <wolfssl/options.h>\\n\#include <wolfssl/openssl/ssl.h>\\n int main(){return 0;}" | tr -d \\\\ | $(CC) -x c $(CFLAGS) -o testwssl.o - 2>/dev/null && $(CC) $(LDFLAGS) -otestwssl testwssl.o $(STATIC_PREFIX) -lwolfssl $(STATIC_SUFFIX) 2>/dev/null && rm testwssl testwssl.o && echo true||echo false)
|
||||
WOLFSSL_CHECK ?= $(shell printf "\#include <wolfssl/options.h>\\n\#include <wolfssl/openssl/ssl.h>\\n int main(){return 0;}" | tr -d \\\\ | $(CC) -x c $(CFLAGS) -o testwssl.o - 2>/dev/null && $(CC) $(LDFLAGS) -otestwssl testwssl.o $(STATIC_PREFIX) -lwolfssl $(STATIC_SUFFIX) 2>/dev/null && rm testwssl testwssl.o && echo true||echo false)
|
||||
ifeq ($(WOLFSSL_CHECK), true)
|
||||
LIBS += $(STATIC_PREFIX) -lwolfssl $(STATIC_SUFFIX)
|
||||
CFLAGS += -DWITH_SSL -DWITH_WOLFSSL
|
||||
SSL_OBJS = ssllib$(OBJSUFFICS) ssl$(OBJSUFFICS)
|
||||
ZLIB :=
|
||||
else
|
||||
OPENSSL_CHECK ?= $(shell echo "\#include <openssl/ssl.h>\\n int main(){return 0;}" | tr -d \\\\ | $(CC) -x c $(CFLAGS) -o testssl.o - 2>/dev/null && $(CC) $(LDFLAGS) -otestssl testssl.o $(STATIC_PREFIX) $(ZLIB) -lcrypto -lssl $(STATIC_SUFFIX) 2>/dev/null && rm testssl testssl.o && echo true||echo false)
|
||||
OPENSSL_CHECK ?= $(shell printf "\#include <openssl/ssl.h>\\n int main(){return 0;}" | tr -d \\\\ | $(CC) -x c $(CFLAGS) -o testssl.o - 2>/dev/null && $(CC) $(LDFLAGS) -otestssl testssl.o $(STATIC_PREFIX) $(ZLIB) -lcrypto -lssl $(STATIC_SUFFIX) 2>/dev/null && rm testssl testssl.o && echo true||echo false)
|
||||
ifeq ($(OPENSSL_CHECK), true)
|
||||
LIBS += $(STATIC_PREFIX) $(ZLIB) -lcrypto -lssl $(STATIC_SUFFIX)
|
||||
CFLAGS += -DWITH_SSL
|
||||
@ -70,13 +70,13 @@ else
|
||||
ZLIB :=
|
||||
endif
|
||||
endif
|
||||
PCRE_CHECK ?= $(shell echo "\#define PCRE2_CODE_UNIT_WIDTH 8\\n\#include <pcre2.h>\\n int main(){return 0;}" | tr -d \\\\ | $(CC) -x c $(CFLAGS) -o testpcre.o - 2>/dev/null && $(CC) -o testpcre testpcre.o $(LDFLAGS) $(STATIC_PREFIX) -lpcre2-8 $(STATIC_SUFFIX) 2>/dev/null && rm testpcre testpcre.o && echo true||echo false)
|
||||
PCRE_CHECK ?= $(shell printf "\#define PCRE2_CODE_UNIT_WIDTH 8\\n\#include <pcre2.h>\\n int main(){return 0;}" | tr -d \\\\ | $(CC) -x c $(CFLAGS) -o testpcre.o - 2>/dev/null && $(CC) -o testpcre testpcre.o $(LDFLAGS) $(STATIC_PREFIX) -lpcre2-8 $(STATIC_SUFFIX) 2>/dev/null && rm testpcre testpcre.o && echo true||echo false)
|
||||
ifeq ($(PCRE_CHECK), true)
|
||||
CFLAGS += -DWITH_PCRE
|
||||
PCRE_OBJS = pcre$(OBJSUFFICS)
|
||||
PCRE_LIBS = $(STATIC_PREFIX) -lpcre2-8 $(STATIC_SUFFIX)
|
||||
endif
|
||||
PAM_CHECK ?= $(shell echo "\#include <security/pam_appl.h>\\n int main(){return 0;}" | tr -d \\\\ | $(CC) -x c $(CFLAGS) -o testpam.o - 2>/dev/null && $(CC) $(LDFLAGS) -o testpam testpam.o -lpam 2>/dev/null && rm testpam testpam.o && echo true||echo false)
|
||||
PAM_CHECK ?= $(shell printf "\#include <security/pam_appl.h>\\n int main(){return 0;}" | tr -d \\\\ | $(CC) -x c $(CFLAGS) -o testpam.o - 2>/dev/null && $(CC) $(LDFLAGS) -o testpam testpam.o -lpam 2>/dev/null && rm testpam testpam.o && echo true||echo false)
|
||||
ifeq ($(PAM_CHECK), true)
|
||||
PLUGINS += PamAuth
|
||||
endif
|
||||
|
||||
@ -47,14 +47,14 @@ ifeq ($(LIBSTATIC), true)
|
||||
STATIC_SUFFIX = -Wl,-Bdynamic
|
||||
ZLIB = -lz
|
||||
endif
|
||||
WOLFSSL_CHECK = $(shell echo "\#include <wolfssl/options.h>\\n\#include <wolfssl/openssl/ssl.h>\\n int main(){return 0;}" | tr -d '\\\\' | $(CC) -x c $(CFLAGS) $(LDFLAGS) $(STATIC_PREFIX) -lwolfssl $(STATIC_SUFFIX) -o testwssl - 2>/dev/null && rm testwssl && echo true||echo false)
|
||||
WOLFSSL_CHECK = $(shell printf "\#include <wolfssl/options.h>\\n\#include <wolfssl/openssl/ssl.h>\\n int main(){return 0;}" | tr -d '\\\\' | $(CC) -x c $(CFLAGS) $(LDFLAGS) $(STATIC_PREFIX) -lwolfssl $(STATIC_SUFFIX) -o testwssl - 2>/dev/null && rm testwssl && echo true||echo false)
|
||||
ifeq ($(WOLFSSL_CHECK), true)
|
||||
LIBS += $(STATIC_PREFIX) -lwolfssl $(STATIC_SUFFIX) -lws2_32
|
||||
CFLAGS += -DWITH_SSL -DWITH_WOLFSSL
|
||||
SSL_OBJS = ssllib$(OBJSUFFICS) ssl$(OBJSUFFICS)
|
||||
ZLIB :=
|
||||
else
|
||||
OPENSSL_CHECK = $(shell echo "\#include <openssl/ssl.h>\\n int main(){return 0;}" | tr -d '\\\\' | $(CC) -x c $(CFLAGS) $(LDFLAGS) $(STATIC_PREFIX) $(ZLIB) -l crypto -l ssl $(STATIC_SUFFIX) -o testssl - 2>/dev/null && rm testssl && echo true||echo false)
|
||||
OPENSSL_CHECK = $(shell printf "\#include <openssl/ssl.h>\\n int main(){return 0;}" | tr -d '\\\\' | $(CC) -x c $(CFLAGS) $(LDFLAGS) $(STATIC_PREFIX) $(ZLIB) -l crypto -l ssl $(STATIC_SUFFIX) -o testssl - 2>/dev/null && rm testssl && echo true||echo false)
|
||||
ifeq ($(OPENSSL_CHECK), true)
|
||||
LIBS += $(STATIC_PREFIX) $(ZLIB) -l crypto -l ssl $(STATIC_SUFFIX) -lcrypt32
|
||||
CFLAGS += -DWITH_SSL
|
||||
@ -63,11 +63,11 @@ else
|
||||
ZLIB :=
|
||||
endif
|
||||
endif
|
||||
PAM_CHECK = $(shell echo "\#include <security/pam_appl.h>\\n int main(){return 0;}" | tr -d '\\\\' | $(CC) -x c $(CFLAGS) $(LDFLAGS) -l pam -o testpam - 2>/dev/null && rm testpam && echo true||echo false)
|
||||
PAM_CHECK = $(shell printf "\#include <security/pam_appl.h>\\n int main(){return 0;}" | tr -d '\\\\' | $(CC) -x c $(CFLAGS) $(LDFLAGS) -l pam -o testpam - 2>/dev/null && rm testpam && echo true||echo false)
|
||||
ifeq ($(PAM_CHECK), true)
|
||||
PLUGINS += PamAuth
|
||||
endif
|
||||
PCRE_CHECK = $(shell echo "\#define PCRE2_CODE_UNIT_WIDTH 8\\n#include <pcre2.h>\\n int main(){return 0;}" | tr -d '\\\\' | $(CC) -x c $(CFLAGS) $(LDFLAGS) $(STATIC_PREFIX) -lpcre2-8 $(STATIC_SUFFIX) -o testpcre - 2>/dev/null && rm testpcre && echo true||echo false)
|
||||
PCRE_CHECK = $(shell printf "\#define PCRE2_CODE_UNIT_WIDTH 8\\n#include <pcre2.h>\\n int main(){return 0;}" | tr -d '\\\\' | $(CC) -x c $(CFLAGS) $(LDFLAGS) $(STATIC_PREFIX) -lpcre2-8 $(STATIC_SUFFIX) -o testpcre - 2>/dev/null && rm testpcre && echo true||echo false)
|
||||
ifeq ($(PCRE_CHECK), true)
|
||||
CFLAGS += -DWITH_PCRE
|
||||
PCRE_OBJS = pcre$(OBJSUFFICS)
|
||||
|
||||
59
README.md
59
README.md
@ -6,13 +6,52 @@
|
||||
|
||||
### Branches
|
||||
|
||||
- **Master** (stable) branch - 3proxy 0.9
|
||||
- **Devel** branch - 3proxy 10 (don't use it)
|
||||
- **Master** (stable) branch - 3proxy 1.0
|
||||
- **0.9** (LTS) branch - 3proxy 0.9 maintenance branch, this branch
|
||||
- **Devel** branch - 3proxy 2.0-devel (don't use it)
|
||||
|
||||
### Binaries (deb / rpm / Windows zip)
|
||||
|
||||
https://github.com/3proxy/3proxy/releases
|
||||
|
||||
### Package repository (apt / dnf)
|
||||
|
||||
Signed apt and dnf repositories are published at https://3proxy.org/repo/ in
|
||||
two channels: `lts` (0.9 branch) and `current` (master).
|
||||
|
||||
Debian 12 and Ubuntu 22.04 or newer:
|
||||
|
||||
```
|
||||
sudo curl -fsSL https://3proxy.org/repo/3proxy-release-key.asc \
|
||||
-o /usr/share/keyrings/3proxy.asc
|
||||
sudo tee /etc/apt/sources.list.d/3proxy.sources <<EOF
|
||||
Types: deb
|
||||
URIs: https://3proxy.org/repo/deb
|
||||
Suites: lts
|
||||
Components: main
|
||||
Signed-By: /usr/share/keyrings/3proxy.asc
|
||||
EOF
|
||||
sudo apt update && sudo apt install 3proxy
|
||||
```
|
||||
|
||||
AlmaLinux, RHEL, Rocky and CentOS Stream 8, 9 and 10:
|
||||
|
||||
```
|
||||
sudo tee /etc/yum.repos.d/3proxy.repo <<EOF
|
||||
[3proxy]
|
||||
name=3proxy
|
||||
baseurl=https://3proxy.org/repo/rpm/lts/el\$releasever/\$basearch/
|
||||
enabled=1
|
||||
gpgcheck=1
|
||||
repo_gpgcheck=1
|
||||
gpgkey=https://3proxy.org/repo/3proxy-release-key.asc
|
||||
EOF
|
||||
sudo dnf install 3proxy
|
||||
```
|
||||
|
||||
Both the packages and the repository metadata are signed. See
|
||||
https://3proxy.org/repo/ for the `current` channel and for release key details.
|
||||
|
||||
### Docker images
|
||||
|
||||
https://hub.docker.com/r/3proxy/3proxy
|
||||
@ -29,9 +68,9 @@ Documentation (man pages and HTML) available with download, on https://3proxy.or
|
||||
|
||||
## Docker images
|
||||
|
||||
3 docker configurations are provided, default (full) also tagged as `:latest`, `:busybox` and `:minimal`, all refer to newest stable version. Except busybox, images are distroless and contain only binaries, you can not sh inside the container. `:busybox` contains busybox shell.
|
||||
3 docker configurations are provided, default (full) also tagged as `:lts`, `:lts-busybox` and `:lts-minimal`, all refer to newest 0.9 LTS version. Images built from this branch use the `lts` tags, images built from the master branch use `:latest`, `:busybox` and `:minimal`. Use the `lts` tags to stay on the 0.9 branch, use a version tag (e.g. `:0.9.9`) to pin an exact version. Except busybox, images are distroless and contain only binaries, you can not sh inside the container. `:lts-busybox` contains busybox shell.
|
||||
|
||||
### Default image (`:latest`):
|
||||
### Default image (`:lts`):
|
||||
|
||||
Full installation requires to mount /etc/3proxy/3proxy.cfg files.
|
||||
|
||||
@ -42,7 +81,7 @@ echo "log
|
||||
nserver 8.8.8.8
|
||||
nscache 65536
|
||||
proxy -p3129" | docker config create 3proxy
|
||||
docker run --read-only -p 3129:3129 --config source=3proxy,target=/etc/3proxy/3proxy.cfg --name 3proxy.full docker.io/3proxy/3proxy
|
||||
docker run --read-only -p 3129:3129 --config source=3proxy,target=/etc/3proxy/3proxy.cfg --name 3proxy.full docker.io/3proxy/3proxy:lts
|
||||
```
|
||||
|
||||
`podman` does not support `config` as above.
|
||||
@ -60,13 +99,13 @@ podman run --read-only -p 3129:3129 -v /path/to/local/config/directory/3proxy.cf
|
||||
use `log` without pathname in config to log to stdout.
|
||||
plugins are located in /usr/local/3proxy/libexec (/libexec for chroot config) and since 0.9.6 symlinked by /lib and /lib64 in both chroot and non-chroot configurations, so no full path is required in `plugin` command. Use e.g. `plugin SSLPlugin.ls.so ssl_plugin`. SSLPlugin is supported since 0.9.6. Some proxy types (e.g. SOCKSv5 UDPASSCOC, SOCKSv5 BIND functionality, ftp proxy) require access to ephemeral port, you may use e.g. -`-network host` mode or `-P` for `docker run`.
|
||||
|
||||
since 0.9.6 images are distroless (except :busybox) it's recommended to use with read only file system, there are no benefits from chroot. For compatibility, you still can use chroot installation by mounting directory with 3proxy.cfg to /usr/local/3proxy/config.
|
||||
since 0.9.6 images are distroless (except :lts-busybox) it's recommended to use with read only file system, there are no benefits from chroot. For compatibility, you still can use chroot installation by mounting directory with 3proxy.cfg to /usr/local/3proxy/config.
|
||||
|
||||
### Busybox image (`:busybox`):
|
||||
### Busybox image (`:lts-busybox`):
|
||||
|
||||
`full` with busybox added, to allow `sh` and few more commands like `sed` inside container. All libraries are in /lib, so chroot configuration can not use plugins.
|
||||
|
||||
### Interactive `:minimal` image:
|
||||
### Interactive `:lts-minimal` image:
|
||||
|
||||
Dockerfile for "interactive" minimal 3proxy execution, no configuration mounting is required, configuration
|
||||
is accepted from stdin. Use `end` command to indicate the end of configuration. Use `log` for stdout logging.
|
||||
@ -76,7 +115,7 @@ since 0.9.6 images are distroless (except :busybox) it's recommended to use with
|
||||
|
||||
Run example:
|
||||
|
||||
`docker run --read-only -i -p 3129:3129 --name 3proxy docker.io/3proxy/3proxy:minimal`
|
||||
`docker run --read-only -i -p 3129:3129 --name 3proxy docker.io/3proxy/3proxy:lts-minimal`
|
||||
or
|
||||
`docker start -ai 3proxy` to start existing container
|
||||
|
||||
@ -92,7 +131,7 @@ end
|
||||
|
||||
Some proxy types (e.g. SOCKSv5 UDPASSCOC, SOCKSv5 BIND functionality, ftp proxy) require access to ephemeral port, you may use e.g. `--network host` mode or `-P` to `docker run`.
|
||||
|
||||
`:minimal` without version specified uses current stable version.
|
||||
`:lts-minimal` without version specified uses current 0.9 LTS version.
|
||||
|
||||
## Building and installation
|
||||
|
||||
|
||||
60
SECURITY.md
60
SECURITY.md
@ -12,3 +12,63 @@
|
||||
Report to 3proxy@3proxy.org or via [GitHub security reporting](https://github.com/3proxy/3proxy/security)
|
||||
|
||||
For High/Critical patched version is released within 2 weeks
|
||||
|
||||
## Verifying downloads
|
||||
|
||||
Release binaries and the source tarball are published with SHA256 checksums, an
|
||||
OpenPGP signature and a GitHub build provenance attestation.
|
||||
|
||||
The release signing key is `3proxy-release-key.asc` in the root of this
|
||||
repository, an RSA-4096 key:
|
||||
|
||||
```
|
||||
pub rsa4096 2026-08-21 [SC]
|
||||
FC12 2144 99FC C7BA 1CFF 6CDC 0312 384E 3A73 940B
|
||||
uid 3proxy release signing <3proxy@3proxy.org>
|
||||
```
|
||||
|
||||
Import it once:
|
||||
|
||||
```
|
||||
gpg --import 3proxy-release-key.asc
|
||||
```
|
||||
|
||||
Checksums and the checksum file signature:
|
||||
|
||||
```
|
||||
gpg --verify SHA256SUMS-x86_64.asc SHA256SUMS-x86_64
|
||||
sha256sum -c SHA256SUMS-x86_64
|
||||
```
|
||||
|
||||
The source tarball published with each release is signed as well:
|
||||
|
||||
```
|
||||
gpg --verify SHA256SUMS-src.asc SHA256SUMS-src
|
||||
sha256sum -c SHA256SUMS-src
|
||||
gpg --verify 3proxy-0.9.9.tar.gz.asc 3proxy-0.9.9.tar.gz
|
||||
```
|
||||
|
||||
Prefer it over the `Source code (tar.gz)` link GitHub generates automatically:
|
||||
only the published tarball is signed. It is produced with `git archive` from
|
||||
the release tag, so it can be regenerated and compared byte for byte.
|
||||
|
||||
RPM packages are signed, the signature is checked by rpm itself:
|
||||
|
||||
```
|
||||
sudo rpm --import 3proxy-release-key.asc
|
||||
rpm -K 3proxy-0.9.9.x86_64.rpm
|
||||
```
|
||||
|
||||
DEB packages are published with a detached signature:
|
||||
|
||||
```
|
||||
gpg --verify 3proxy-0.9.9.x86_64.deb.asc 3proxy-0.9.9.x86_64.deb
|
||||
```
|
||||
|
||||
Build provenance (which workflow, commit and runner produced the file) is
|
||||
verified with the GitHub CLI:
|
||||
|
||||
```
|
||||
gh attestation verify 3proxy-0.9.9.x86_64.rpm --owner 3proxy
|
||||
gh attestation verify oci://docker.io/3proxy/3proxy:lts --owner 3proxy
|
||||
```
|
||||
|
||||
12
debian/changelog
vendored
12
debian/changelog
vendored
@ -1,3 +1,15 @@
|
||||
3proxy (0.9.9.1-1) buster; urgency=medium
|
||||
|
||||
*3proxy 0.9.9.1 initial build
|
||||
|
||||
-- z3APA3A <3apa3a@3proxy.org> Sat, 10 Oct 2026 16:57:17 +0000
|
||||
|
||||
3proxy (0.9.9.0-1) buster; urgency=medium
|
||||
|
||||
*3proxy 0.9.9.0 initial build
|
||||
|
||||
-- z3APA3A <3apa3a@3proxy.org> Thu, 20 Aug 2026 19:12:35 +0300
|
||||
|
||||
3proxy (0.9.9-1) buster; urgency=medium
|
||||
|
||||
*3proxy 0.9.9 initial build
|
||||
|
||||
12
doc/changelog/0/9/9/1
Normal file
12
doc/changelog/0/9/9/1
Normal file
@ -0,0 +1,12 @@
|
||||
! Fix: crash (segmentation fault) on configuration reload (SIGUSR1) on a busy server: a closing session could still use its service after the reload had freed it; the race existed since 0.9.7, the 5 second linger added in 0.9.9 made it much more likely (#1278)
|
||||
! Fix: -Di and -De (bind to interface) were not applied to SOCKSv5 UDP ASSOCIATE and BIND sockets, the FTP proxy data connection and connect back (#1277)
|
||||
! Fix: SOCKSv5 UDP ASSOCIATE over IPv6: the source address of a datagram was truncated and the reply was sent to the wrong address (#1279)
|
||||
! Fix: SOCKSv5 UDP ASSOCIATE: an access rule with host names matched any datagram sent to a literal address; the address is used as the host name now, as it is for TCP requests
|
||||
! Fix: buffer could be insufficient for the headers the HTTP proxy adds after a pcre_rewrite had grown the request
|
||||
! Fix: heap buffer overflow in pcre_rewrite: a $N reference to a group which did not match was written out as its digits, which the space allocated for the result did not count
|
||||
! Fix: pcre_extend did nothing, the rules it appended were never consulted
|
||||
! Fix: certificates generated for TLS MitM (openssl) carried no subject and authority key identifiers and were refused by strict verifiers, including macOS clients, OpenSSL with x509_strict and Python 3.13
|
||||
! Fix: null pointer dereference in ftppr on PASS without USER and in smtpp on a user name without a host
|
||||
! Fix: no service started with wolfSSL on glibc: the default thread stack was too small for wolfSSL thread-local storage, pthread_create() failed and the failure was not reported
|
||||
! Fix: dnspr did not work on Windows, the socket it answers from could not be bound
|
||||
- Windows binaries are no longer signed with a self-signed Authenticode certificate, it gave no trust and triggered antivirus false positives
|
||||
@ -1471,10 +1471,12 @@ allowed traffic in megabytes (MB). nocountin allows you to set exclusions.
|
||||
For name resolution and caching, use the commands nserver, nscache / nscache6, and nsrecord.
|
||||
<pre>
|
||||
nserver 192.168.1.2
|
||||
nserver 192.168.1.3:5353/tcp</pre>
|
||||
nserver 192.168.1.3:5353/tcp
|
||||
nserver [2001:4860:4860::8844]</pre>
|
||||
sets DNS resolvers. 192.168.1.3 will be used via TCP/5353 (instead of default UDP/53)
|
||||
only if 192.168.1.2 fails. Up to 5 nservers may be specified.
|
||||
If no nserver is configured, default system name resolution functions are used.
|
||||
An IPv6 address has to be written in square brackets.
|
||||
<pre>
|
||||
nscache 65535
|
||||
nscache6 65535</pre>
|
||||
|
||||
@ -1536,11 +1536,13 @@ socks -p1080
|
||||
nscache и nsrecord.
|
||||
<pre>
|
||||
nserver 192.168.1.2
|
||||
nserver 192.168.1.3:5353/tcp</pre>
|
||||
nserver 192.168.1.3:5353/tcp
|
||||
nserver [2001:4860:4860::8844]</pre>
|
||||
указывает 3proxy какие машины следует использвоать в качестве серверов
|
||||
DNS. Сервер 192.168.1.3 будет использоваться по порту TCP/5353 (вместо дефолтного UDP/53) только при недостижимости
|
||||
192.168.1.2. Можно указать до 5 серверов. Если nserver не указан, будут
|
||||
использованы системные функции разрешения имен.
|
||||
Адрес IPv6 необходимо записывать в квадратных скобках.
|
||||
<pre>
|
||||
nscache 65535
|
||||
nscache6 65535</pre>
|
||||
|
||||
@ -489,7 +489,11 @@ experimental.</p>
|
||||
Nameserver to use for name resolutions. If none specified
|
||||
system routines for name resolution is used. Optional port
|
||||
number may be specified. If optional /tcp is added to IP
|
||||
address, name resolution is performed over TCP.</p>
|
||||
address, name resolution is performed over TCP. An IPv6 address
|
||||
has to be enclosed in square brackets: <br>
|
||||
<b>nserver 1.1.1.1</b> <br>
|
||||
<b>nserver [2001:4860:4860::8844]</b> <br>
|
||||
<b>nserver [2001:4860:4860::8844]:5353/tcp</b></p>
|
||||
|
||||
|
||||
<p style="margin-left:6%; margin-top: 1em"><b>authnserver</b>
|
||||
|
||||
@ -514,6 +514,13 @@ system routines for name resolution is
|
||||
used. Optional port number may be specified.
|
||||
If optional /tcp is added to IP address, name resolution is
|
||||
performed over TCP.
|
||||
An IPv6 address has to be enclosed in square brackets:
|
||||
.br
|
||||
\fBnserver 1.1.1.1\fR
|
||||
.br
|
||||
\fBnserver [2001:4860:4860::8844]\fR
|
||||
.br
|
||||
\fBnserver [2001:4860:4860::8844]:5353/tcp\fR
|
||||
|
||||
.br
|
||||
.BR authnserver
|
||||
|
||||
66
scripts/openwrt/Makefile
Normal file
66
scripts/openwrt/Makefile
Normal file
@ -0,0 +1,66 @@
|
||||
#
|
||||
# Copyright (C) 2026 3proxy.org
|
||||
#
|
||||
# This is free software, licensed under the BSD 3-Clause License.
|
||||
#
|
||||
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=3proxy
|
||||
PKG_VERSION:=0.9.9.0
|
||||
PKG_RELEASE:=1
|
||||
|
||||
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
|
||||
# A trailing ? tells the download helper the URL is complete and PKG_SOURCE
|
||||
# must not be appended to it.
|
||||
PKG_SOURCE_URL:=https://codeload.github.com/3proxy/3proxy/tar.gz/refs/tags/$(PKG_VERSION)?
|
||||
PKG_HASH:=5af253fa734f61af6d5fe3790022130a14caf25bfce24a6aefd415797d351dd3
|
||||
|
||||
PKG_MAINTAINER:=Vladimir Dubrovin <vlad@3proxy.org>
|
||||
PKG_LICENSE:=BSD-3-Clause
|
||||
PKG_LICENSE_FILES:=copying
|
||||
PKG_CPE_ID:=cpe:/a:3proxy:3proxy
|
||||
|
||||
PKG_BUILD_PARALLEL:=1
|
||||
|
||||
include $(INCLUDE_DIR)/package.mk
|
||||
|
||||
define Package/3proxy
|
||||
SECTION:=net
|
||||
CATEGORY:=Network
|
||||
SUBMENU:=Web Servers/Proxies
|
||||
TITLE:=tiny free proxy server
|
||||
URL:=https://3proxy.org/
|
||||
DEPENDS:=+libopenssl +libpcre2
|
||||
endef
|
||||
|
||||
define Package/3proxy/description
|
||||
3proxy is a tiny free proxy server supporting HTTP, HTTPS, FTP, SOCKS v4/v4a/v5,
|
||||
POP3, SMTP, IMAP, TCP and UDP port mapping, with access control, bandwidth
|
||||
limiting and traffic accounting.
|
||||
endef
|
||||
|
||||
define Package/3proxy/conffiles
|
||||
/etc/config/3proxy
|
||||
endef
|
||||
|
||||
# Makefile.Linux appends to CFLAGS and LDFLAGS internally; the target flags have
|
||||
# to be added rather than substituted, or the defines it relies on are lost.
|
||||
define Build/Compile
|
||||
$(MAKE) -C $(PKG_BUILD_DIR) -f Makefile.Linux \
|
||||
CC="$(TARGET_CC)" \
|
||||
EXTRA_CFLAGS="$(TARGET_CFLAGS) $(TARGET_CPPFLAGS)" \
|
||||
EXTRA_LDFLAGS="$(TARGET_LDFLAGS)" \
|
||||
PLUGINS=
|
||||
endef
|
||||
|
||||
define Package/3proxy/install
|
||||
$(INSTALL_DIR) $(1)/usr/bin
|
||||
$(INSTALL_BIN) $(PKG_BUILD_DIR)/bin/3proxy $(1)/usr/bin/3proxy
|
||||
$(INSTALL_DIR) $(1)/etc/config
|
||||
$(INSTALL_CONF) ./files/3proxy.config $(1)/etc/config/3proxy
|
||||
$(INSTALL_DIR) $(1)/etc/init.d
|
||||
$(INSTALL_BIN) ./files/3proxy.init $(1)/etc/init.d/3proxy
|
||||
endef
|
||||
|
||||
$(eval $(call BuildPackage,3proxy))
|
||||
59
scripts/openwrt/files/3proxy.config
Normal file
59
scripts/openwrt/files/3proxy.config
Normal file
@ -0,0 +1,59 @@
|
||||
config 3proxy 'global'
|
||||
option enabled '0'
|
||||
option nscache '65536'
|
||||
# option nscache6 '65536'
|
||||
# static records, added to the cache; 0.0.0.0 blackholes a name
|
||||
# list nsrecord 'ads.example.com 0.0.0.0'
|
||||
option maxconn '128'
|
||||
option auth 'iponly'
|
||||
option log 'syslog'
|
||||
# option timeouts '1 5 30 60 180 1800 15 60 15 5 5'
|
||||
# list include '/etc/3proxy/extra.cfg'
|
||||
list nserver '8.8.8.8'
|
||||
list nserver '8.8.4.4'
|
||||
# list user 'admin:CL:password'
|
||||
# list extra_config 'timeouts 1 5 30 60 180 1800 15 60'
|
||||
# access list used by services which do not define their own
|
||||
list acl 'lan'
|
||||
|
||||
# Access rules are named sections referenced by services. The order of the
|
||||
# references decides precedence: 3proxy stops at the first rule that matches.
|
||||
config acl 'lan'
|
||||
option action 'allow'
|
||||
option src '192.168.1.0/24'
|
||||
|
||||
config acl 'deny_private'
|
||||
option action 'deny'
|
||||
option dst '10.0.0.0/8,172.16.0.0/12,192.168.0.0/16'
|
||||
|
||||
#config acl 'via_upstream'
|
||||
# option action 'allow'
|
||||
# list parent 'upstream'
|
||||
|
||||
# Parent proxies extend an allow rule to build a chain. Weights group them:
|
||||
# parents whose weights sum to 1000 form one group and one is picked at random,
|
||||
# several groups are chained in order.
|
||||
#config parent 'upstream'
|
||||
# option weight '1000'
|
||||
# option type 'socks5'
|
||||
# option ip '10.0.0.1'
|
||||
# option port '1080'
|
||||
# option username ''
|
||||
# option password ''
|
||||
|
||||
config service 'proxy'
|
||||
option enabled '0'
|
||||
option type 'proxy'
|
||||
option port '3128'
|
||||
# option bind ''
|
||||
# option external ''
|
||||
# option extra ''
|
||||
# option auth 'strong'
|
||||
list acl 'deny_private'
|
||||
list acl 'lan'
|
||||
|
||||
config service 'socks'
|
||||
option enabled '0'
|
||||
option type 'socks'
|
||||
option port '1080'
|
||||
list acl 'lan'
|
||||
460
scripts/openwrt/files/3proxy.init
Normal file
460
scripts/openwrt/files/3proxy.init
Normal file
@ -0,0 +1,460 @@
|
||||
#!/bin/sh /etc/rc.common
|
||||
|
||||
START=50
|
||||
USE_PROCD=1
|
||||
|
||||
CFGFILE=/var/etc/3proxy.cfg
|
||||
PROG=/usr/bin/3proxy
|
||||
|
||||
# 3proxy.cfg is order dependent: authentication and access rules apply to the
|
||||
# service lines that follow them, and the access list has to be flushed before
|
||||
# each service. The file is written as one global block followed by one block
|
||||
# per service.
|
||||
|
||||
acl_written=0
|
||||
|
||||
append_line() {
|
||||
echo "$1" >> "$CFGFILE"
|
||||
}
|
||||
|
||||
append_include() {
|
||||
echo "include $1" >> "$CFGFILE"
|
||||
}
|
||||
|
||||
# The limiter directives carry their own ACL pattern rather than attaching to a
|
||||
# preceding allow rule, and 3proxy defaults every omitted field to *, so the
|
||||
# trailing wildcards are dropped again to keep the file readable.
|
||||
# logformat takes a single argument, so a format containing spaces has to be
|
||||
# quoted. Quotes already present in the UCI value are not doubled.
|
||||
append_logformat() {
|
||||
local fmt="$1"
|
||||
|
||||
case "$fmt" in
|
||||
'"'*'"') ;;
|
||||
*) fmt="\"$fmt\"" ;;
|
||||
esac
|
||||
|
||||
echo "logformat $fmt" >> "$CFGFILE"
|
||||
}
|
||||
|
||||
limit_match() {
|
||||
local users src dst ports ops weekdays periods out
|
||||
|
||||
config_get users "$1" users '*'
|
||||
config_get src "$1" src '*'
|
||||
config_get dst "$1" dst '*'
|
||||
config_get ports "$1" ports '*'
|
||||
config_get ops "$1" operations '*'
|
||||
config_get weekdays "$1" weekdays '*'
|
||||
config_get periods "$1" timeperiods '*'
|
||||
|
||||
out="$users $src $dst $ports $ops $weekdays $periods"
|
||||
while [ "${out% \*}" != "$out" ]; do out="${out% \*}"; done
|
||||
|
||||
echo "$out"
|
||||
}
|
||||
|
||||
append_limit() {
|
||||
local type rate period number count_type limit match
|
||||
|
||||
config_get type "$1" type
|
||||
|
||||
case "$type" in
|
||||
bandlimin|bandlimout|nobandlimin|nobandlimout|\
|
||||
connlim|noconnlim|\
|
||||
countin|countout|countall|nocountin|nocountout|nocountall) ;;
|
||||
*)
|
||||
echo "3proxy: limit '$1' has unknown type '$type', ignored" >&2
|
||||
return 0
|
||||
;;
|
||||
esac
|
||||
|
||||
match=$(limit_match "$1")
|
||||
|
||||
case "$type" in
|
||||
bandlimin|bandlimout)
|
||||
config_get rate "$1" rate
|
||||
[ -n "$rate" ] || {
|
||||
echo "3proxy: limit '$1' needs a rate, ignored" >&2
|
||||
return 0
|
||||
}
|
||||
echo "$type $rate $match" >> "$CFGFILE"
|
||||
;;
|
||||
connlim)
|
||||
config_get rate "$1" rate
|
||||
config_get period "$1" period 0
|
||||
[ -n "$rate" ] || {
|
||||
echo "3proxy: limit '$1' needs a rate, ignored" >&2
|
||||
return 0
|
||||
}
|
||||
echo "$type $rate $period $match" >> "$CFGFILE"
|
||||
;;
|
||||
countin|countout|countall)
|
||||
config_get number "$1" number
|
||||
config_get count_type "$1" count_type
|
||||
config_get limit "$1" limit
|
||||
[ -n "$number" ] && [ -n "$count_type" ] && [ -n "$limit" ] || {
|
||||
echo "3proxy: limit '$1' needs number, count_type and limit, ignored" >&2
|
||||
return 0
|
||||
}
|
||||
echo "$type $number $count_type $limit $match" >> "$CFGFILE"
|
||||
;;
|
||||
*)
|
||||
echo "$type $match" >> "$CFGFILE"
|
||||
;;
|
||||
esac
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
append_pcre_extend() {
|
||||
echo "pcre_extend $1" >> "$CFGFILE"
|
||||
}
|
||||
|
||||
append_pcre() {
|
||||
local match_type action regexp rewrite ace
|
||||
|
||||
config_get match_type "$1" match_type
|
||||
config_get action "$1" action
|
||||
config_get regexp "$1" regexp
|
||||
config_get rewrite "$1" rewrite
|
||||
config_get ace "$1" ace
|
||||
|
||||
[ -n "$match_type" ] && [ -n "$action" ] && [ -n "$regexp" ] || {
|
||||
echo "3proxy: pcre '$1' needs match_type, action and regexp, ignored" >&2
|
||||
return 0
|
||||
}
|
||||
|
||||
# Catch bad values here: 3proxy rejects the whole configuration on an
|
||||
# unknown type or action, which would leave the router without a proxy.
|
||||
case "$action" in
|
||||
allow|deny|dunno) ;;
|
||||
*)
|
||||
echo "3proxy: pcre '$1' action '$action' is not allow, deny or dunno, ignored" >&2
|
||||
return 0
|
||||
;;
|
||||
esac
|
||||
|
||||
local part
|
||||
for part in $(echo "$match_type" | tr ',' ' '); do
|
||||
case "$part" in
|
||||
request|cliheader|srvheader|clidata|srvdata) ;;
|
||||
*)
|
||||
echo "3proxy: pcre '$1' match_type '$part' is unknown, ignored" >&2
|
||||
return 0
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [ -n "$rewrite" ]; then
|
||||
echo "pcre_rewrite $match_type $action $regexp $rewrite${ace:+ $ace}" >> "$CFGFILE"
|
||||
else
|
||||
echo "pcre $match_type $action $regexp${ace:+ $ace}" >> "$CFGFILE"
|
||||
fi
|
||||
|
||||
config_list_foreach "$1" extend append_pcre_extend
|
||||
return 0
|
||||
}
|
||||
|
||||
append_nsrecord() {
|
||||
set -- $1
|
||||
if [ $# -ne 2 ]; then
|
||||
echo "3proxy: nsrecord '$*' needs a hostname and an address, ignored" >&2
|
||||
return 0
|
||||
fi
|
||||
|
||||
echo "nsrecord $1 $2" >> "$CFGFILE"
|
||||
nsrecord_written=1
|
||||
return 0
|
||||
}
|
||||
|
||||
append_nserver() {
|
||||
echo "nserver $1" >> "$CFGFILE"
|
||||
}
|
||||
|
||||
append_user() {
|
||||
users="$users $1"
|
||||
}
|
||||
|
||||
# $1 is the name of an acl section referenced by a service, or by the global
|
||||
# section as the default access list.
|
||||
append_acl() {
|
||||
local action users src dst ports
|
||||
|
||||
config_get action "$1" action allow
|
||||
config_get users "$1" users
|
||||
config_get src "$1" src
|
||||
config_get dst "$1" dst
|
||||
config_get ports "$1" ports
|
||||
|
||||
case "$action" in
|
||||
allow|deny) ;;
|
||||
*)
|
||||
echo "3proxy: acl '$1' has unknown action '$action', ignored" >&2
|
||||
return 0
|
||||
;;
|
||||
esac
|
||||
|
||||
echo "$action ${users:-*} ${src:-*} ${dst:-*} ${ports:-*}" >> "$CFGFILE"
|
||||
acl_written=1
|
||||
|
||||
if [ "$action" = "allow" ]; then
|
||||
config_list_foreach "$1" parent append_parent
|
||||
else
|
||||
config_get _parent "$1" parent
|
||||
[ -z "$_parent" ] || echo "3proxy: acl '$1' is a deny rule, its parents are ignored" >&2
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
# $1 is the name of a parent section referenced by an acl. "parent" extends the
|
||||
# allow rule that precedes it, so these are emitted directly after their rule.
|
||||
append_parent() {
|
||||
local weight type ip port username password line
|
||||
|
||||
config_get weight "$1" weight 1000
|
||||
config_get type "$1" type
|
||||
config_get ip "$1" ip
|
||||
config_get port "$1" port
|
||||
config_get username "$1" username
|
||||
config_get password "$1" password
|
||||
|
||||
[ -n "$type" ] && [ -n "$ip" ] && [ -n "$port" ] || {
|
||||
echo "3proxy: parent '$1' needs type, ip and port, ignored" >&2
|
||||
return 0
|
||||
}
|
||||
|
||||
line="parent $weight $type $ip $port"
|
||||
if [ -n "$username" ]; then
|
||||
line="$line $username"
|
||||
[ -n "$password" ] && line="$line $password"
|
||||
fi
|
||||
|
||||
echo "$line" >> "$CFGFILE"
|
||||
return 0
|
||||
}
|
||||
|
||||
# TLS parameters that take a value. The UCI option name is the directive name.
|
||||
SSL_VALUE_OPTIONS="ssl_server_cert ssl_server_key ssl_client_cert ssl_client_key
|
||||
ssl_client_ciphersuites ssl_server_ciphersuites
|
||||
ssl_client_cipher_list ssl_server_cipher_list
|
||||
ssl_client_min_proto_version ssl_server_min_proto_version
|
||||
ssl_client_max_proto_version ssl_server_max_proto_version
|
||||
ssl_server_ca_file ssl_server_ca_key ssl_server_ca_dir ssl_server_ca_store
|
||||
ssl_client_ca_file ssl_client_ca_dir ssl_client_ca_store
|
||||
ssl_client_sni ssl_client_alpn ssl_client_mode ssl_certcache"
|
||||
|
||||
# The TLS switches apply to every service below them, so they leak from one
|
||||
# service to the next unless turned back off. These track what is currently in
|
||||
# effect - all off, matching the defaults - so a directive is written only when
|
||||
# a service actually needs a different state.
|
||||
ssl_state_mitm=0
|
||||
ssl_state_server=0
|
||||
ssl_state_client=0
|
||||
ssl_state_client_verify=0
|
||||
ssl_state_server_verify=0
|
||||
|
||||
# $1 section, $2 uci option, $3 state variable, $4 directive on, $5 directive off
|
||||
append_ssl_toggle() {
|
||||
local want have
|
||||
|
||||
config_get_bool want "$1" "$2" 0
|
||||
have=$(eval echo \$$3)
|
||||
|
||||
[ "$want" = "$have" ] && return 0
|
||||
|
||||
if [ "$want" -gt 0 ]; then
|
||||
echo "$4" >> "$CFGFILE"
|
||||
else
|
||||
echo "$5" >> "$CFGFILE"
|
||||
fi
|
||||
|
||||
eval "$3=$want"
|
||||
return 0
|
||||
}
|
||||
|
||||
append_ssl() {
|
||||
local opt value mitm server cert key cverify
|
||||
|
||||
for opt in $SSL_VALUE_OPTIONS; do
|
||||
config_get value "$1" "$opt"
|
||||
[ -n "$value" ] && echo "$opt $value" >> "$CFGFILE"
|
||||
done
|
||||
|
||||
append_ssl_toggle "$1" ssl_mitm ssl_state_mitm ssl_mitm ssl_nomitm
|
||||
append_ssl_toggle "$1" ssl_server ssl_state_server ssl_serv ssl_noserv
|
||||
append_ssl_toggle "$1" ssl_client ssl_state_client ssl_cli ssl_nocli
|
||||
append_ssl_toggle "$1" ssl_client_verify ssl_state_client_verify \
|
||||
ssl_client_verify ssl_client_no_verify
|
||||
append_ssl_toggle "$1" ssl_server_verify ssl_state_server_verify \
|
||||
ssl_server_verify ssl_server_no_verify
|
||||
|
||||
config_get_bool mitm "$1" ssl_mitm 0
|
||||
config_get_bool cverify "$1" ssl_client_verify 0
|
||||
[ "$mitm" -gt 0 ] && [ "$cverify" -gt 0 ] || [ "$mitm" -eq 0 ] || \
|
||||
echo "3proxy: service '$1' spoofs certificates without ssl_client_verify, upstream certificates are not checked" >&2
|
||||
|
||||
config_get_bool server "$1" ssl_server 0
|
||||
if [ "$server" -gt 0 ]; then
|
||||
config_get cert "$1" ssl_server_cert
|
||||
config_get key "$1" ssl_server_key
|
||||
[ -n "$cert" ] && [ -n "$key" ] || \
|
||||
echo "3proxy: service '$1' requires TLS from clients but has no ssl_server_cert/ssl_server_key" >&2
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
append_service() {
|
||||
local enabled type port bind external extra auth args
|
||||
local bind_interface external_interface logformat
|
||||
|
||||
config_get_bool enabled "$1" enabled 0
|
||||
[ "$enabled" -gt 0 ] || return 0
|
||||
|
||||
config_get type "$1" type
|
||||
[ -n "$type" ] || {
|
||||
echo "3proxy: service '$1' has no type, ignored" >&2
|
||||
return 0
|
||||
}
|
||||
|
||||
config_get port "$1" port
|
||||
config_get bind "$1" bind
|
||||
config_get external "$1" external
|
||||
config_get extra "$1" extra
|
||||
config_get bind_interface "$1" bind_interface
|
||||
config_get external_interface "$1" external_interface
|
||||
config_get logformat "$1" logformat
|
||||
config_get auth "$1" auth "$global_auth"
|
||||
|
||||
echo "" >> "$CFGFILE"
|
||||
echo "flush" >> "$CFGFILE"
|
||||
[ -n "$auth" ] && echo "auth $auth" >> "$CFGFILE"
|
||||
|
||||
# Rules referenced by the service, in the order they are listed. A service
|
||||
# without its own list falls back to the global one.
|
||||
acl_written=0
|
||||
config_list_foreach "$1" acl append_acl
|
||||
[ "$acl_written" -gt 0 ] || config_list_foreach global acl append_acl
|
||||
|
||||
[ -n "$logformat" ] && append_logformat "$logformat"
|
||||
|
||||
append_ssl "$1"
|
||||
|
||||
args=""
|
||||
[ -n "$port" ] && args="$args -p$port"
|
||||
[ -n "$bind" ] && args="$args -i$bind"
|
||||
[ -n "$external" ] && args="$args -e$external"
|
||||
[ -n "$bind_interface" ] && args="$args -Di$bind_interface"
|
||||
[ -n "$external_interface" ] && args="$args -De$external_interface"
|
||||
[ -n "$extra" ] && args="$args $extra"
|
||||
|
||||
echo "$type$args" >> "$CFGFILE"
|
||||
return 0
|
||||
}
|
||||
|
||||
write_config() {
|
||||
local nscache nscache6 maxconn log timeouts fakeresolve logformat
|
||||
local authcache_type authcache_time authcache_size
|
||||
local counter_file counter_type counter_name pcre_options
|
||||
|
||||
mkdir -p "$(dirname "$CFGFILE")"
|
||||
: > "$CFGFILE"
|
||||
|
||||
config_get nscache global nscache
|
||||
config_get nscache6 global nscache6
|
||||
config_get maxconn global maxconn
|
||||
config_get global_auth global auth iponly
|
||||
config_get log global log syslog
|
||||
config_get timeouts global timeouts
|
||||
config_get logformat global logformat
|
||||
config_get_bool fakeresolve global fakeresolve 0
|
||||
config_get authcache_type global authcache_type
|
||||
config_get authcache_time global authcache_time
|
||||
config_get authcache_size global authcache_size
|
||||
config_get counter_file global counter_file
|
||||
config_get counter_type global counter_type
|
||||
config_get counter_name global counter_name
|
||||
config_get pcre_options global pcre_options
|
||||
|
||||
config_list_foreach global nserver append_nserver
|
||||
[ -n "$nscache" ] && echo "nscache $nscache" >> "$CFGFILE"
|
||||
[ -n "$nscache6" ] && echo "nscache6 $nscache6" >> "$CFGFILE"
|
||||
|
||||
# Static records are added to the cache, so they have to come after it.
|
||||
nsrecord_written=0
|
||||
config_list_foreach global nsrecord append_nsrecord
|
||||
[ "$nsrecord_written" -eq 0 ] || [ -n "$nscache$nscache6" ] || \
|
||||
echo "3proxy: nsrecord needs nscache or nscache6 to be set" >&2
|
||||
|
||||
case "$log" in
|
||||
syslog) echo "log" >> "$CFGFILE" ;;
|
||||
none|"") ;;
|
||||
*) echo "log $log" >> "$CFGFILE" ;;
|
||||
esac
|
||||
|
||||
users=""
|
||||
config_list_foreach global user append_user
|
||||
[ -n "$users" ] && echo "users$users" >> "$CFGFILE"
|
||||
|
||||
[ -n "$timeouts" ] && echo "timeouts $timeouts" >> "$CFGFILE"
|
||||
[ "$fakeresolve" -gt 0 ] && echo "fakeresolve" >> "$CFGFILE"
|
||||
[ -n "$logformat" ] && append_logformat "$logformat"
|
||||
|
||||
if [ -n "$authcache_type" ]; then
|
||||
[ -n "$authcache_time" ] || authcache_time=600
|
||||
echo "authcache $authcache_type $authcache_time${authcache_size:+ $authcache_size}" >> "$CFGFILE"
|
||||
fi
|
||||
|
||||
if [ -n "$counter_file" ]; then
|
||||
echo "counter $counter_file${counter_type:+ $counter_type}${counter_name:+ $counter_name}" >> "$CFGFILE"
|
||||
fi
|
||||
|
||||
[ -n "$pcre_options" ] && echo "pcre_options $pcre_options" >> "$CFGFILE"
|
||||
|
||||
# Both lists are order sensitive: 3proxy stops at the first match, so the
|
||||
# exempting rules (nobandlimin and friends) have to be listed first.
|
||||
config_list_foreach global pcre append_pcre
|
||||
config_list_foreach global limit append_limit
|
||||
|
||||
config_list_foreach global include append_include
|
||||
config_list_foreach global extra_config append_line
|
||||
|
||||
[ -n "$maxconn" ] && echo "maxconn $maxconn" >> "$CFGFILE"
|
||||
|
||||
config_foreach append_service service
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
start_service() {
|
||||
local enabled
|
||||
|
||||
config_load 3proxy
|
||||
config_get_bool enabled global enabled 0
|
||||
|
||||
[ "$enabled" -gt 0 ] || {
|
||||
echo "3proxy is disabled in /etc/config/3proxy" >&2
|
||||
return 1
|
||||
}
|
||||
|
||||
write_config
|
||||
|
||||
procd_open_instance
|
||||
procd_set_param command "$PROG" "$CFGFILE"
|
||||
procd_set_param file "$CFGFILE"
|
||||
procd_set_param respawn
|
||||
procd_set_param stdout 1
|
||||
procd_set_param stderr 1
|
||||
procd_close_instance
|
||||
}
|
||||
|
||||
service_triggers() {
|
||||
procd_add_reload_trigger "3proxy"
|
||||
}
|
||||
|
||||
reload_service() {
|
||||
stop
|
||||
start
|
||||
}
|
||||
@ -1,5 +1,5 @@
|
||||
Name: 3proxy
|
||||
Version: 0.9.9
|
||||
Version: 0.9.9.1
|
||||
Release: 1%{?dist}
|
||||
Summary: 3proxy tiny proxy server
|
||||
License: GPL/LGPL/Apache/BSD
|
||||
@ -9,6 +9,9 @@ Prefix: %{_prefix}
|
||||
Packager: z3APA3A
|
||||
Source: https://github.com/%{packager}/%{name}/archive/%{version}.tar.gz
|
||||
|
||||
%global debug_package %{nil}
|
||||
%global __requires_exclude ^/(usr/)?bin/3proxy$
|
||||
|
||||
%description
|
||||
3proxy is lightweight yet powerful proxy server
|
||||
|
||||
|
||||
65
src/common.c
65
src/common.c
@ -182,7 +182,7 @@ int timeouts[12] = {
|
||||
EINVAL below it and the thread silently gets the 8M system default stack.
|
||||
*/
|
||||
size_t threadstacksize(int extra){
|
||||
long size = BASESTACKSIZE + extra;
|
||||
long size = BASESTACKSIZE + TLSSTACKSIZE + extra;
|
||||
|
||||
if(size < (long)PTHREAD_STACK_MIN) size = (long)PTHREAD_STACK_MIN;
|
||||
return (size_t)size;
|
||||
@ -677,6 +677,49 @@ int connectwithpoll(struct clientparam *param, SOCKET sock, struct sockaddr *sa,
|
||||
}
|
||||
|
||||
|
||||
/* -Di / -De: ties a socket to the interface asked for, for TCP and UDP alike.
|
||||
Where the option is set per protocol, family is the one of the address the
|
||||
socket will be bound to. */
|
||||
int bindtodevice(struct sockfuncs *sf, void *state, SOCKET sock, const char *device, int family){
|
||||
if(!device) return 0;
|
||||
#if defined SO_BINDTODEVICE
|
||||
if(sf->_setsockopt(state, sock, SOL_SOCKET, SO_BINDTODEVICE, device, strlen(device) + 1))
|
||||
return 1;
|
||||
#elif defined IP_BOUND_IF
|
||||
{
|
||||
int idx;
|
||||
idx = if_nametoindex(device);
|
||||
if(!idx || (family == AF_INET && sf->_setsockopt(state, sock, IPPROTO_IP, IP_BOUND_IF, &idx, sizeof(idx))))
|
||||
return 1;
|
||||
#ifndef NOIPV6
|
||||
#ifndef IPV6_BOUND_IF
|
||||
#define IPV6_BOUND_IF 125
|
||||
#endif
|
||||
if(family == AF_INET6 && sf->_setsockopt(state, sock, IPPROTO_IPV6, IPV6_BOUND_IF, &idx, sizeof(idx))) return 1;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* the external side, a socket to be bound to sinsl */
|
||||
int extbindtodevice(struct clientparam *param, SOCKET sock){
|
||||
#if defined SO_BINDTODEVICE || defined IP_BOUND_IF
|
||||
return bindtodevice(¶m->srv->so, param->sostate, sock, param->srv->obindtodevice, *SAFAMILY(¶m->sinsl));
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* the internal side, a socket to be bound to sincl */
|
||||
int intbindtodevice(struct clientparam *param, SOCKET sock){
|
||||
#if defined SO_BINDTODEVICE || defined IP_BOUND_IF
|
||||
return bindtodevice(¶m->srv->so, param->sostate, sock, param->srv->ibindtodevice, *SAFAMILY(¶m->sincl));
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
int doconnect(struct clientparam * param){
|
||||
SASIZETYPE size;
|
||||
|
||||
@ -724,25 +767,7 @@ int doconnect(struct clientparam * param){
|
||||
setopts(param->remsock, param->srv->srvsockopts);
|
||||
|
||||
param->srv->so._setsockopt(param->sostate, param->remsock, SOL_SOCKET, SO_LINGER, (char *)&lg, sizeof(lg));
|
||||
#if defined SO_BINDTODEVICE
|
||||
if(param->srv->obindtodevice) {
|
||||
if(param->srv->so._setsockopt(param->sostate, param->remsock, SOL_SOCKET, SO_BINDTODEVICE, param->srv->obindtodevice, strlen(param->srv->obindtodevice) + 1))
|
||||
return 12;
|
||||
}
|
||||
#elif defined IP_BOUND_IF
|
||||
if(param->srv->obindtodevice) {
|
||||
int idx;
|
||||
idx = if_nametoindex(param->srv->obindtodevice);
|
||||
if(!idx || (*SAFAMILY(¶m->sinsl) == AF_INET && param->srv->so._setsockopt(param->sostate, param->remsock, IPPROTO_IP, IP_BOUND_IF, &idx, sizeof(idx))))
|
||||
return 12;
|
||||
#ifndef NOIPV6
|
||||
#ifndef IPV6_BOUND_IF
|
||||
#define IPV6_BOUND_IF 125
|
||||
#endif
|
||||
if(*SAFAMILY(¶m->sinsl) == AF_INET6 && param->srv->so._setsockopt(param->sostate, param->remsock, IPPROTO_IPV6, IPV6_BOUND_IF, &idx, sizeof(idx))) return 12;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
if(extbindtodevice(param, param->remsock)) return 12;
|
||||
#ifdef WITH_UN
|
||||
if(*SAFAMILY(¶m->sinsl) != AF_UNIX)
|
||||
#endif
|
||||
|
||||
@ -158,7 +158,12 @@ int start_proxy_thread(struct child * chp){
|
||||
pthread_attr_init(&pa);
|
||||
pthread_attr_setstacksize(&pa,threadstacksize(conf.stacksize));
|
||||
pthread_attr_setdetachstate(&pa,PTHREAD_CREATE_DETACHED);
|
||||
pthread_create(&thread, &pa, startsrv, (void *)chp);
|
||||
if(pthread_create(&thread, &pa, startsrv, (void *)chp)){
|
||||
pthread_attr_destroy(&pa);
|
||||
fprintf(stderr, "Failed to create service thread on line %d, try to set larger stacksize\n", linenum);
|
||||
_3proxy_sem_unlock(conf.threadinit);
|
||||
return(40);
|
||||
}
|
||||
pthread_attr_destroy(&pa);
|
||||
#endif
|
||||
_3proxy_sem_lock(conf.threadinit);
|
||||
|
||||
@ -64,6 +64,13 @@ void * ftpprchild(struct clientparam* param) {
|
||||
|
||||
}
|
||||
else if (!strncasecmp((char *)buf, "PASS ", 5)){
|
||||
/* The user name carries the server to log in to, and it arrives
|
||||
with USER. Without it there is nothing to log in to, and what
|
||||
follows would read the name and the host as if there were. */
|
||||
if(!param->hostname || !param->extusername){
|
||||
socksend(param, param->ctrlsock, (unsigned char *)"503 Login with USER first\r\n", 27, conf.timeouts[STRING_S]);
|
||||
RETURN(805);
|
||||
}
|
||||
param->extpassword = (unsigned char *)strdup((char *)buf+5);
|
||||
inbuf = BUFSIZE;
|
||||
res = ftplogin(param, (char *)buf, &inbuf);
|
||||
@ -120,6 +127,7 @@ void * ftpprchild(struct clientparam* param) {
|
||||
clidatasock = INVALID_SOCKET;
|
||||
}
|
||||
if ((clidatasock=socket(SASOCK(¶m->sincl), SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET) {RETURN(821);}
|
||||
if(intbindtodevice(param, clidatasock)){RETURN(822);}
|
||||
*SAPORT(¶m->sincl) = 0;
|
||||
if(param->srv->so._bind(param->sostate, clidatasock, (struct sockaddr *)¶m->sincl, SASIZE(¶m->sincl))){RETURN(822);}
|
||||
if (pasv) {
|
||||
|
||||
22
src/pcre.c
22
src/pcre.c
@ -265,6 +265,9 @@ static FILTER_ACTION pcre_filter_client(void *fo, struct clientparam * param, vo
|
||||
return (res)? CONTINUE:PASS;
|
||||
}
|
||||
|
||||
/* What a rewritten buffer keeps free for its caller to append to. */
|
||||
#define PCRE_HEADROOM 1024
|
||||
|
||||
static FILTER_ACTION pcre_filter_buffer(void *fc, struct clientparam *param, unsigned char ** buf_p, int * bufsize_p, int offset, int * length_p){
|
||||
PCRE2_SIZE *ovector;
|
||||
int count = 0;
|
||||
@ -277,7 +280,7 @@ static FILTER_ACTION pcre_filter_buffer(void *fc, struct clientparam *param, uns
|
||||
#define pcrefd ((struct pcre_filter_data *)fc)
|
||||
|
||||
for(acl = pcrefd->acl; acl; acl=acl->next){
|
||||
if(pl->ACLMatches(pcrefd->acl, param)){
|
||||
if(pl->ACLMatches(acl, param)){
|
||||
match = 1;
|
||||
break;
|
||||
}
|
||||
@ -324,12 +327,17 @@ static FILTER_ACTION pcre_filter_buffer(void *fc, struct clientparam *param, uns
|
||||
else if(*replace == '$' && isnumber(*(replace+1))){
|
||||
replace ++;
|
||||
num = atoi(replace);
|
||||
/* Past the digits first, and only then decide whether
|
||||
the group is one to copy: the pass which measured
|
||||
this string did it in that order, and a reference it
|
||||
counted as nothing must not be written out as its
|
||||
own digits here. */
|
||||
while(isnumber(*replace)) replace++;
|
||||
if(num > (count - 1)) continue;
|
||||
if(ovector[(num<<1)] == PCRE2_UNSET) continue;
|
||||
if(ovector[(num<<1) + 1] > (PCRE2_SIZE)*length_p || ovector[(num<<1)] > ovector[(num<<1) + 1]) continue;
|
||||
memcpy(target, *buf_p + ovector[(num<<1)], ovector[(num<<1) + 1] - ovector[(num<<1)]);
|
||||
target += (ovector[(num<<1) + 1] - ovector[(num<<1)]);
|
||||
while(isnumber(*replace)) replace++;
|
||||
}
|
||||
else {
|
||||
*target++ = *replace++;
|
||||
@ -338,7 +346,13 @@ static FILTER_ACTION pcre_filter_buffer(void *fc, struct clientparam *param, uns
|
||||
repsz = (int)(target - tmpbuf);
|
||||
memcpy(target, *buf_p + ovector[1], *length_p - ovector[1]);
|
||||
if((ovector[0] + replen + 1) > *bufsize_p){
|
||||
newbuf = pl->mallocfunc(ovector[0] + replen + 1);
|
||||
/* Room beyond what was produced: whoever asked for the
|
||||
filtering usually has something of its own to add, and a
|
||||
buffer sized to the last byte written leaves nowhere to
|
||||
put it. The size reported is the size allocated. */
|
||||
int newsize = ovector[0] + replen + 1 + PCRE_HEADROOM;
|
||||
|
||||
newbuf = pl->mallocfunc(newsize);
|
||||
if(!newbuf){
|
||||
pl->freefunc(tmpbuf);
|
||||
return CONTINUE;
|
||||
@ -346,7 +360,7 @@ static FILTER_ACTION pcre_filter_buffer(void *fc, struct clientparam *param, uns
|
||||
memcpy(newbuf, *buf_p, ovector[0]);
|
||||
pl->freefunc(*buf_p);
|
||||
*buf_p = (unsigned char *)newbuf;
|
||||
*bufsize_p = ovector[0] + replen + 1;
|
||||
*bufsize_p = newsize;
|
||||
}
|
||||
memcpy(*buf_p + ovector[0], tmpbuf, replen);
|
||||
pl->freefunc(tmpbuf);
|
||||
|
||||
27
src/proxy.c
27
src/proxy.c
@ -132,6 +132,12 @@ char * proxy_stringtable[] = {
|
||||
};
|
||||
|
||||
#define LINESIZE 32768
|
||||
/* "Content-Length: " plus 20 digits plus CRLF and a NUL, rounded up */
|
||||
#define CLHDRSIZE 48
|
||||
/* what the headers this proxy adds of its own can come to: a Forwarded or
|
||||
Via with a host name in it, a Connection, a Proxy-support and a
|
||||
Proxy-Authorization carrying an encoded user and password */
|
||||
#define HDRRESERVE 2048
|
||||
#define BUFSIZE (LINESIZE*2)
|
||||
#define FTPBUFSIZE 1536
|
||||
|
||||
@ -151,6 +157,20 @@ static int send_st(struct clientparam *param, int idx){
|
||||
return socksend(param, param->clisock, (unsigned char *)proxy_stringtable[idx], pst_len(idx), conf.timeouts[STRING_S]);
|
||||
}
|
||||
|
||||
/* Makes room in a buffer whose size is tracked. A filter may hand back one
|
||||
holding exactly what it produced, so nothing may be added to it without
|
||||
asking for the room first. Returns 1 when the room cannot be had. */
|
||||
static int growbuf(unsigned char **buf, int *bufsize, int need){
|
||||
unsigned char *newbuf;
|
||||
|
||||
if(need <= *bufsize) return 0;
|
||||
need += BUFSIZE; /* for what follows too, not just this */
|
||||
if(!(newbuf = realloc(*buf, need))) return 1;
|
||||
*buf = newbuf;
|
||||
*bufsize = need;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void freeptr(void *p){
|
||||
void **pp = (void **)p;
|
||||
if(*pp) { free(*pp); *pp = NULL; }
|
||||
@ -587,6 +607,10 @@ for(;;){
|
||||
RETURN(0);
|
||||
}
|
||||
if(action != PASS) RETURN(517);
|
||||
/* A filter may have returned a buffer sized to exactly what it produced.
|
||||
The headers this proxy adds of its own go in after it, so the room for
|
||||
them is taken back before anything is written. */
|
||||
if(growbuf(&buf, &bufsize, inbuf + HDRRESERVE)) RETURN(21);
|
||||
param->nolongdatfilter = 0;
|
||||
|
||||
#endif
|
||||
@ -620,6 +644,7 @@ for(;;){
|
||||
contentlength64 = param->cliinbuf;
|
||||
param->nolongdatfilter = 1;
|
||||
}
|
||||
if(growbuf(&buf, &bufsize, (int)strlen((char *)buf) + CLHDRSIZE)) RETURN(21);
|
||||
sprintf((char*)buf+strlen((char *)buf), "Content-Length: %"PRIu64"\r\n", contentlength64);
|
||||
}
|
||||
|
||||
@ -1097,6 +1122,7 @@ for(;;){
|
||||
RETURN(0);
|
||||
}
|
||||
if(action != PASS) RETURN(517);
|
||||
if(growbuf(&buf, &bufsize, inbuf + HDRRESERVE)) RETURN(21);
|
||||
|
||||
param->nolongdatfilter = 0;
|
||||
|
||||
@ -1120,6 +1146,7 @@ for(;;){
|
||||
}
|
||||
if(action != PASS) RETURN(517);
|
||||
contentlength64 = param->srvinbuf;
|
||||
if(growbuf(&buf, &bufsize, (int)strlen((char *)buf) + CLHDRSIZE)) RETURN(21);
|
||||
sprintf((char*)buf+strlen((char *)buf), "Content-Length: %"PRIu64"\r\n", contentlength64);
|
||||
hascontent = 1;
|
||||
}
|
||||
|
||||
20
src/proxy.h
20
src/proxy.h
@ -135,6 +135,23 @@ void daemonize(void);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* wolfSSL reserves around 48K of static thread-local storage. glibc counts
|
||||
that against the thread stack, so pthread_create() fails with EINVAL and
|
||||
no thread starts at all. musl places the block next to the stack instead
|
||||
of inside it and needs nothing extra, and OpenSSL has no static TLS.
|
||||
musl identifies itself by no macro of its own, but it does not define
|
||||
__GLIBC__, which any libc header pulled in above would have set.
|
||||
*/
|
||||
#ifndef TLSSTACKSIZE
|
||||
#if defined(__linux__) && !defined(__GLIBC__)
|
||||
#define TLSSTACKSIZE 0
|
||||
#elif defined(WITH_WOLFSSL)
|
||||
#define TLSSTACKSIZE 49152
|
||||
#else
|
||||
#define TLSSTACKSIZE 0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef _WIN32
|
||||
size_t threadstacksize(int extra);
|
||||
#endif
|
||||
@ -352,6 +369,9 @@ unsigned char * dologname (unsigned char *buf, unsigned char *name, const unsign
|
||||
int readconfig(FILE * fp);
|
||||
void initcommands(void);
|
||||
int connectwithpoll(struct clientparam *param, SOCKET sock, struct sockaddr *sa, SASIZETYPE size, int to);
|
||||
int bindtodevice(struct sockfuncs *sf, void *state, SOCKET sock, const char *device, int family);
|
||||
int extbindtodevice(struct clientparam *param, SOCKET sock);
|
||||
int intbindtodevice(struct clientparam *param, SOCKET sock);
|
||||
|
||||
|
||||
uint32_t myrand(void);
|
||||
|
||||
@ -830,35 +830,25 @@ int MODULEMAINFUNC (int argc, char** argv){
|
||||
#ifndef _WIN32
|
||||
opt = 1;
|
||||
if(srv.so._setsockopt(srv.so.state, sock, SOL_SOCKET, SO_REUSEADDR, (char *)&opt, sizeof(int)))perror("setsockopt()");
|
||||
#else
|
||||
/* A UDP service on Windows answers from a second socket bound to
|
||||
the address it listens on, and Windows only allows that bind
|
||||
when both sockets ask for it. */
|
||||
if(isudp){
|
||||
opt = 1;
|
||||
if(srv.so._setsockopt(srv.so.state, sock, SOL_SOCKET, SO_REUSEADDR, (char *)&opt, sizeof(int)))perror("setsockopt()");
|
||||
}
|
||||
#endif
|
||||
#ifdef SO_REUSEPORT
|
||||
opt = 1;
|
||||
srv.so._setsockopt(srv.so.state, sock, SOL_SOCKET, SO_REUSEPORT, (char *)&opt, sizeof(int));
|
||||
#endif
|
||||
}
|
||||
#if defined SO_BINDTODEVICE
|
||||
if(srv.ibindtodevice && srv.so._setsockopt(srv.so.state, sock, SOL_SOCKET, SO_BINDTODEVICE, srv.ibindtodevice, strlen(srv.ibindtodevice) + 1)) {
|
||||
#if defined SO_BINDTODEVICE || defined IP_BOUND_IF
|
||||
if(bindtodevice(&srv.so, srv.so.state, sock, srv.ibindtodevice, *SAFAMILY(&srv.intsa))) {
|
||||
dolog(&defparam, (unsigned char *)"failed to bind device");
|
||||
return -12;
|
||||
}
|
||||
#elif defined IP_BOUND_IF
|
||||
if(srv.ibindtodevice){
|
||||
int idx;
|
||||
idx = if_nametoindex(srv.ibindtodevice);
|
||||
if(!idx || (*SAFAMILY(&srv.intsa) == AF_INET && setsockopt(sock, IPPROTO_IP, IP_BOUND_IF, &idx, sizeof(idx)))) {
|
||||
dolog(&defparam, (unsigned char *)"failed to bind device");
|
||||
return -12;
|
||||
}
|
||||
#ifndef NOIPV6
|
||||
#ifndef IPV6_BOUND_IF
|
||||
#define IPV6_BOUND_IF 125
|
||||
#endif
|
||||
if((*SAFAMILY(&srv.intsa) == AF_INET6 && srv.so._setsockopt(srv.so.state, sock, IPPROTO_IPV6, IPV6_BOUND_IF, &idx, sizeof(idx)))) {
|
||||
dolog(&defparam, (unsigned char *)"failed to bind device");
|
||||
return -12;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#ifdef WITH_UN
|
||||
@ -1012,6 +1002,15 @@ int MODULEMAINFUNC (int argc, char** argv){
|
||||
setopts(new_sock, srv.cbcsockopts);
|
||||
|
||||
parsehost(srv.family, cbc_string, (struct sockaddr *)&defparam.sincr);
|
||||
#if defined SO_BINDTODEVICE || defined IP_BOUND_IF
|
||||
/* as for a listening socket, an interface that cannot be
|
||||
bound to is not worth retrying */
|
||||
if(bindtodevice(&so, so.state, new_sock, srv.ibindtodevice, *SAFAMILY(&defparam.sincr))) {
|
||||
dolog(&defparam, (unsigned char *)"failed to bind device");
|
||||
so._closesocket(so.state, new_sock);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
if(connectwithpoll(NULL, new_sock,(struct sockaddr *)&defparam.sincr,SASIZE(&defparam.sincr),CONNBACK_TO)) {
|
||||
so._closesocket(so.state, new_sock);
|
||||
new_sock = INVALID_SOCKET;
|
||||
@ -1322,7 +1321,16 @@ void srvfree(struct srvparam * srv){
|
||||
if(srv->cbsock != INVALID_SOCKET) so._closesocket(srv->so.state, srv->cbsock);
|
||||
srv->cbsock = INVALID_SOCKET;
|
||||
srv->service = S_ZOMBIE;
|
||||
while(srv->child) usleep(SLEEPTIME * 100);
|
||||
/* under the mutex, so the last child has let go of it before it is destroyed */
|
||||
for(;;){
|
||||
struct clientparam *child;
|
||||
|
||||
_3proxy_mutex_lock(&srv->counter_mutex);
|
||||
child = srv->child;
|
||||
_3proxy_mutex_unlock(&srv->counter_mutex);
|
||||
if(!child) break;
|
||||
usleep(SLEEPTIME * 100);
|
||||
}
|
||||
#ifndef STDMAIN
|
||||
if(srv->filter){
|
||||
while(srv->nfilters){
|
||||
@ -1364,23 +1372,14 @@ void srvfree(struct srvparam * srv){
|
||||
void freeparam(struct clientparam * param) {
|
||||
if(param->srv){
|
||||
if(param->srv->so.freefunc) param->srv->so.freefunc(param->sostate);
|
||||
_3proxy_mutex_lock(¶m->srv->counter_mutex);
|
||||
#ifndef STDMAIN
|
||||
if(param->srv->service == S_UDPPM) hashdelete(&udp_table, param);
|
||||
#endif
|
||||
if(param->prev || param->next || param->srv->child == param){
|
||||
if(param->prev){
|
||||
param->prev->next = param->next;
|
||||
}
|
||||
else
|
||||
param->srv->child = param->next;
|
||||
if(param->next){
|
||||
param->next->prev = param->prev;
|
||||
}
|
||||
(param->srv->childcount)--;
|
||||
}
|
||||
if(param->srv->service == S_UDPPM){
|
||||
_3proxy_mutex_lock(¶m->srv->counter_mutex);
|
||||
hashdelete(&udp_table, param);
|
||||
_3proxy_mutex_unlock(¶m->srv->counter_mutex);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
if(param->clibuf) free(param->clibuf);
|
||||
if(param->srvbuf) free(param->srvbuf);
|
||||
if(param->srv) {
|
||||
@ -1419,6 +1418,24 @@ void freeparam(struct clientparam * param) {
|
||||
}
|
||||
if(param->connlim) stopconnlims(param);
|
||||
#endif
|
||||
/* Leaving the service comes last. Once its last child is gone, srvfree()
|
||||
frees the service along with its socket functions, filters and mutex,
|
||||
and a close above may have lingered for seconds before getting here. */
|
||||
if(param->srv){
|
||||
_3proxy_mutex_lock(¶m->srv->counter_mutex);
|
||||
if(param->prev || param->next || param->srv->child == param){
|
||||
if(param->prev){
|
||||
param->prev->next = param->next;
|
||||
}
|
||||
else
|
||||
param->srv->child = param->next;
|
||||
if(param->next){
|
||||
param->next->prev = param->prev;
|
||||
}
|
||||
(param->srv->childcount)--;
|
||||
}
|
||||
_3proxy_mutex_unlock(¶m->srv->counter_mutex);
|
||||
}
|
||||
if(param->hostname) free(param->hostname);
|
||||
if(param->username) free(param->username);
|
||||
if(param->password) free(param->password);
|
||||
|
||||
@ -159,7 +159,10 @@ void * smtppchild(struct clientparam* param) {
|
||||
i = de64(buf,username,255);
|
||||
if(i < 1) {RETURN(664);}
|
||||
username[i] = 0;
|
||||
parseconnusername((char *)username, param, 0, 587);
|
||||
/* The name has to carry the host to connect to, and the answer says
|
||||
whether it did: without one there is nowhere to go, and what follows
|
||||
reads the name as if there were. */
|
||||
if(parseconnusername((char *)username, param, 0, 587)) {RETURN(669);}
|
||||
socksend(param, param->clisock, (unsigned char *)"334 UGFzc3dvcmQ6\r\n", 18,conf.timeouts[STRING_S]);
|
||||
i = sockgetlinebuf(param, CLIENT, buf, sizeof(buf) - 10, '\n', conf.timeouts[STRING_S]);
|
||||
if(i < 2) {RETURN(665);}
|
||||
@ -184,7 +187,7 @@ void * smtppchild(struct clientparam* param) {
|
||||
}
|
||||
if(i < 3 || *username) {RETURN(668);}
|
||||
username[i] = 0;
|
||||
parseconnusername((char *)username+1, param, 0, 587);
|
||||
if(parseconnusername((char *)username+1, param, 0, 587)) {RETURN(670);}
|
||||
res = (int)strlen((char *)username+1) + 2;
|
||||
if(res < i){
|
||||
if(param->extpassword) free(param->extpassword);
|
||||
|
||||
@ -63,7 +63,7 @@ int sockrecvfrom(struct clientparam *param, SOCKET sock, struct sockaddr * sin,
|
||||
if(conf.timetoexit) return EOF;
|
||||
res = param?param->srv->so._poll(param->sostate, &fds, 1, to):so._poll(so.state, &fds, 1, to);
|
||||
if (res<1) return 0;
|
||||
sasize = SASIZE(sin);
|
||||
sasize = sizeof(PROXYSOCKADDRTYPE);
|
||||
do {
|
||||
res = param?param->srv->so._recvfrom(param->sostate, sock, (char *)buf, bufsize, 0, (struct sockaddr *)sin, &sasize):so._recvfrom(so.state, sock, (char *)buf, bufsize, 0, (struct sockaddr *)sin, &sasize);
|
||||
} while (res < 0 && (errno == EAGAIN || errno == EINTR));
|
||||
|
||||
@ -185,6 +185,7 @@ void * sockschild(struct clientparam* param) {
|
||||
if(command == 2){
|
||||
if ((param->remsock=param->srv->so._socket(param->sostate, SASOCK(¶m->req), SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET) {RETURN (11);}
|
||||
setopts(param->remsock, param->srv->lissockopts);
|
||||
if(extbindtodevice(param, param->remsock)) {RETURN (12);}
|
||||
}
|
||||
break;
|
||||
|
||||
@ -241,6 +242,7 @@ fflush(stderr);
|
||||
#else
|
||||
fcntl(param->clisock, F_SETFL, O_NONBLOCK | fcntl(param->clisock, F_GETFL));
|
||||
#endif
|
||||
if(intbindtodevice(param, param->clisock)) {RETURN (12);}
|
||||
sin = param->sincl;
|
||||
*SAPORT(&sin) = 0;
|
||||
if(param->srv->so._bind(param->sostate, param->clisock,(struct sockaddr *)&sin,SASIZE(&sin))) {RETURN (12);}
|
||||
|
||||
28
src/ssllib.c
28
src/ssllib.c
@ -84,7 +84,11 @@ static int copy_ext(X509 *dst_cert, X509 *src_cert, int nid)
|
||||
}
|
||||
|
||||
#ifndef WITH_WOLFSSL
|
||||
static int add_ext(X509 *cert, int nid, const char *value)
|
||||
/* issuer is the certificate the extension should describe as the issuer,
|
||||
* which matters for an authority key identifier: it names the key that
|
||||
* signs, not the key being signed.
|
||||
*/
|
||||
static int add_ext_issuer(X509 *cert, X509 *issuer, int nid, const char *value)
|
||||
{
|
||||
X509_EXTENSION *ex;
|
||||
X509V3_CTX ctx;
|
||||
@ -92,10 +96,8 @@ static int add_ext(X509 *cert, int nid, const char *value)
|
||||
/* This sets the 'context' of the extensions. */
|
||||
/* No configuration database */
|
||||
X509V3_set_ctx_nodb(&ctx);
|
||||
/* Issuer and subject certs: both the target since it is self signed,
|
||||
* no request and no CRL
|
||||
*/
|
||||
X509V3_set_ctx(&ctx, cert, cert, NULL, NULL, 0);
|
||||
/* No request and no CRL */
|
||||
X509V3_set_ctx(&ctx, issuer, cert, NULL, NULL, 0);
|
||||
/* value is char * prior to OpenSSL 1.1.0 */
|
||||
ex = X509V3_EXT_conf_nid(NULL, &ctx, nid, (char *)value);
|
||||
if (!ex)
|
||||
@ -105,6 +107,12 @@ static int add_ext(X509 *cert, int nid, const char *value)
|
||||
X509_EXTENSION_free(ex);
|
||||
return err > 0;
|
||||
}
|
||||
|
||||
static int add_ext(X509 *cert, int nid, const char *value)
|
||||
{
|
||||
/* Issuer and subject: both the target, for a self signed certificate */
|
||||
return add_ext_issuer(cert, cert, nid, value);
|
||||
}
|
||||
#endif
|
||||
|
||||
SSL_CERT ssl_copy_cert(SSL_CERT cert, SSL_CONFIG *config)
|
||||
@ -199,6 +207,16 @@ SSL_CERT ssl_copy_cert(SSL_CERT cert, SSL_CONFIG *config)
|
||||
add_ext(dst_cert, NID_basic_constraints, "critical,CA:FALSE");
|
||||
if(!copy_ext(dst_cert, src_cert, NID_ext_key_usage))
|
||||
add_ext(dst_cert, NID_ext_key_usage, "serverAuth");
|
||||
/* A verifier following RFC 5280 strictly looks for the issuer through a
|
||||
* key identifier and refuses a certificate carrying none: OpenSSL does
|
||||
* with x509_strict, and Python has since 3.13. The identifiers are
|
||||
* generated rather than copied, so they name the CA signing here
|
||||
* instead of the one that signed upstream. keyid,issuer keeps working
|
||||
* when the CA certificate has no subject key identifier of its own.
|
||||
*/
|
||||
add_ext(dst_cert, NID_subject_key_identifier, "hash");
|
||||
add_ext_issuer(dst_cert, config->CA_cert, NID_authority_key_identifier,
|
||||
"keyid,issuer");
|
||||
#else
|
||||
copy_ext(dst_cert, src_cert, NID_basic_constraints);
|
||||
copy_ext(dst_cert, src_cert, NID_ext_key_usage);
|
||||
|
||||
@ -121,6 +121,11 @@ int udpbind(struct clientparam *param)
|
||||
fcntl(s, F_SETFL, O_NONBLOCK | fcntl(s, F_GETFL));
|
||||
#endif
|
||||
param->remsock = s;
|
||||
if (extbindtodevice(param, param->remsock)) {
|
||||
param->srv->so._closesocket(param->sostate, param->remsock);
|
||||
param->remsock = INVALID_SOCKET;
|
||||
return 12;
|
||||
}
|
||||
if (param->srv->so._bind(param->sostate, param->remsock,
|
||||
(struct sockaddr *)¶m->sinsl, SASIZE(¶m->sinsl))) {
|
||||
*SAPORT(¶m->sinsl) = 0;
|
||||
@ -284,6 +289,12 @@ int udpsockmap(struct clientparam *param, int timeo)
|
||||
}
|
||||
default: return 997;
|
||||
}
|
||||
/* As for TCP requests, a literal address is the host name,
|
||||
otherwise an ACL with host names only matches any address */
|
||||
if (!dstname) {
|
||||
myinet_ntop(*SAFAMILY(&dst), SAADDR(&dst), dstnamebuf, sizeof(dstnamebuf));
|
||||
dstname = dstnamebuf;
|
||||
}
|
||||
memcpy(SAPORT(&dst), base + i, 2);
|
||||
i += 2;
|
||||
|
||||
|
||||
@ -1,14 +1,14 @@
|
||||
#ifndef VERSION
|
||||
#define VERSION "3proxy-0.9.9"
|
||||
#define VERSION "3proxy-0.9.9.1"
|
||||
#endif
|
||||
#ifndef BUILDDATE
|
||||
#define BUILDDATE ""
|
||||
#define BUILDDATE "261010165717"
|
||||
#endif
|
||||
#define MAJOR3PROXY 0
|
||||
#define SUBMAJOR3PROXY 9
|
||||
#define MINOR3PROXY 9
|
||||
#define SUBMINOR3PROXY 0
|
||||
#define RELEASE3PROXY "3proxy-0.9.9(" BUILDDATE ")\0"
|
||||
#define SUBMINOR3PROXY 1
|
||||
#define RELEASE3PROXY "3proxy-0.9.9.1(" BUILDDATE ")\0"
|
||||
#ifndef YEAR3PROXY
|
||||
#define YEAR3PROXY "2026"
|
||||
#endif
|
||||
|
||||
Loading…
Reference in New Issue
Block a user