mirror of
https://github.com/3proxy/3proxy.git
synced 2026-11-07 02:05:49 +08:00
Compare commits
55 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
09cc61b66e | ||
|
|
f0c2782553 | ||
|
|
163022f00d | ||
|
|
a20014e20c | ||
|
|
be22ab3a0c | ||
|
|
6a35a902c5 | ||
|
|
d987d112a6 | ||
|
|
b15a35350f | ||
|
|
ae4011604f | ||
|
|
20302a67ff | ||
|
|
86457c3024 | ||
|
|
1e6adae3cd | ||
|
|
baad3f3543 | ||
|
|
0b126347c1 | ||
|
|
d211821240 | ||
|
|
29df50528a | ||
|
|
6fd58948f4 | ||
|
|
3b216e9ef3 | ||
|
|
144e2f3840 | ||
|
|
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 |
140
.github/workflows/build-ipk.yml
vendored
Normal file
140
.github/workflows/build-ipk.yml
vendored
Normal file
@ -0,0 +1,140 @@
|
|||||||
|
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
|
||||||
|
# 26.04: the OpenWrt SDK refuses its non-GNU install
|
||||||
|
runs-on: ubuntu-24.04
|
||||||
|
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:
|
workflow_dispatch:
|
||||||
|
|
||||||
permissions:
|
permissions:
|
||||||
contents: write
|
contents: read
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
ci:
|
ci:
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
id-token: write
|
||||||
|
attestations: write
|
||||||
name: "${{ matrix.target }}"
|
name: "${{ matrix.target }}"
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
@ -22,7 +26,11 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
pwd
|
pwd
|
||||||
echo "RELEASE=$(cat RELEASE)" >> $GITHUB_ENV
|
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
|
- name: echo env
|
||||||
run: echo "release $RELEASE version $VERSION"
|
run: echo "release $RELEASE version $VERSION"
|
||||||
- name: Linux libraries
|
- name: Linux libraries
|
||||||
@ -39,45 +47,142 @@ jobs:
|
|||||||
cp ~/rpmbuild/SOURCES/3proxy-$RELEASE.tar.gz ~/debian/3proxy_$RELEASE.orig.tar.gz
|
cp ~/rpmbuild/SOURCES/3proxy-$RELEASE.tar.gz ~/debian/3proxy_$RELEASE.orig.tar.gz
|
||||||
- name: rpmbuild
|
- name: rpmbuild
|
||||||
run: |
|
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
|
cd ~/rpmbuild/SPECS
|
||||||
rpmbuild -ba 3proxy-$RELEASE.spec
|
rpmbuild -ba \
|
||||||
cd $ret
|
--define "use_source_date_epoch_as_buildtime 1" \
|
||||||
mv ~/rpmbuild/RPMS/aarch64/3proxy-$RELEASE-1.aarch64.rpm 3proxy-$RELEASE.arm64.rpm
|
--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
|
- name: Get artifact rpm
|
||||||
uses: actions/upload-artifact@v7
|
uses: actions/upload-artifact@v7
|
||||||
with:
|
with:
|
||||||
name: "3proxy-${{ env.RELEASE }}-arm64.rpm"
|
name: "3proxy-${{ env.RELEASE }}-arm64.rpm"
|
||||||
path: "*.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
|
- name: debbuild
|
||||||
run: |
|
run: |
|
||||||
ret=`pwd`
|
docker run --rm \
|
||||||
cd ~/debian/
|
-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
|
tar xzf 3proxy_$RELEASE.orig.tar.gz
|
||||||
cd 3proxy-$RELEASE
|
cd 3proxy-$RELEASE
|
||||||
echo "3proxy ($RELEASE-$VERSION) buster; urgency=medium" >debian/changelog
|
{ echo "3proxy ($RELEASE-$VERSION) buster; urgency=medium"
|
||||||
echo " " >>debian/changelog
|
echo " "
|
||||||
echo " *3proxy $RELEASE build" >>debian/changelog
|
echo " *3proxy $RELEASE build"
|
||||||
echo " " >>debian/changelog
|
echo " "
|
||||||
echo " -- z3APA3A <3apa3a@3proxy.org> "`date "+%a, %d %b %Y %H:%M:%S %z"` >>debian/changelog
|
echo " -- z3APA3A <3apa3a@3proxy.org> $(date -R -u -d @$SOURCE_DATE_EPOCH)"
|
||||||
echo "">>debian/changelog
|
echo ""
|
||||||
dpkg-buildpackage
|
} > debian/changelog
|
||||||
cd $ret
|
dpkg-buildpackage'
|
||||||
cp ~/debian/3proxy_$RELEASE-"$VERSION"_arm64.deb ./3proxy-$RELEASE.arm64.deb
|
cp ~/debian/3proxy_$RELEASE-"$VERSION"_arm64.deb ./3proxy-$RELEASE.arm64.deb
|
||||||
- name: Get artifact deb
|
- name: Get artifact deb
|
||||||
uses: actions/upload-artifact@v7
|
uses: actions/upload-artifact@v7
|
||||||
with:
|
with:
|
||||||
name: "3proxy-${{ env.RELEASE }}-arm64.deb"
|
name: "3proxy-${{ env.RELEASE }}-arm64.deb"
|
||||||
path: "*.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'
|
if: github.event_name == 'release'
|
||||||
env:
|
env:
|
||||||
GH_TOKEN: ${{ github.token }}
|
GH_TOKEN: ${{ github.token }}
|
||||||
TAG: ${{ github.event.release.tag_name }}
|
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:
|
on:
|
||||||
release:
|
release:
|
||||||
@ -6,10 +6,14 @@ on:
|
|||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|
||||||
permissions:
|
permissions:
|
||||||
contents: write
|
contents: read
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
ci:
|
ci:
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
id-token: write
|
||||||
|
attestations: write
|
||||||
name: "${{ matrix.target }}"
|
name: "${{ matrix.target }}"
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
@ -22,35 +26,12 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
pwd
|
pwd
|
||||||
echo "RELEASE=$(cat RELEASE)" >> $GITHUB_ENV
|
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)
|
||||||
- name: Linux libraries
|
[ -n "$BUILDDATE" ] || BUILDDATE=$(date -u +%y%m%d%H%M%S)
|
||||||
run: |
|
echo "VERSION=$BUILDDATE" >> $GITHUB_ENV
|
||||||
sudo apt update
|
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)
|
||||||
sudo dpkg --add-architecture armhf
|
echo "SOURCE_DATE_EPOCH=$SOURCE_DATE_EPOCH" >> $GITHUB_ENV
|
||||||
echo "Types: deb" > ~/ubuntu.sources
|
- name: configure deb env
|
||||||
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
|
|
||||||
run: |
|
run: |
|
||||||
mkdir ~/debian
|
mkdir ~/debian
|
||||||
mkdir -p ~/rpmbuild/{BUILD,RPMS,SOURCES,SPECS,SRPMS}
|
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
|
ln -s ~/rpmbuild/SOURCES/3proxy-$RELEASE.tar.gz ~/rpmbuild/SOURCES/$RELEASE.tar.gz
|
||||||
cp scripts/rh/3proxy.spec ~/rpmbuild/SPECS/3proxy-$RELEASE.spec
|
cp scripts/rh/3proxy.spec ~/rpmbuild/SPECS/3proxy-$RELEASE.spec
|
||||||
cp ~/rpmbuild/SOURCES/3proxy-$RELEASE.tar.gz ~/debian/3proxy_$RELEASE.orig.tar.gz
|
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
|
- name: debbuild
|
||||||
run: |
|
run: |
|
||||||
ret=`pwd`
|
docker run --rm \
|
||||||
cd ~/debian/
|
-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
|
tar xzf 3proxy_$RELEASE.orig.tar.gz
|
||||||
cd 3proxy-$RELEASE
|
cd 3proxy-$RELEASE
|
||||||
echo "3proxy ($RELEASE-$VERSION) buster; urgency=medium" >debian/changelog
|
{ echo "3proxy ($RELEASE-$VERSION) buster; urgency=medium"
|
||||||
echo " " >>debian/changelog
|
echo " "
|
||||||
echo " *3proxy $RELEASE build" >>debian/changelog
|
echo " *3proxy $RELEASE build"
|
||||||
echo " " >>debian/changelog
|
echo " "
|
||||||
echo " -- z3APA3A <3apa3a@3proxy.org> "`date "+%a, %d %b %Y %H:%M:%S %z"` >>debian/changelog
|
echo " -- z3APA3A <3apa3a@3proxy.org> $(date -R -u -d @$SOURCE_DATE_EPOCH)"
|
||||||
echo "">>debian/changelog
|
echo ""
|
||||||
PATH=/usr/arm-linux-gnueabihf/bin:$PATH
|
} > debian/changelog
|
||||||
export PATH=$PATH
|
export PATH=/usr/arm-linux-gnueabihf/bin:$PATH
|
||||||
CC=arm-linux-gnueabihf-gcc
|
export 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
|
export LD_LIBRARY_PATH=/usr/arm-linux-gnueabihf/lib:$LD_LIBRARY_PATH
|
||||||
dpkg-buildpackage
|
dpkg-buildpackage'
|
||||||
cd $ret
|
|
||||||
cp ~/debian/3proxy_$RELEASE-"$VERSION"_armhf.deb ./3proxy-$RELEASE.arm.deb
|
cp ~/debian/3proxy_$RELEASE-"$VERSION"_armhf.deb ./3proxy-$RELEASE.arm.deb
|
||||||
- name: Get artifact deb
|
- name: Get artifact deb
|
||||||
uses: actions/upload-artifact@v7
|
uses: actions/upload-artifact@v7
|
||||||
with:
|
with:
|
||||||
name: "3proxy-${{ env.RELEASE }}-arm.deb"
|
name: "3proxy-${{ env.RELEASE }}-arm.deb"
|
||||||
path: "*.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'
|
if: github.event_name == 'release'
|
||||||
env:
|
env:
|
||||||
GH_TOKEN: ${{ github.token }}
|
GH_TOKEN: ${{ github.token }}
|
||||||
TAG: ${{ github.event.release.tag_name }}
|
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
|
||||||
|
|||||||
158
.github/workflows/build-rpm-x86-64.yml
vendored
158
.github/workflows/build-rpm-x86-64.yml
vendored
@ -6,15 +6,20 @@ on:
|
|||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|
||||||
permissions:
|
permissions:
|
||||||
contents: write
|
contents: read
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
ci:
|
ci:
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
id-token: write
|
||||||
|
attestations: write
|
||||||
name: "${{ matrix.target }}"
|
name: "${{ matrix.target }}"
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
target:
|
target:
|
||||||
- ubuntu-latest
|
# 26.04: rpm 6 runs %__gpg_sign_cmd differently, signing fails
|
||||||
|
- ubuntu-24.04
|
||||||
runs-on: ${{ matrix.target }}
|
runs-on: ${{ matrix.target }}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v7
|
- uses: actions/checkout@v7
|
||||||
@ -22,7 +27,11 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
pwd
|
pwd
|
||||||
echo "RELEASE=$(cat RELEASE)" >> $GITHUB_ENV
|
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
|
- name: echo env
|
||||||
run: echo "release $RELEASE version $VERSION"
|
run: echo "release $RELEASE version $VERSION"
|
||||||
- name: Linux libraries
|
- name: Linux libraries
|
||||||
@ -39,46 +48,143 @@ jobs:
|
|||||||
cp ~/rpmbuild/SOURCES/3proxy-$RELEASE.tar.gz ~/debian/3proxy_$RELEASE.orig.tar.gz
|
cp ~/rpmbuild/SOURCES/3proxy-$RELEASE.tar.gz ~/debian/3proxy_$RELEASE.orig.tar.gz
|
||||||
- name: rpmbuild
|
- name: rpmbuild
|
||||||
run: |
|
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
|
cd ~/rpmbuild/SPECS
|
||||||
rpmbuild -ba 3proxy-$RELEASE.spec
|
rpmbuild -ba \
|
||||||
cd $ret
|
--define "use_source_date_epoch_as_buildtime 1" \
|
||||||
mv ~/rpmbuild/RPMS/x86_64/3proxy-$RELEASE-1.x86_64.rpm 3proxy-$RELEASE.x86_64.rpm
|
--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
|
- name: Get artifact rpm
|
||||||
uses: actions/upload-artifact@v7
|
uses: actions/upload-artifact@v7
|
||||||
with:
|
with:
|
||||||
name: "3proxy-${{ env.RELEASE }}-x86_64.rpm"
|
name: "3proxy-${{ env.RELEASE }}-x86_64.rpm"
|
||||||
path: "*.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
|
- name: debbuild
|
||||||
run: |
|
run: |
|
||||||
ret=`pwd`
|
docker run --rm \
|
||||||
cd ~/debian/
|
-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
|
tar xzf 3proxy_$RELEASE.orig.tar.gz
|
||||||
cd 3proxy-$RELEASE
|
cd 3proxy-$RELEASE
|
||||||
echo "3proxy ($RELEASE-$VERSION) buster; urgency=medium" >debian/changelog
|
{ echo "3proxy ($RELEASE-$VERSION) buster; urgency=medium"
|
||||||
echo " " >>debian/changelog
|
echo " "
|
||||||
echo " *3proxy $RELEASE build" >>debian/changelog
|
echo " *3proxy $RELEASE build"
|
||||||
echo " " >>debian/changelog
|
echo " "
|
||||||
echo " -- z3APA3A <3apa3a@3proxy.org> "`date "+%a, %d %b %Y %H:%M:%S %z"` >>debian/changelog
|
echo " -- z3APA3A <3apa3a@3proxy.org> $(date -R -u -d @$SOURCE_DATE_EPOCH)"
|
||||||
echo "">>debian/changelog
|
echo ""
|
||||||
dpkg-buildpackage
|
} > debian/changelog
|
||||||
cd $ret
|
dpkg-buildpackage'
|
||||||
cp ~/debian/3proxy_$RELEASE-"$VERSION"_amd64.deb ./3proxy-$RELEASE.x86_64.deb
|
cp ~/debian/3proxy_$RELEASE-"$VERSION"_amd64.deb ./3proxy-$RELEASE.x86_64.deb
|
||||||
- name: Get artifact deb
|
- name: Get artifact deb
|
||||||
uses: actions/upload-artifact@v7
|
uses: actions/upload-artifact@v7
|
||||||
with:
|
with:
|
||||||
name: "3proxy-${{ env.RELEASE }}-x86_64.deb"
|
name: "3proxy-${{ env.RELEASE }}-x86_64.deb"
|
||||||
path: "*.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'
|
if: github.event_name == 'release'
|
||||||
env:
|
env:
|
||||||
GH_TOKEN: ${{ github.token }}
|
GH_TOKEN: ${{ github.token }}
|
||||||
TAG: ${{ github.event.release.tag_name }}
|
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:
|
workflow_dispatch:
|
||||||
|
|
||||||
permissions:
|
permissions:
|
||||||
contents: write
|
contents: read
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
ci:
|
ci:
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
id-token: write
|
||||||
|
attestations: write
|
||||||
name: "${{ matrix.target }}"
|
name: "${{ matrix.target }}"
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
@ -34,19 +38,8 @@ jobs:
|
|||||||
- name: make Watcom
|
- name: make Watcom
|
||||||
shell: cmd
|
shell: cmd
|
||||||
run: |
|
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
|
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
|
- name: make dist dir
|
||||||
shell: cmd
|
shell: cmd
|
||||||
run: |
|
run: |
|
||||||
@ -86,10 +79,30 @@ jobs:
|
|||||||
if: github.event_name == 'release'
|
if: github.event_name == 'release'
|
||||||
shell: pwsh
|
shell: pwsh
|
||||||
run: Compress-Archive -Path dist/* -DestinationPath 3proxy-${{ env.RELEASE }}-lite.zip
|
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
|
- name: Upload to release
|
||||||
if: github.event_name == 'release'
|
if: github.event_name == 'release'
|
||||||
shell: bash
|
shell: bash
|
||||||
env:
|
env:
|
||||||
GH_TOKEN: ${{ github.token }}
|
GH_TOKEN: ${{ github.token }}
|
||||||
TAG: ${{ github.event.release.tag_name }}
|
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:
|
workflow_dispatch:
|
||||||
|
|
||||||
permissions:
|
permissions:
|
||||||
contents: write
|
contents: read
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
ci:
|
ci:
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
id-token: write
|
||||||
|
attestations: write
|
||||||
name: "${{ matrix.target }}"
|
name: "${{ matrix.target }}"
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
@ -40,27 +44,8 @@ jobs:
|
|||||||
cd "D:/a/3proxy/3proxy"
|
cd "D:/a/3proxy/3proxy"
|
||||||
set "LIB=%LIB%;c:/vcpkg/installed/x86-windows-static/lib"
|
set "LIB=%LIB%;c:/vcpkg/installed/x86-windows-static/lib"
|
||||||
set "INCLUDE=%INCLUDE%;c:/vcpkg/installed/x86-windows-static/include"
|
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
|
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
|
- name: make dist dir
|
||||||
shell: cmd
|
shell: cmd
|
||||||
run: |
|
run: |
|
||||||
@ -91,7 +76,6 @@ jobs:
|
|||||||
copy authors dist\3proxy\
|
copy authors dist\3proxy\
|
||||||
copy README.md dist\3proxy\
|
copy README.md dist\3proxy\
|
||||||
copy rus.3ps dist\3proxy\
|
copy rus.3ps dist\3proxy\
|
||||||
copy 3proxy.crt dist\3proxy\
|
|
||||||
- name: Get artifact
|
- name: Get artifact
|
||||||
uses: actions/upload-artifact@v7
|
uses: actions/upload-artifact@v7
|
||||||
with:
|
with:
|
||||||
@ -101,10 +85,30 @@ jobs:
|
|||||||
if: github.event_name == 'release'
|
if: github.event_name == 'release'
|
||||||
shell: pwsh
|
shell: pwsh
|
||||||
run: Compress-Archive -Path dist/* -DestinationPath 3proxy-${{ env.RELEASE }}-x86.zip
|
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
|
- name: Upload to release
|
||||||
if: github.event_name == 'release'
|
if: github.event_name == 'release'
|
||||||
shell: bash
|
shell: bash
|
||||||
env:
|
env:
|
||||||
GH_TOKEN: ${{ github.token }}
|
GH_TOKEN: ${{ github.token }}
|
||||||
TAG: ${{ github.event.release.tag_name }}
|
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:
|
workflow_dispatch:
|
||||||
|
|
||||||
permissions:
|
permissions:
|
||||||
contents: write
|
contents: read
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
ci:
|
ci:
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
id-token: write
|
||||||
|
attestations: write
|
||||||
name: "${{ matrix.target }}"
|
name: "${{ matrix.target }}"
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
@ -40,28 +44,9 @@ jobs:
|
|||||||
cd "D:/a/3proxy/3proxy"
|
cd "D:/a/3proxy/3proxy"
|
||||||
set "LIB=%LIB%;c:/vcpkg/installed/x64-windows-static/lib"
|
set "LIB=%LIB%;c:/vcpkg/installed/x64-windows-static/lib"
|
||||||
set "INCLUDE=%INCLUDE%;c:/vcpkg/installed/x64-windows-static/include"
|
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%
|
echo %NOW% / %RELEASE% / %BUILDDATE% / %VERSION%
|
||||||
nmake /F Makefile.msvc WOLFSSL=1
|
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
|
- name: make dist dir
|
||||||
shell: cmd
|
shell: cmd
|
||||||
run: |
|
run: |
|
||||||
@ -92,7 +77,6 @@ jobs:
|
|||||||
copy authors dist\3proxy\
|
copy authors dist\3proxy\
|
||||||
copy README.md dist\3proxy\
|
copy README.md dist\3proxy\
|
||||||
copy rus.3ps dist\3proxy\
|
copy rus.3ps dist\3proxy\
|
||||||
copy 3proxy.crt dist\3proxy\
|
|
||||||
- name: Get artifact
|
- name: Get artifact
|
||||||
uses: actions/upload-artifact@v7
|
uses: actions/upload-artifact@v7
|
||||||
with:
|
with:
|
||||||
@ -102,10 +86,30 @@ jobs:
|
|||||||
if: github.event_name == 'release'
|
if: github.event_name == 'release'
|
||||||
shell: pwsh
|
shell: pwsh
|
||||||
run: Compress-Archive -Path dist/* -DestinationPath 3proxy-${{ env.RELEASE }}-x64.zip
|
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
|
- name: Upload to release
|
||||||
if: github.event_name == 'release'
|
if: github.event_name == 'release'
|
||||||
shell: bash
|
shell: bash
|
||||||
env:
|
env:
|
||||||
GH_TOKEN: ${{ github.token }}
|
GH_TOKEN: ${{ github.token }}
|
||||||
TAG: ${{ github.event.release.tag_name }}
|
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:
|
workflow_dispatch:
|
||||||
|
|
||||||
permissions:
|
permissions:
|
||||||
contents: write
|
contents: read
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
ci:
|
ci:
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
id-token: write
|
||||||
|
attestations: write
|
||||||
name: "${{ matrix.target }}"
|
name: "${{ matrix.target }}"
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
@ -40,27 +44,8 @@ jobs:
|
|||||||
cd "D:/a/3proxy/3proxy"
|
cd "D:/a/3proxy/3proxy"
|
||||||
set "LIB=%LIB%;c:/vcpkg/installed/arm64-windows-static/lib"
|
set "LIB=%LIB%;c:/vcpkg/installed/arm64-windows-static/lib"
|
||||||
set "INCLUDE=%INCLUDE%;c:/vcpkg/installed/arm64-windows-static/include"
|
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
|
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
|
- name: make dist dir
|
||||||
shell: cmd
|
shell: cmd
|
||||||
run: |
|
run: |
|
||||||
@ -91,7 +76,6 @@ jobs:
|
|||||||
copy authors dist\3proxy\
|
copy authors dist\3proxy\
|
||||||
copy README.md dist\3proxy\
|
copy README.md dist\3proxy\
|
||||||
copy rus.3ps dist\3proxy\
|
copy rus.3ps dist\3proxy\
|
||||||
copy 3proxy.crt dist\3proxy\
|
|
||||||
- name: Get artifact
|
- name: Get artifact
|
||||||
uses: actions/upload-artifact@v7
|
uses: actions/upload-artifact@v7
|
||||||
with:
|
with:
|
||||||
@ -101,10 +85,30 @@ jobs:
|
|||||||
if: github.event_name == 'release'
|
if: github.event_name == 'release'
|
||||||
shell: pwsh
|
shell: pwsh
|
||||||
run: Compress-Archive -Path dist/* -DestinationPath 3proxy-${{ env.RELEASE }}-arm64.zip
|
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
|
- name: Upload to release
|
||||||
if: github.event_name == 'release'
|
if: github.event_name == 'release'
|
||||||
shell: bash
|
shell: bash
|
||||||
env:
|
env:
|
||||||
GH_TOKEN: ${{ github.token }}
|
GH_TOKEN: ${{ github.token }}
|
||||||
TAG: ${{ github.event.release.tag_name }}
|
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:
|
on:
|
||||||
release:
|
release:
|
||||||
@ -7,89 +7,187 @@ on:
|
|||||||
|
|
||||||
permissions:
|
permissions:
|
||||||
contents: read
|
contents: read
|
||||||
id-token: write
|
|
||||||
|
|
||||||
env:
|
env:
|
||||||
REGISTRY: docker.io
|
DOCKERHUB_IMAGE: docker.io/3proxy/3proxy
|
||||||
IMAGE_NAME: 3proxy/3proxy
|
GHCR_IMAGE: ghcr.io/3proxy/3proxy
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
name: Build and push Docker images
|
name: ${{ matrix.image }} ${{ matrix.platform }}
|
||||||
runs-on: ubuntu-latest
|
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:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v7
|
uses: actions/checkout@v7
|
||||||
|
|
||||||
- name: Determine tags
|
- name: Platform name
|
||||||
id: tags
|
id: platform
|
||||||
env:
|
run: echo "pair=$(echo '${{ matrix.platform }}' | tr / -)" >> "$GITHUB_OUTPUT"
|
||||||
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: Set up QEMU
|
- name: Set up QEMU
|
||||||
|
if: matrix.platform == 'linux/arm/v7'
|
||||||
uses: docker/setup-qemu-action@v4
|
uses: docker/setup-qemu-action@v4
|
||||||
|
|
||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
uses: docker/setup-buildx-action@v4
|
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
|
- name: Install cosign
|
||||||
uses: sigstore/cosign-installer@v3
|
uses: sigstore/cosign-installer@v3
|
||||||
|
with:
|
||||||
|
cosign-release: v2.4.3
|
||||||
|
|
||||||
- name: Login to Docker Hub
|
- name: Login to Docker Hub
|
||||||
if: github.event_name != 'pull_request'
|
|
||||||
uses: docker/login-action@v4
|
uses: docker/login-action@v4
|
||||||
with:
|
with:
|
||||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||||
|
|
||||||
- name: Build and push minimal
|
- name: Login to GHCR
|
||||||
uses: docker/build-push-action@v7
|
uses: docker/login-action@v4
|
||||||
with:
|
with:
|
||||||
context: .
|
registry: ghcr.io
|
||||||
file: Dockerfile.minimal
|
username: ${{ github.actor }}
|
||||||
platforms: linux/amd64,linux/arm64,linux/arm/v7,ppc64le
|
password: ${{ secrets.GITHUB_TOKEN }}
|
||||||
push: ${{ github.event_name != 'pull_request' }}
|
|
||||||
tags: ${{ steps.tags.outputs.minimal }}
|
|
||||||
|
|
||||||
- name: Build and push busybox
|
- name: Determine tags
|
||||||
uses: docker/build-push-action@v7
|
id: tags
|
||||||
with:
|
env:
|
||||||
context: .
|
RELEASE_TAG: ${{ github.event.release.tag_name }}
|
||||||
file: Dockerfile.busybox
|
SUFFIX: ${{ matrix.suffix }}
|
||||||
platforms: linux/amd64,linux/arm64,linux/arm/v7,ppc64le
|
FLOATING: ${{ matrix.floating }}
|
||||||
push: ${{ github.event_name != 'pull_request' }}
|
run: |
|
||||||
tags: ${{ steps.tags.outputs.busybox }}
|
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
|
- name: Create manifest list and push
|
||||||
uses: docker/build-push-action@v7
|
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:
|
with:
|
||||||
context: .
|
subject-name: ${{ env.DOCKERHUB_IMAGE }}
|
||||||
file: Dockerfile.full
|
subject-digest: ${{ steps.digest.outputs.digest }}
|
||||||
platforms: linux/amd64,linux/arm64,linux/arm/v7,ppc64le
|
push-to-registry: false
|
||||||
push: ${{ github.event_name != 'pull_request' }}
|
|
||||||
tags: ${{ steps.tags.outputs.full }}
|
- 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
|
- name: Sign images
|
||||||
if: github.event_name != 'pull_request'
|
|
||||||
env:
|
env:
|
||||||
TAGS_MINIMAL: ${{ steps.tags.outputs.minimal }}
|
DIGEST: ${{ steps.digest.outputs.digest }}
|
||||||
TAGS_BUSYBOX: ${{ steps.tags.outputs.busybox }}
|
|
||||||
TAGS_FULL: ${{ steps.tags.outputs.full }}
|
|
||||||
run: |
|
run: |
|
||||||
IFS=',' read -ra TAGS <<< "$TAGS_MINIMAL,$TAGS_BUSYBOX,$TAGS_FULL"
|
cosign sign --yes "${DOCKERHUB_IMAGE}@${DIGEST}"
|
||||||
for tag in "${TAGS[@]}"; do
|
cosign sign --yes "${GHCR_IMAGE}@${DIGEST}"
|
||||||
cosign sign --yes "$tag"
|
|
||||||
done
|
|
||||||
|
|||||||
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-----
|
||||||
32
CHANGELOG
32
CHANGELOG
@ -1,18 +1,16 @@
|
|||||||
3proxy-0.9.9 Released August, 20 2026
|
3proxy-0.9.9.2 Released October, 24 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: dnspr relayed to the client whatever came first to the socket it asked the name server from, from any address and under any id, so a forged answer could be passed on; the query now goes out under a random id, and only an answer from the name server asked, with that id and the same question, is relayed
|
||||||
! Fix: socket leak with SOCKSv5 UDP ASSOCIATE through a parent proxy, sockets were accumulated in CLOSE_WAIT state until descriptors ran out
|
! Fix: a client sending a part of a TLS record and then nothing kept a thread taking all of a CPU, and the read never timed out
|
||||||
! Fix: file descriptor leak in HTTP proxy on the ftp:// request path
|
! Fix: without -Ne, the reply to SOCKS CONNECT and BIND gave the address of the client's connection to the proxy instead of the socket towards the destination: a BIND client was told the proxy's own port and the peer could never reach it (since 0.9.6)
|
||||||
! Fix: crash with illegal instruction on some platforms (e.g. some musl based Linux builds), caused by a memcpy on overlapping buffers
|
! Fix: a client which shut down its sending side (half-close) could get the answer cut short, megabytes short with large answers; likewise an upload after the server half-closed
|
||||||
! Fix: extip and ha (HAProxy PROXY protocol) parents are applied to SOCKSv5 UDP ASSOCIATE now
|
! Fix: with chroot every local time was UTC and every syslog message was lost: the time zone is loaded and syslog connected before chroot; the chroot entry of 3proxy.cfg(5) lists what PAM, LDAP and ODBC still need inside the chroot
|
||||||
! Fix: only socks5 and socks5+ parents are tried for UDP ASSOCIATE, other parent types can not be used for UDP
|
! Fix: the HTTP proxy closed the server connection of a kept-alive client and opened another one when only the request method changed (a POST after a GET to the same host)
|
||||||
! Fix: udppm through a SOCKSv5 parent did not work
|
! Fix: the last ssl_client_mode in the configuration applied to every service, and a reload changed it for the services still running
|
||||||
! 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: memory leaks: on every refused configuration reload, on every failed TLS handshake, the server CA paths of every TLS service
|
||||||
! Fix: -4 / -6 handling for UDP in socks; a single UDP association can use both IPv4 and IPv6 destinations now
|
! Fix: Unix sockets: on Linux a proxy listening on a Unix socket relayed only the first bytes of an answer (result 95); an abstract socket (unix:@NAME) was bound under a name padded with zeros, which clients did not reach; tcppm refused port 0 for a unix: target, as given in the manual's example; on a reload the socket file of a listening service was removed
|
||||||
! Fix: a datagram with a null destination address is dropped now
|
! Fix: SIGPIPE could kill 3proxy when a client was gone while services were starting, and standalone services (proxy, socks, ...) at any time; sends use MSG_NOSIGNAL where the system has it
|
||||||
! Fix: DNS over TCP: a reply which did not fit a single read was never processed
|
! Fix: TLS MitM failed for every connection with wolfSSL built with WOLFSSL_QT (wolfSSL 5.9.1 of Ubuntu 26.04): the source certificate's serial number could not be copied; a serial number made from the hash of the source certificate is used then
|
||||||
! 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
|
! Fix: Windows: closing a connection could leave its socket open (SO_LINGER on a non-blocking socket) or reset it while the peer still sent, so the end of an answer could be lost
|
||||||
+ 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
|
! Fix: standalone port mappers (tcppm, udppm, tlspr) built with CMake were built as if they were not port mappers
|
||||||
+ socks: -U option to control what happens when the destination changes within an UDP association: log it, authorize it, both (default) or neither
|
- splice() is built by default on Linux again and is used only by services given -s
|
||||||
+ -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
|
|
||||||
|
|||||||
@ -1,18 +1,16 @@
|
|||||||
3proxy-0.9.9 Вышел 20 Августа 2026
|
3proxy-0.9.9.2 Вышел 24 Октября 2026
|
||||||
|
|
||||||
! Исправление: ответы DNS теперь проверяются: ответ с адреса, отличного от адреса сервера имён, которому был отправлен запрос, а также ответ с секцией вопроса, не совпадающей с запросом, отбрасываются; ранее оба принимались
|
! Исправление: dnspr передавал клиенту то, что первым пришло на сокет, с которого он обращался к серверу имён, с любого адреса и с любым id, так что поддельный ответ мог быть передан клиенту; теперь запрос отправляется со случайным id, и передаётся только ответ от того сервера имён, к которому обращались, с этим id и тем же вопросом
|
||||||
! Исправление: утечка сокетов при SOCKSv5 UDP ASSOCIATE через вышестоящий прокси, сокеты накапливались в состоянии CLOSE_WAIT до исчерпания дескрипторов
|
! Исправление: клиент, отправивший часть записи TLS и затем ничего, занимал поток на всё процессорное время, и чтение не завершалось по таймауту
|
||||||
! Исправление: утечка файловых дескрипторов в HTTP-прокси на пути обработки запроса ftp://
|
! Исправление: без -Ne ответ на SOCKS CONNECT и BIND содержал адрес соединения клиента с прокси вместо адреса сокета в сторону назначения: клиенту BIND сообщался собственный порт прокси, и удалённая сторона не могла к нему подключиться (с 0.9.6)
|
||||||
! Исправление: аварийное завершение с недопустимой инструкцией на некоторых платформах (например, в некоторых сборках Linux на основе musl) из-за memcpy на перекрывающихся буферах
|
! Исправление: клиент, закрывший свою сторону передачи (half-close), мог получить ответ не полностью, на больших ответах без нескольких мегабайт; так же обрезалась загрузка на сервер после того, как сервер закрыл свою сторону
|
||||||
! Исправление: родители типа extip и ha (HAProxy PROXY protocol) теперь применяются к SOCKSv5 UDP ASSOCIATE
|
! Исправление: при chroot всё местное время становилось UTC и все сообщения syslog терялись: часовой пояс теперь загружается, а syslog подключается до chroot; в описании chroot в 3proxy.cfg(5) перечислено, что ещё нужно внутри chroot для PAM, LDAP и ODBC
|
||||||
! Исправление: для UDP ASSOCIATE используются только родители socks5 и socks5+, остальные типы для UDP неприменимы
|
! Исправление: HTTP прокси закрывал соединение с сервером для клиента с keep-alive и открывал новое, когда менялся только метод запроса (POST после GET к тому же хосту)
|
||||||
! Исправление: udppm через вышестоящий прокси SOCKSv5 не работал
|
! Исправление: последний ssl_client_mode в конфигурации действовал для всех служб, а перезагрузка конфигурации меняла его для уже работающих служб
|
||||||
! Исправление: опции -Ne и -Ni никогда не применялись, буква опции не разбиралась; -Ne больше не применяется к ответу на UDP ASSOCIATE, -Ni применяется к нему
|
! Исправление: утечки памяти: при каждой отвергнутой перезагрузке конфигурации, при каждом неудачном согласовании TLS, пути CA сервера каждой службы с TLS
|
||||||
! Исправление: обработка -4 / -6 для UDP в socks; одна UDP-ассоциация теперь может использовать адреса назначения и IPv4, и IPv6
|
! Исправление: сокеты Unix: в Linux прокси, слушающий на сокете Unix, передавал только первые байты ответа (результат 95); абстрактный сокет (unix:@NAME) привязывался к имени, дополненному нулями, до которого клиенты не доходили; tcppm отвергал порт 0 для цели unix:, как в примере из документации; при перезагрузке конфигурации файл сокета слушающей службы удалялся
|
||||||
! Исправление: датаграмма с нулевым адресом назначения теперь отбрасывается
|
! Исправление: SIGPIPE мог завершить 3proxy, если клиент отключался во время запуска служб, а отдельные службы (proxy, socks, ...) — в любой момент; отправка данных использует MSG_NOSIGNAL там, где система его поддерживает
|
||||||
! Исправление: DNS поверх TCP: ответ, не помещавшийся в одно чтение, никогда не обрабатывался
|
! Исправление: TLS MitM не работал ни для одного соединения с wolfSSL, собранным с WOLFSSL_QT (wolfSSL 5.9.1 в Ubuntu 26.04): не удавалось скопировать серийный номер исходного сертификата; в этом случае используется серийный номер, полученный из хеша исходного сертификата
|
||||||
! Документация: в HOWTO добавлен раздел "Как применять ACL к UDP-трафику"; в "Optimizing 3proxy for High Load" и в рекомендации по безопасности добавлены заметки о кэше аутентификации, ACL и UDP
|
! Исправление: Windows: при закрытии соединения сокет мог остаться открытым (SO_LINGER на неблокирующем сокете) или соединение сбрасывалось, пока другая сторона ещё передавала данные, так что конец ответа мог потеряться
|
||||||
+ SOCKSv5 UDP: адрес назначения каждой датаграммы авторизуется, поэтому ACL, ограничивающие адрес назначения, имя хоста или порт, теперь применяются к UDP-трафику; вышестоящий прокси и внешний адрес выбираются для адреса назначения датаграммы, а не для запроса UDP ASSOCIATE
|
! Исправление: отдельные портмапперы (tcppm, udppm, tlspr), собранные с CMake, собирались так, как будто они не портмапперы
|
||||||
+ socks: опция -U для управления тем, что происходит при смене адреса назначения в рамках UDP-ассоциации: журналировать, авторизовать, и то и другое (по умолчанию) или ничего
|
- splice() снова собирается по умолчанию в Linux и используется только службами с -s
|
||||||
+ Опция -C (для TCP-сервисов) завершает сессию, как только любая из сторон закрывает соединение; по умолчанию сессия сохраняется, пока соединение не закроют обе стороны (полузакрытие TCP)
|
|
||||||
+ timeouts: добавлено значение LINGER (11-е, по умолчанию 5), используется для доставки буферизованных данных после того, как одна из сторон закрыла свою передающую сторону, а также как значение SO_LINGER для исходящих соединений
|
|
||||||
|
|||||||
@ -51,7 +51,7 @@ option(3PROXY_USE_OPENSSL "Enable TLS/SSL support via OpenSSL (fallback when wol
|
|||||||
option(3PROXY_USE_PCRE2 "Enable PCRE2 regex filtering" ON)
|
option(3PROXY_USE_PCRE2 "Enable PCRE2 regex filtering" ON)
|
||||||
option(3PROXY_USE_PAM "Enable PAM/PamAuth" ON)
|
option(3PROXY_USE_PAM "Enable PAM/PamAuth" ON)
|
||||||
option(3PROXY_USE_ODBC "Enable ODBC support (Unix only, always ON on Windows)" OFF)
|
option(3PROXY_USE_ODBC "Enable ODBC support (Unix only, always ON on Windows)" OFF)
|
||||||
option(3PROXY_USE_SPLICE "Build Linux splice() support, slower than read/write for most traffic (Linux only)" OFF)
|
option(3PROXY_USE_SPLICE "Build Linux splice() support, used by services given -s (Linux only)" ON)
|
||||||
option(3PROXY_USE_POLL "Use poll() instead of select() (Unix only)" ON)
|
option(3PROXY_USE_POLL "Use poll() instead of select() (Unix only)" ON)
|
||||||
option(3PROXY_USE_WSAPOLL "Use WSAPoll instead of select() (Windows only)" ON)
|
option(3PROXY_USE_WSAPOLL "Use WSAPoll instead of select() (Windows only)" ON)
|
||||||
option(3PROXY_USE_NETFILTER "Enable Linux netfilter support (Linux only)" ON)
|
option(3PROXY_USE_NETFILTER "Enable Linux netfilter support (Linux only)" ON)
|
||||||
@ -664,10 +664,7 @@ foreach(PROXY_NAME proxy socks pop3p imapp smtpp ftppr tcppm udppm tlspr)
|
|||||||
${CMAKE_CURRENT_SOURCE_DIR}/src
|
${CMAKE_CURRENT_SOURCE_DIR}/src
|
||||||
)
|
)
|
||||||
|
|
||||||
target_compile_definitions(${PROXY_NAME} PRIVATE
|
target_compile_definitions(${PROXY_NAME} PRIVATE WITHMAIN)
|
||||||
WITHMAIN
|
|
||||||
NOPORTMAP
|
|
||||||
)
|
|
||||||
|
|
||||||
if(NOT PROXY_NAME STREQUAL "udppm")
|
if(NOT PROXY_NAME STREQUAL "udppm")
|
||||||
target_compile_definitions(${PROXY_NAME} PRIVATE NOUDPMAIN)
|
target_compile_definitions(${PROXY_NAME} PRIVATE NOUDPMAIN)
|
||||||
@ -679,8 +676,12 @@ foreach(PROXY_NAME proxy socks pop3p imapp smtpp ftppr tcppm udppm tlspr)
|
|||||||
target_compile_definitions(${PROXY_NAME} PRIVATE ANONYMOUS)
|
target_compile_definitions(${PROXY_NAME} PRIVATE ANONYMOUS)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
# port mappers take port, host and port as arguments, the others options
|
||||||
|
# only; one of the two is defined, as in src/Makefile.inc
|
||||||
if(PROXY_NAME STREQUAL "tcppm" OR PROXY_NAME STREQUAL "udppm" OR PROXY_NAME STREQUAL "tlspr")
|
if(PROXY_NAME STREQUAL "tcppm" OR PROXY_NAME STREQUAL "udppm" OR PROXY_NAME STREQUAL "tlspr")
|
||||||
target_compile_definitions(${PROXY_NAME} PRIVATE PORTMAP)
|
target_compile_definitions(${PROXY_NAME} PRIVATE PORTMAP)
|
||||||
|
else()
|
||||||
|
target_compile_definitions(${PROXY_NAME} PRIVATE NOPORTMAP)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(WIN32)
|
if(WIN32)
|
||||||
|
|||||||
@ -52,14 +52,14 @@ ifeq ($(LIBSTATIC), true)
|
|||||||
STATIC_SUFFIX = -Wl,-Bdynamic
|
STATIC_SUFFIX = -Wl,-Bdynamic
|
||||||
ZLIB = -lz -lzstd
|
ZLIB = -lz -lzstd
|
||||||
endif
|
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)
|
ifeq ($(WOLFSSL_CHECK), true)
|
||||||
LIBS += $(STATIC_PREFIX) -lwolfssl $(STATIC_SUFFIX)
|
LIBS += $(STATIC_PREFIX) -lwolfssl $(STATIC_SUFFIX)
|
||||||
CFLAGS += -DWITH_SSL -DWITH_WOLFSSL
|
CFLAGS += -DWITH_SSL -DWITH_WOLFSSL
|
||||||
SSL_OBJS = ssllib$(OBJSUFFICS) ssl$(OBJSUFFICS)
|
SSL_OBJS = ssllib$(OBJSUFFICS) ssl$(OBJSUFFICS)
|
||||||
ZLIB :=
|
ZLIB :=
|
||||||
else
|
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)
|
ifeq ($(OPENSSL_CHECK), true)
|
||||||
LIBS += $(STATIC_PREFIX) $(ZLIB) -l crypto -l ssl $(STATIC_SUFFIX)
|
LIBS += $(STATIC_PREFIX) $(ZLIB) -l crypto -l ssl $(STATIC_SUFFIX)
|
||||||
CFLAGS += -DWITH_SSL
|
CFLAGS += -DWITH_SSL
|
||||||
@ -68,13 +68,13 @@ else
|
|||||||
ZLIB :=
|
ZLIB :=
|
||||||
endif
|
endif
|
||||||
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)
|
ifeq ($(PCRE_CHECK), true)
|
||||||
CFLAGS += -DWITH_PCRE
|
CFLAGS += -DWITH_PCRE
|
||||||
PCRE_OBJS = pcre$(OBJSUFFICS)
|
PCRE_OBJS = pcre$(OBJSUFFICS)
|
||||||
PCRE_LIBS = $(STATIC_PREFIX) -lpcre2-8 $(STATIC_SUFFIX)
|
PCRE_LIBS = $(STATIC_PREFIX) -lpcre2-8 $(STATIC_SUFFIX)
|
||||||
endif
|
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)
|
ifeq ($(PAM_CHECK), true)
|
||||||
PLUGINS += PamAuth
|
PLUGINS += PamAuth
|
||||||
endif
|
endif
|
||||||
|
|||||||
@ -4,9 +4,9 @@
|
|||||||
# add -DWITH_ODBC to CFLAGS and -lodbc to LIBS to compile with ODBC
|
# add -DWITH_ODBC to CFLAGS and -lodbc to LIBS to compile with ODBC
|
||||||
# library support. Add -DSAFESQL for poorely written ODBC library / drivers.
|
# library support. Add -DSAFESQL for poorely written ODBC library / drivers.
|
||||||
#
|
#
|
||||||
# Linux splice() support is not built by default, it is slower than the
|
# Linux splice() support is built, but used only by services given the -s
|
||||||
# read/write path for most traffic. Add -DWITHSPLICE to CFLAGS to build it,
|
# option: it is faster for large transfers and slower for small requests.
|
||||||
# it must additionally be enabled per service with the -s option.
|
# Remove -DWITHSPLICE from CFLAGS to build without it.
|
||||||
|
|
||||||
BUILDDIR = ../bin/
|
BUILDDIR = ../bin/
|
||||||
PREFIX ?= 3proxy_
|
PREFIX ?= 3proxy_
|
||||||
@ -14,7 +14,7 @@ CRYPT_PREFIX ?= $(PREFIX)
|
|||||||
CC ?= gcc
|
CC ?= gcc
|
||||||
|
|
||||||
CFLAGS ?= -O3 -flto
|
CFLAGS ?= -O3 -flto
|
||||||
CFLAGS += -fno-strict-aliasing -c -pthread -D_GNU_SOURCE -DGETHOSTBYNAME_R -D_THREAD_SAFE -D_REENTRANT -DFD_SETSIZE=4096 -DWITH_POLL -DWITH_NETFILTER -D WITH_UN
|
CFLAGS += -fno-strict-aliasing -c -pthread -DWITHSPLICE -D_GNU_SOURCE -DGETHOSTBYNAME_R -D_THREAD_SAFE -D_REENTRANT -DFD_SETSIZE=4096 -DWITH_POLL -DWITH_NETFILTER -D WITH_UN
|
||||||
COUT = -o
|
COUT = -o
|
||||||
LN ?= ${CC}
|
LN ?= ${CC}
|
||||||
DCFLAGS ?= -fPIC
|
DCFLAGS ?= -fPIC
|
||||||
@ -60,14 +60,14 @@ ifeq ($(LIBSTATIC), true)
|
|||||||
ZLIB = -lz -lzstd
|
ZLIB = -lz -lzstd
|
||||||
endif
|
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)
|
ifeq ($(WOLFSSL_CHECK), true)
|
||||||
LIBS += $(STATIC_PREFIX) -lwolfssl $(STATIC_SUFFIX)
|
LIBS += $(STATIC_PREFIX) -lwolfssl $(STATIC_SUFFIX)
|
||||||
CFLAGS += -DWITH_SSL -DWITH_WOLFSSL
|
CFLAGS += -DWITH_SSL -DWITH_WOLFSSL
|
||||||
SSL_OBJS = ssllib$(OBJSUFFICS) ssl$(OBJSUFFICS)
|
SSL_OBJS = ssllib$(OBJSUFFICS) ssl$(OBJSUFFICS)
|
||||||
ZLIB :=
|
ZLIB :=
|
||||||
else
|
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)
|
ifeq ($(OPENSSL_CHECK), true)
|
||||||
LIBS += $(STATIC_PREFIX) $(ZLIB) -lcrypto -lssl $(STATIC_SUFFIX)
|
LIBS += $(STATIC_PREFIX) $(ZLIB) -lcrypto -lssl $(STATIC_SUFFIX)
|
||||||
CFLAGS += -DWITH_SSL
|
CFLAGS += -DWITH_SSL
|
||||||
@ -76,13 +76,13 @@ else
|
|||||||
ZLIB :=
|
ZLIB :=
|
||||||
endif
|
endif
|
||||||
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)
|
ifeq ($(PCRE_CHECK), true)
|
||||||
CFLAGS += -DWITH_PCRE
|
CFLAGS += -DWITH_PCRE
|
||||||
PCRE_OBJS = pcre$(OBJSUFFICS)
|
PCRE_OBJS = pcre$(OBJSUFFICS)
|
||||||
PCRE_LIBS = $(STATIC_PREFIX) -lpcre2-8 $(STATIC_SUFFIX)
|
PCRE_LIBS = $(STATIC_PREFIX) -lpcre2-8 $(STATIC_SUFFIX)
|
||||||
endif
|
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)
|
ifeq ($(PAM_CHECK), true)
|
||||||
PLUGINS += PamAuth
|
PLUGINS += PamAuth
|
||||||
endif
|
endif
|
||||||
|
|||||||
@ -31,20 +31,20 @@ COMPATLIBS =
|
|||||||
MAKEFILE = Makefile.Solaris
|
MAKEFILE = Makefile.Solaris
|
||||||
PLUGINS = StringsPlugin TrafficPlugin TransparentPlugin FilePlugin
|
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)
|
ifeq ($(WOLFSSL_CHECK), true)
|
||||||
LIBS += -lwolfssl
|
LIBS += -lwolfssl
|
||||||
CFLAGS += -DWITH_SSL -DWITH_WOLFSSL
|
CFLAGS += -DWITH_SSL -DWITH_WOLFSSL
|
||||||
SSL_OBJS = ssllib$(OBJSUFFICS) ssl$(OBJSUFFICS)
|
SSL_OBJS = ssllib$(OBJSUFFICS) ssl$(OBJSUFFICS)
|
||||||
else
|
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)
|
ifeq ($(OPENSSL_CHECK), true)
|
||||||
LIBS += -l crypto -l ssl
|
LIBS += -l crypto -l ssl
|
||||||
CFLAGS += -DWITH_SSL
|
CFLAGS += -DWITH_SSL
|
||||||
SSL_OBJS = ssllib$(OBJSUFFICS) ssl$(OBJSUFFICS)
|
SSL_OBJS = ssllib$(OBJSUFFICS) ssl$(OBJSUFFICS)
|
||||||
endif
|
endif
|
||||||
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)
|
ifeq ($(PCRE_CHECK), true)
|
||||||
CFLAGS += -DWITH_PCRE
|
CFLAGS += -DWITH_PCRE
|
||||||
PCRE_OBJS = pcre$(OBJSUFFICS)
|
PCRE_OBJS = pcre$(OBJSUFFICS)
|
||||||
|
|||||||
@ -54,14 +54,14 @@ ifeq ($(LIBSTATIC), true)
|
|||||||
STATIC_SUFFIX = -Wl,-Bdynamic
|
STATIC_SUFFIX = -Wl,-Bdynamic
|
||||||
ZLIB = -lz -lzstd
|
ZLIB = -lz -lzstd
|
||||||
endif
|
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)
|
ifeq ($(WOLFSSL_CHECK), true)
|
||||||
LIBS += $(STATIC_PREFIX) -lwolfssl $(STATIC_SUFFIX)
|
LIBS += $(STATIC_PREFIX) -lwolfssl $(STATIC_SUFFIX)
|
||||||
CFLAGS += -DWITH_SSL -DWITH_WOLFSSL
|
CFLAGS += -DWITH_SSL -DWITH_WOLFSSL
|
||||||
SSL_OBJS = ssllib$(OBJSUFFICS) ssl$(OBJSUFFICS)
|
SSL_OBJS = ssllib$(OBJSUFFICS) ssl$(OBJSUFFICS)
|
||||||
ZLIB :=
|
ZLIB :=
|
||||||
else
|
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)
|
ifeq ($(OPENSSL_CHECK), true)
|
||||||
LIBS += $(STATIC_PREFIX) $(ZLIB) -lcrypto -lssl $(STATIC_SUFFIX)
|
LIBS += $(STATIC_PREFIX) $(ZLIB) -lcrypto -lssl $(STATIC_SUFFIX)
|
||||||
CFLAGS += -DWITH_SSL
|
CFLAGS += -DWITH_SSL
|
||||||
@ -70,13 +70,13 @@ else
|
|||||||
ZLIB :=
|
ZLIB :=
|
||||||
endif
|
endif
|
||||||
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)
|
ifeq ($(PCRE_CHECK), true)
|
||||||
CFLAGS += -DWITH_PCRE
|
CFLAGS += -DWITH_PCRE
|
||||||
PCRE_OBJS = pcre$(OBJSUFFICS)
|
PCRE_OBJS = pcre$(OBJSUFFICS)
|
||||||
PCRE_LIBS = $(STATIC_PREFIX) -lpcre2-8 $(STATIC_SUFFIX)
|
PCRE_LIBS = $(STATIC_PREFIX) -lpcre2-8 $(STATIC_SUFFIX)
|
||||||
endif
|
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)
|
ifeq ($(PAM_CHECK), true)
|
||||||
PLUGINS += PamAuth
|
PLUGINS += PamAuth
|
||||||
endif
|
endif
|
||||||
|
|||||||
@ -47,14 +47,14 @@ ifeq ($(LIBSTATIC), true)
|
|||||||
STATIC_SUFFIX = -Wl,-Bdynamic
|
STATIC_SUFFIX = -Wl,-Bdynamic
|
||||||
ZLIB = -lz
|
ZLIB = -lz
|
||||||
endif
|
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)
|
ifeq ($(WOLFSSL_CHECK), true)
|
||||||
LIBS += $(STATIC_PREFIX) -lwolfssl $(STATIC_SUFFIX) -lws2_32
|
LIBS += $(STATIC_PREFIX) -lwolfssl $(STATIC_SUFFIX) -lws2_32
|
||||||
CFLAGS += -DWITH_SSL -DWITH_WOLFSSL
|
CFLAGS += -DWITH_SSL -DWITH_WOLFSSL
|
||||||
SSL_OBJS = ssllib$(OBJSUFFICS) ssl$(OBJSUFFICS)
|
SSL_OBJS = ssllib$(OBJSUFFICS) ssl$(OBJSUFFICS)
|
||||||
ZLIB :=
|
ZLIB :=
|
||||||
else
|
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)
|
ifeq ($(OPENSSL_CHECK), true)
|
||||||
LIBS += $(STATIC_PREFIX) $(ZLIB) -l crypto -l ssl $(STATIC_SUFFIX) -lcrypt32
|
LIBS += $(STATIC_PREFIX) $(ZLIB) -l crypto -l ssl $(STATIC_SUFFIX) -lcrypt32
|
||||||
CFLAGS += -DWITH_SSL
|
CFLAGS += -DWITH_SSL
|
||||||
@ -63,11 +63,11 @@ else
|
|||||||
ZLIB :=
|
ZLIB :=
|
||||||
endif
|
endif
|
||||||
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)
|
ifeq ($(PAM_CHECK), true)
|
||||||
PLUGINS += PamAuth
|
PLUGINS += PamAuth
|
||||||
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) $(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)
|
ifeq ($(PCRE_CHECK), true)
|
||||||
CFLAGS += -DWITH_PCRE
|
CFLAGS += -DWITH_PCRE
|
||||||
PCRE_OBJS = pcre$(OBJSUFFICS)
|
PCRE_OBJS = pcre$(OBJSUFFICS)
|
||||||
|
|||||||
59
README.md
59
README.md
@ -6,13 +6,52 @@
|
|||||||
|
|
||||||
### Branches
|
### Branches
|
||||||
|
|
||||||
- **Master** (stable) branch - 3proxy 0.9
|
- **Master** (stable) branch - 3proxy 1.0
|
||||||
- **Devel** branch - 3proxy 10 (don't use it)
|
- **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)
|
### Binaries (deb / rpm / Windows zip)
|
||||||
|
|
||||||
https://github.com/3proxy/3proxy/releases
|
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
|
### Docker images
|
||||||
|
|
||||||
https://hub.docker.com/r/3proxy/3proxy
|
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
|
## 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.
|
Full installation requires to mount /etc/3proxy/3proxy.cfg files.
|
||||||
|
|
||||||
@ -42,7 +81,7 @@ echo "log
|
|||||||
nserver 8.8.8.8
|
nserver 8.8.8.8
|
||||||
nscache 65536
|
nscache 65536
|
||||||
proxy -p3129" | docker config create 3proxy
|
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.
|
`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.
|
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`.
|
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.
|
`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
|
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.
|
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:
|
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
|
or
|
||||||
`docker start -ai 3proxy` to start existing container
|
`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`.
|
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
|
## 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)
|
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
|
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
|
||||||
|
```
|
||||||
|
|||||||
18
debian/changelog
vendored
18
debian/changelog
vendored
@ -1,3 +1,21 @@
|
|||||||
|
3proxy (0.9.9.2-1) buster; urgency=medium
|
||||||
|
|
||||||
|
*3proxy 0.9.9.2 initial build
|
||||||
|
|
||||||
|
-- z3APA3A <3apa3a@3proxy.org> Sat, 24 Oct 2026 12:03:57 +0000
|
||||||
|
|
||||||
|
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-1) buster; urgency=medium
|
||||||
|
|
||||||
*3proxy 0.9.9 initial build
|
*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
|
||||||
14
doc/changelog/0/9/9/2
Normal file
14
doc/changelog/0/9/9/2
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
! Fix: dnspr relayed to the client whatever came first to the socket it asked the name server from, from any address and under any id, so a forged answer could be passed on; the query now goes out under a random id, and only an answer from the name server asked, with that id and the same question, is relayed
|
||||||
|
! Fix: a client sending a part of a TLS record and then nothing kept a thread taking all of a CPU, and the read never timed out
|
||||||
|
! Fix: without -Ne, the reply to SOCKS CONNECT and BIND gave the address of the client's connection to the proxy instead of the socket towards the destination: a BIND client was told the proxy's own port and the peer could never reach it (since 0.9.6)
|
||||||
|
! Fix: a client which shut down its sending side (half-close) could get the answer cut short, megabytes short with large answers; likewise an upload after the server half-closed
|
||||||
|
! Fix: with chroot every local time was UTC and every syslog message was lost: the time zone is loaded and syslog connected before chroot; the chroot entry of 3proxy.cfg(5) lists what PAM, LDAP and ODBC still need inside the chroot
|
||||||
|
! Fix: the HTTP proxy closed the server connection of a kept-alive client and opened another one when only the request method changed (a POST after a GET to the same host)
|
||||||
|
! Fix: the last ssl_client_mode in the configuration applied to every service, and a reload changed it for the services still running
|
||||||
|
! Fix: memory leaks: on every refused configuration reload, on every failed TLS handshake, the server CA paths of every TLS service
|
||||||
|
! Fix: Unix sockets: on Linux a proxy listening on a Unix socket relayed only the first bytes of an answer (result 95); an abstract socket (unix:@NAME) was bound under a name padded with zeros, which clients did not reach; tcppm refused port 0 for a unix: target, as given in the manual's example; on a reload the socket file of a listening service was removed
|
||||||
|
! Fix: SIGPIPE could kill 3proxy when a client was gone while services were starting, and standalone services (proxy, socks, ...) at any time; sends use MSG_NOSIGNAL where the system has it
|
||||||
|
! Fix: TLS MitM failed for every connection with wolfSSL built with WOLFSSL_QT (wolfSSL 5.9.1 of Ubuntu 26.04): the source certificate's serial number could not be copied; a serial number made from the hash of the source certificate is used then
|
||||||
|
! Fix: Windows: closing a connection could leave its socket open (SO_LINGER on a non-blocking socket) or reset it while the peer still sent, so the end of an answer could be lost
|
||||||
|
! Fix: standalone port mappers (tcppm, udppm, tlspr) built with CMake were built as if they were not port mappers
|
||||||
|
- splice() is built by default on Linux again and is used only by services given -s
|
||||||
@ -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.
|
For name resolution and caching, use the commands nserver, nscache / nscache6, and nsrecord.
|
||||||
<pre>
|
<pre>
|
||||||
nserver 192.168.1.2
|
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)
|
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.
|
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.
|
If no nserver is configured, default system name resolution functions are used.
|
||||||
|
An IPv6 address has to be written in square brackets.
|
||||||
<pre>
|
<pre>
|
||||||
nscache 65535
|
nscache 65535
|
||||||
nscache6 65535</pre>
|
nscache6 65535</pre>
|
||||||
|
|||||||
@ -1536,11 +1536,13 @@ socks -p1080
|
|||||||
nscache и nsrecord.
|
nscache и nsrecord.
|
||||||
<pre>
|
<pre>
|
||||||
nserver 192.168.1.2
|
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 какие машины следует использвоать в качестве серверов
|
указывает 3proxy какие машины следует использвоать в качестве серверов
|
||||||
DNS. Сервер 192.168.1.3 будет использоваться по порту TCP/5353 (вместо дефолтного UDP/53) только при недостижимости
|
DNS. Сервер 192.168.1.3 будет использоваться по порту TCP/5353 (вместо дефолтного UDP/53) только при недостижимости
|
||||||
192.168.1.2. Можно указать до 5 серверов. Если nserver не указан, будут
|
192.168.1.2. Можно указать до 5 серверов. Если nserver не указан, будут
|
||||||
использованы системные функции разрешения имен.
|
использованы системные функции разрешения имен.
|
||||||
|
Адрес IPv6 необходимо записывать в квадратных скобках.
|
||||||
<pre>
|
<pre>
|
||||||
nscache 65535
|
nscache 65535
|
||||||
nscache6 65535</pre>
|
nscache6 65535</pre>
|
||||||
|
|||||||
@ -216,12 +216,11 @@ second. Useful to minimize polling <b><br>
|
|||||||
-s</b> <br>
|
-s</b> <br>
|
||||||
(for admin) secure, allow only secure operations, currently
|
(for admin) secure, allow only secure operations, currently
|
||||||
only traffic counters view without ability to reset. <br>
|
only traffic counters view without ability to reset. <br>
|
||||||
(for TCP services, Linux) enable splice(). splice() is not
|
(for TCP services, Linux) enable splice(). It is built on
|
||||||
built by default and is disabled even when built, because
|
Linux by default, but off unless -s is given: splice() is
|
||||||
current Linux does not implement SPLICE_F_MOVE, so no real
|
faster for large transfers and the read/write path for small
|
||||||
zero-copy takes place and the read/write path is faster for
|
requests. -s0 disables it explicitly; build without
|
||||||
most traffic. Rebuild with -DWITHSPLICE to make -s
|
-DWITHSPLICE to leave it out. <b><br>
|
||||||
available, -s0 disables it explicitly. <b><br>
|
|
||||||
-C</b> <br>
|
-C</b> <br>
|
||||||
(for TCP services) a connection closed by any of the sides
|
(for TCP services) a connection closed by any of the sides
|
||||||
terminates the session, buffered data is delivered before
|
terminates the session, buffered data is delivered before
|
||||||
@ -489,7 +488,11 @@ experimental.</p>
|
|||||||
Nameserver to use for name resolutions. If none specified
|
Nameserver to use for name resolutions. If none specified
|
||||||
system routines for name resolution is used. Optional port
|
system routines for name resolution is used. Optional port
|
||||||
number may be specified. If optional /tcp is added to IP
|
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>
|
<p style="margin-left:6%; margin-top: 1em"><b>authnserver</b>
|
||||||
@ -1133,7 +1136,15 @@ groupname. Unix only.</p>
|
|||||||
[<i><gid></i>] <br>
|
[<i><gid></i>] <br>
|
||||||
calls chroot(path) and sets gid/uid. Unix only. uid/gid
|
calls chroot(path) and sets gid/uid. Unix only. uid/gid
|
||||||
supported since 0.9, can be numeric or
|
supported since 0.9, can be numeric or
|
||||||
username/groupname</p>
|
username/groupname. The time zone and the syslog connection
|
||||||
|
are set up before the call.
|
||||||
|
Plugins which read their own configuration or load modules
|
||||||
|
while running need them inside the chroot: PAM
|
||||||
|
(<i>/etc/pam.d</i> and the modules it names, read for every
|
||||||
|
authentication), LDAP (<i>ldap.conf</i> and, for ldaps, the
|
||||||
|
CA certificates), ODBC (<i>odbc.ini</i>, <i>odbcinst.ini</i>
|
||||||
|
and the driver libraries, loaded again whenever the
|
||||||
|
connection is reopened).</p>
|
||||||
|
|
||||||
|
|
||||||
<p style="margin-left:6%; margin-top: 1em"><b>stacksize</b>
|
<p style="margin-left:6%; margin-top: 1em"><b>stacksize</b>
|
||||||
|
|||||||
@ -194,11 +194,10 @@ delay GRACE_DELAY milliseconds before polling if average polling size is below G
|
|||||||
(for admin) secure, allow only secure operations, currently only traffic counters
|
(for admin) secure, allow only secure operations, currently only traffic counters
|
||||||
view without ability to reset.
|
view without ability to reset.
|
||||||
.br
|
.br
|
||||||
(for TCP services, Linux) enable splice(). splice() is not built by default and
|
(for TCP services, Linux) enable splice(). It is built on Linux by default,
|
||||||
is disabled even when built, because current Linux does not implement
|
but off unless -s is given: splice() is faster for large transfers and the
|
||||||
SPLICE_F_MOVE, so no real zero-copy takes place and the read/write path is faster
|
read/write path for small requests. -s0 disables it explicitly; build without
|
||||||
for most traffic. Rebuild with -DWITHSPLICE to make -s available, -s0 disables it
|
-DWITHSPLICE to leave it out.
|
||||||
explicitly.
|
|
||||||
.br
|
.br
|
||||||
.B -C
|
.B -C
|
||||||
(for TCP services) a connection closed by any of the sides terminates the
|
(for TCP services) a connection closed by any of the sides terminates the
|
||||||
@ -514,6 +513,13 @@ system routines for name resolution is
|
|||||||
used. Optional port number may be specified.
|
used. Optional port number may be specified.
|
||||||
If optional /tcp is added to IP address, name resolution is
|
If optional /tcp is added to IP address, name resolution is
|
||||||
performed over TCP.
|
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
|
||||||
.BR authnserver
|
.BR authnserver
|
||||||
@ -1247,7 +1253,12 @@ for all threads.
|
|||||||
.BR chroot
|
.BR chroot
|
||||||
\fI<path>\fR [\fI<uid>\fR] [\fI<gid>\fR]
|
\fI<path>\fR [\fI<uid>\fR] [\fI<gid>\fR]
|
||||||
.br
|
.br
|
||||||
calls chroot(path) and sets gid/uid. Unix only. uid/gid supported since 0.9, can be numeric or username/groupname
|
calls chroot(path) and sets gid/uid. Unix only. uid/gid supported since 0.9, can be numeric or username/groupname.
|
||||||
|
The time zone and the syslog connection are set up before the call.
|
||||||
|
Plugins which read their own configuration or load modules while running need them inside the chroot:
|
||||||
|
PAM (\fI/etc/pam.d\fR and the modules it names, read for every authentication),
|
||||||
|
LDAP (\fIldap.conf\fR and, for ldaps, the CA certificates),
|
||||||
|
ODBC (\fIodbc.ini\fR, \fIodbcinst.ini\fR and the driver libraries, loaded again whenever the connection is reopened).
|
||||||
|
|
||||||
.br
|
.br
|
||||||
.BR stacksize
|
.BR stacksize
|
||||||
|
|||||||
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
|
Name: 3proxy
|
||||||
Version: 0.9.9
|
Version: 0.9.9.2
|
||||||
Release: 1%{?dist}
|
Release: 1%{?dist}
|
||||||
Summary: 3proxy tiny proxy server
|
Summary: 3proxy tiny proxy server
|
||||||
License: GPL/LGPL/Apache/BSD
|
License: GPL/LGPL/Apache/BSD
|
||||||
@ -9,6 +9,9 @@ Prefix: %{_prefix}
|
|||||||
Packager: z3APA3A
|
Packager: z3APA3A
|
||||||
Source: https://github.com/%{packager}/%{name}/archive/%{version}.tar.gz
|
Source: https://github.com/%{packager}/%{name}/archive/%{version}.tar.gz
|
||||||
|
|
||||||
|
%global debug_package %{nil}
|
||||||
|
%global __requires_exclude ^/(usr/)?bin/3proxy$
|
||||||
|
|
||||||
%description
|
%description
|
||||||
3proxy is lightweight yet powerful proxy server
|
3proxy is lightweight yet powerful proxy server
|
||||||
|
|
||||||
|
|||||||
@ -511,6 +511,11 @@ int WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef _WIN32
|
||||||
|
/* before readconfig() starts the services: a client gone while it is
|
||||||
|
written to is an error, not the end */
|
||||||
|
signal(SIGPIPE, SIG_IGN);
|
||||||
|
#endif
|
||||||
_3proxy_mutex_init(&config_mutex);
|
_3proxy_mutex_init(&config_mutex);
|
||||||
_3proxy_mutex_init(&bandlim_mutex);
|
_3proxy_mutex_init(&bandlim_mutex);
|
||||||
_3proxy_mutex_init(&connlim_mutex);
|
_3proxy_mutex_init(&connlim_mutex);
|
||||||
@ -561,7 +566,6 @@ int WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int
|
|||||||
signal(SIGCONT, mysigpause);
|
signal(SIGCONT, mysigpause);
|
||||||
signal(SIGTERM, mysigterm);
|
signal(SIGTERM, mysigterm);
|
||||||
signal(SIGUSR1, mysigusr1);
|
signal(SIGUSR1, mysigusr1);
|
||||||
signal(SIGPIPE, SIG_IGN);
|
|
||||||
cyclestep();
|
cyclestep();
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
80
src/common.c
80
src/common.c
@ -182,7 +182,7 @@ int timeouts[12] = {
|
|||||||
EINVAL below it and the thread silently gets the 8M system default stack.
|
EINVAL below it and the thread silently gets the 8M system default stack.
|
||||||
*/
|
*/
|
||||||
size_t threadstacksize(int extra){
|
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;
|
if(size < (long)PTHREAD_STACK_MIN) size = (long)PTHREAD_STACK_MIN;
|
||||||
return (size_t)size;
|
return (size_t)size;
|
||||||
@ -414,7 +414,6 @@ int
|
|||||||
return shutdown(s, how);
|
return shutdown(s, how);
|
||||||
}
|
}
|
||||||
int WINAPI def_closesocket(void* state, SOCKET s){
|
int WINAPI def_closesocket(void* state, SOCKET s){
|
||||||
usleep(SLEEPTIME);
|
|
||||||
return closesocket(s);
|
return closesocket(s);
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
@ -454,11 +453,18 @@ int
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* a peer gone is an error of the send, not SIGPIPE, where the system can
|
||||||
|
say so for a call: SIGPIPE is ignored too, for TLS and splice() */
|
||||||
|
#ifdef MSG_NOSIGNAL
|
||||||
|
#define SENDFLAGS MSG_NOSIGNAL
|
||||||
|
#else
|
||||||
|
#define SENDFLAGS 0
|
||||||
|
#endif
|
||||||
ssize_t def_send(void* state, SOCKET s, const void *msg, size_t len, int flags){
|
ssize_t def_send(void* state, SOCKET s, const void *msg, size_t len, int flags){
|
||||||
return send(s, msg, len, flags);
|
return send(s, msg, len, flags | SENDFLAGS);
|
||||||
}
|
}
|
||||||
ssize_t def_sendto(void* state, SOCKET s, const void *msg, size_t len, int flags, const struct sockaddr *to, socklen_t tolen){
|
ssize_t def_sendto(void* state, SOCKET s, const void *msg, size_t len, int flags, const struct sockaddr *to, socklen_t tolen){
|
||||||
return sendto(s, msg, len, flags, to, tolen);
|
return sendto(s, msg, len, flags | SENDFLAGS, to, tolen);
|
||||||
}
|
}
|
||||||
ssize_t def_recv(void* state, SOCKET s, void *buf, size_t len, int flags){
|
ssize_t def_recv(void* state, SOCKET s, void *buf, size_t len, int flags){
|
||||||
return recv(s, buf, len, flags);
|
return recv(s, buf, len, flags);
|
||||||
@ -677,6 +683,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){
|
int doconnect(struct clientparam * param){
|
||||||
SASIZETYPE size;
|
SASIZETYPE size;
|
||||||
|
|
||||||
@ -693,7 +742,9 @@ int doconnect(struct clientparam * param){
|
|||||||
if(param->srv->so._getpeername(param->sostate, param->remsock, (struct sockaddr *)¶m->sinsr, &size)==-1) {return (14);}
|
if(param->srv->so._getpeername(param->sostate, param->remsock, (struct sockaddr *)¶m->sinsr, &size)==-1) {return (14);}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
#ifndef _WIN32
|
||||||
struct linger lg = {1,conf.timeouts[LINGER_TO]};
|
struct linger lg = {1,conf.timeouts[LINGER_TO]};
|
||||||
|
#endif
|
||||||
|
|
||||||
if(SAISNULL(¶m->sinsr)){
|
if(SAISNULL(¶m->sinsr)){
|
||||||
if(SAISNULL(¶m->req)) {
|
if(SAISNULL(¶m->req)) {
|
||||||
@ -723,26 +774,11 @@ int doconnect(struct clientparam * param){
|
|||||||
*SAPORT(¶m->sinsl) = 0;
|
*SAPORT(¶m->sinsl) = 0;
|
||||||
setopts(param->remsock, param->srv->srvsockopts);
|
setopts(param->remsock, param->srv->srvsockopts);
|
||||||
|
|
||||||
|
#ifndef _WIN32
|
||||||
|
/* not on Windows, see the accepting side in proxymain.c */
|
||||||
param->srv->so._setsockopt(param->sostate, param->remsock, SOL_SOCKET, SO_LINGER, (char *)&lg, sizeof(lg));
|
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
|
#endif
|
||||||
|
if(extbindtodevice(param, param->remsock)) return 12;
|
||||||
#ifdef WITH_UN
|
#ifdef WITH_UN
|
||||||
if(*SAFAMILY(¶m->sinsl) != AF_UNIX)
|
if(*SAFAMILY(¶m->sinsl) != AF_UNIX)
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
37
src/conf.c
37
src/conf.c
@ -158,7 +158,12 @@ int start_proxy_thread(struct child * chp){
|
|||||||
pthread_attr_init(&pa);
|
pthread_attr_init(&pa);
|
||||||
pthread_attr_setstacksize(&pa,threadstacksize(conf.stacksize));
|
pthread_attr_setstacksize(&pa,threadstacksize(conf.stacksize));
|
||||||
pthread_attr_setdetachstate(&pa,PTHREAD_CREATE_DETACHED);
|
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);
|
pthread_attr_destroy(&pa);
|
||||||
#endif
|
#endif
|
||||||
_3proxy_sem_lock(conf.threadinit);
|
_3proxy_sem_lock(conf.threadinit);
|
||||||
@ -331,7 +336,8 @@ static int h_log(int argc, unsigned char ** argv){
|
|||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
conf.logfunc = logsyslog;
|
conf.logfunc = logsyslog;
|
||||||
if(notchanged) return 0;
|
if(notchanged) return 0;
|
||||||
openlog((char *)conf.logtarget+1, LOG_PID, LOG_DAEMON);
|
/* connected now: after a chroot there is no /dev/log to find */
|
||||||
|
openlog((char *)conf.logtarget+1, LOG_PID | LOG_NDELAY, LOG_DAEMON);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
#ifdef WITH_ODBC
|
#ifdef WITH_ODBC
|
||||||
@ -1591,6 +1597,14 @@ static int h_setgid(int argc, unsigned char **argv){
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* What the C library reads on first use from files a chroot hides, read
|
||||||
|
while they can still be found: the time zone, without which every time
|
||||||
|
is UTC. Names looked up through the system cannot be helped this way, the
|
||||||
|
hosts file and resolv.conf are read again for lookups to come. */
|
||||||
|
static void prechroot(void){
|
||||||
|
tzset();
|
||||||
|
}
|
||||||
|
|
||||||
static int h_chroot(int argc, unsigned char **argv){
|
static int h_chroot(int argc, unsigned char **argv){
|
||||||
uid_t uid = 0;
|
uid_t uid = 0;
|
||||||
gid_t gid = 0;
|
gid_t gid = 0;
|
||||||
@ -1610,6 +1624,8 @@ static int h_chroot(int argc, unsigned char **argv){
|
|||||||
}
|
}
|
||||||
if(!chrootp){
|
if(!chrootp){
|
||||||
char *p;
|
char *p;
|
||||||
|
|
||||||
|
prechroot();
|
||||||
if(chroot((char *)argv[1])) {
|
if(chroot((char *)argv[1])) {
|
||||||
fprintf(stderr, "Unable to chroot %s", argv[1]);
|
fprintf(stderr, "Unable to chroot %s", argv[1]);
|
||||||
return(1);
|
return(1);
|
||||||
@ -1920,6 +1936,7 @@ int readconfig(FILE * fp){
|
|||||||
|
|
||||||
if( !(buf = malloc(bufsize)) || ! (argv = malloc((NPARAMS + 1) * sizeof(unsigned char *))) ) {
|
if( !(buf = malloc(bufsize)) || ! (argv = malloc((NPARAMS + 1) * sizeof(unsigned char *))) ) {
|
||||||
fprintf(stderr, "No memory for configuration");
|
fprintf(stderr, "No memory for configuration");
|
||||||
|
if(buf) free(buf);
|
||||||
return(10);
|
return(10);
|
||||||
}
|
}
|
||||||
for (linenum = 1; fgets((char *)buf, STRINGBUF, fp); linenum++){
|
for (linenum = 1; fgets((char *)buf, STRINGBUF, fp); linenum++){
|
||||||
@ -1929,7 +1946,8 @@ int readconfig(FILE * fp){
|
|||||||
argc = parsestr (buf, argv, NPARAMS-1, &buf, &inbuf, &bufsize);
|
argc = parsestr (buf, argv, NPARAMS-1, &buf, &inbuf, &bufsize);
|
||||||
if(argc < 1) {
|
if(argc < 1) {
|
||||||
fprintf(stderr, "Parse error line %d\n", linenum);
|
fprintf(stderr, "Parse error line %d\n", linenum);
|
||||||
return(11);
|
res = 11;
|
||||||
|
goto DONE;
|
||||||
}
|
}
|
||||||
argv[argc] = NULL;
|
argv[argc] = NULL;
|
||||||
if(!strcmp((char *)argv[0], "end") && argc == 1) {
|
if(!strcmp((char *)argv[0], "end") && argc == 1) {
|
||||||
@ -1951,23 +1969,28 @@ int readconfig(FILE * fp){
|
|||||||
if(!strcmp((char *)argv[0], (char *)cm->command)){
|
if(!strcmp((char *)argv[0], (char *)cm->command)){
|
||||||
if(argc < cm->minargs || (cm->maxargs && argc > cm->maxargs)){
|
if(argc < cm->minargs || (cm->maxargs && argc > cm->maxargs)){
|
||||||
fprintf(stderr, "Command: '%s' wrong number of arguments , line %d\n", argv[0], linenum);
|
fprintf(stderr, "Command: '%s' wrong number of arguments , line %d\n", argv[0], linenum);
|
||||||
return(linenum);
|
res = linenum;
|
||||||
|
goto DONE;
|
||||||
}
|
}
|
||||||
res = (*cm->handler)(argc, argv);
|
res = (*cm->handler)(argc, argv);
|
||||||
if(res > 0){
|
if(res > 0){
|
||||||
fprintf(stderr, "Command: '%s' failed with code %d, line %d\n", argv[0], res, linenum);
|
fprintf(stderr, "Command: '%s' failed with code %d, line %d\n", argv[0], res, linenum);
|
||||||
return(linenum);
|
res = linenum;
|
||||||
|
goto DONE;
|
||||||
}
|
}
|
||||||
if(!res) break;
|
if(!res) break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(res != 1)continue;
|
if(res != 1)continue;
|
||||||
fprintf(stderr, "Unknown command: '%s' line %d\n", argv[0], linenum);
|
fprintf(stderr, "Unknown command: '%s' line %d\n", argv[0], linenum);
|
||||||
return(linenum);
|
res = linenum;
|
||||||
|
goto DONE;
|
||||||
}
|
}
|
||||||
|
res = 0;
|
||||||
|
DONE:
|
||||||
free(buf);
|
free(buf);
|
||||||
free(argv);
|
free(argv);
|
||||||
return 0;
|
return res;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
37
src/dnspr.c
37
src/dnspr.c
@ -15,6 +15,12 @@
|
|||||||
|
|
||||||
#define BUFSIZE 16384
|
#define BUFSIZE 16384
|
||||||
|
|
||||||
|
/* An answer to the query asked: our id, a response, and the question
|
||||||
|
byte for byte. */
|
||||||
|
static int dnsanswer(const unsigned char *buf, int len, const unsigned char *q, int qend){
|
||||||
|
return len >= qend && buf[0] == q[0] && buf[1] == q[1] && (buf[2] & 0x80) &&
|
||||||
|
buf[4] == q[4] && buf[5] == q[5] && !memcmp(buf + 12, q + 12, qend - 12);
|
||||||
|
}
|
||||||
|
|
||||||
void * dnsprchild(struct clientparam* param) {
|
void * dnsprchild(struct clientparam* param) {
|
||||||
uint32_t ip = 0;
|
uint32_t ip = 0;
|
||||||
@ -144,6 +150,20 @@ void * dnsprchild(struct clientparam* param) {
|
|||||||
else ip = 0;
|
else ip = 0;
|
||||||
}
|
}
|
||||||
if(!ip && numservers){
|
if(!ip && numservers){
|
||||||
|
/* the question, to check the answer against; the name server is
|
||||||
|
asked under an id of our own, the client's put back in its answer */
|
||||||
|
unsigned char question[1024], cid[2];
|
||||||
|
int qend = (len < i)? len : i;
|
||||||
|
unsigned short id = (unsigned short)myrand();
|
||||||
|
PROXYSOCKADDRTYPE from;
|
||||||
|
time_t deadline;
|
||||||
|
int to;
|
||||||
|
|
||||||
|
cid[0] = buf[0];
|
||||||
|
cid[1] = buf[1];
|
||||||
|
buf[0] = (unsigned char)(id >> 8);
|
||||||
|
buf[1] = (unsigned char)(id & 0xff);
|
||||||
|
memcpy(question, buf, qend);
|
||||||
if((param->remsock=param->srv->so._socket(param->sostate, SASOCK(&nservers[0].addr), nservers[0].usetcp? SOCK_STREAM:SOCK_DGRAM, nservers[0].usetcp?IPPROTO_TCP:IPPROTO_UDP)) == INVALID_SOCKET) {
|
if((param->remsock=param->srv->so._socket(param->sostate, SASOCK(&nservers[0].addr), nservers[0].usetcp? SOCK_STREAM:SOCK_DGRAM, nservers[0].usetcp?IPPROTO_TCP:IPPROTO_UDP)) == INVALID_SOCKET) {
|
||||||
RETURN(818);
|
RETURN(818);
|
||||||
}
|
}
|
||||||
@ -172,10 +192,22 @@ void * dnsprchild(struct clientparam* param) {
|
|||||||
}
|
}
|
||||||
param->statscli64 += i;
|
param->statscli64 += i;
|
||||||
param->nwrites++;
|
param->nwrites++;
|
||||||
len = sockrecvfrom(param, param->remsock, (struct sockaddr *)¶m->sinsr, buf, BUFSIZE, conf.timeouts[DNS_TO]*1000);
|
/* over UDP only an answer from the name server asked is taken, any
|
||||||
|
other read past while the time for it lasts */
|
||||||
|
deadline = time(NULL) + conf.timeouts[DNS_TO];
|
||||||
|
for(;;){
|
||||||
|
to = (int)(deadline - time(NULL));
|
||||||
|
if(to <= 0) RETURN(821);
|
||||||
|
len = sockrecvfrom(param, param->remsock, (struct sockaddr *)&from, buf, BUFSIZE, to*1000);
|
||||||
if(len <= 13) {
|
if(len <= 13) {
|
||||||
RETURN(821);
|
RETURN(821);
|
||||||
}
|
}
|
||||||
|
if(nservers[0].usetcp) break;
|
||||||
|
if(*SAFAMILY(&from) == *SAFAMILY(¶m->sinsr) &&
|
||||||
|
!memcmp(SAADDR(&from), SAADDR(¶m->sinsr), SAADDRLEN(¶m->sinsr)) &&
|
||||||
|
*SAPORT(&from) == *SAPORT(¶m->sinsr) &&
|
||||||
|
dnsanswer(buf, len, question, qend)) break;
|
||||||
|
}
|
||||||
param->statssrv64 += len;
|
param->statssrv64 += len;
|
||||||
param->nreads++;
|
param->nreads++;
|
||||||
if(nservers[0].usetcp) {
|
if(nservers[0].usetcp) {
|
||||||
@ -186,7 +218,10 @@ void * dnsprchild(struct clientparam* param) {
|
|||||||
len -= 2;
|
len -= 2;
|
||||||
if(len < us) len += sockgetlinebuf(param, SERVER, buf+len, us - len, 0, conf.timeouts[SINGLEBYTE_L]);
|
if(len < us) len += sockgetlinebuf(param, SERVER, buf+len, us - len, 0, conf.timeouts[SINGLEBYTE_L]);
|
||||||
if(len != us) RETURN(832);
|
if(len != us) RETURN(832);
|
||||||
|
if(!dnsanswer(buf, len, question, qend)) RETURN(834);
|
||||||
}
|
}
|
||||||
|
buf[0] = cid[0];
|
||||||
|
buf[1] = cid[1];
|
||||||
if(buf[6] || buf[7]){
|
if(buf[6] || buf[7]){
|
||||||
if(socksendto(param, param->clisock, (struct sockaddr *)¶m->sincr, buf, len, conf.timeouts[SINGLEBYTE_L]*1000) != len){
|
if(socksendto(param, param->clisock, (struct sockaddr *)¶m->sincr, buf, len, conf.timeouts[SINGLEBYTE_L]*1000) != len){
|
||||||
RETURN(822);
|
RETURN(822);
|
||||||
|
|||||||
17
src/ftppr.c
17
src/ftppr.c
@ -21,14 +21,18 @@ void * ftpprchild(struct clientparam* param) {
|
|||||||
SOCKET sc = INVALID_SOCKET, ss = INVALID_SOCKET, clidatasock = INVALID_SOCKET;
|
SOCKET sc = INVALID_SOCKET, ss = INVALID_SOCKET, clidatasock = INVALID_SOCKET;
|
||||||
SASIZETYPE sasize;
|
SASIZETYPE sasize;
|
||||||
char * req = NULL;
|
char * req = NULL;
|
||||||
|
#ifndef _WIN32
|
||||||
struct linger lg;
|
struct linger lg;
|
||||||
|
#endif
|
||||||
struct pollfd fds;
|
struct pollfd fds;
|
||||||
|
|
||||||
if(!(buf = malloc(BUFSIZE))) RETURN(876);
|
if(!(buf = malloc(BUFSIZE))) RETURN(876);
|
||||||
param->ctrlsock = param->clisock;
|
param->ctrlsock = param->clisock;
|
||||||
param->operation = CONNECT;
|
param->operation = CONNECT;
|
||||||
|
#ifndef _WIN32
|
||||||
lg.l_onoff = 1;
|
lg.l_onoff = 1;
|
||||||
lg.l_linger = conf.timeouts[STRING_L];;
|
lg.l_linger = conf.timeouts[STRING_L];
|
||||||
|
#endif
|
||||||
if(socksend(param, param->ctrlsock, (unsigned char *)"220 Ready\r\n", 11, conf.timeouts[STRING_S])!=11) {RETURN (801);}
|
if(socksend(param, param->ctrlsock, (unsigned char *)"220 Ready\r\n", 11, conf.timeouts[STRING_S])!=11) {RETURN (801);}
|
||||||
for(;;){
|
for(;;){
|
||||||
i = sockgetlinebuf(param, CLIENT, buf, BUFSIZE - 10, '\n', conf.timeouts[CONNECTION_S]);
|
i = sockgetlinebuf(param, CLIENT, buf, BUFSIZE - 10, '\n', conf.timeouts[CONNECTION_S]);
|
||||||
@ -64,6 +68,13 @@ void * ftpprchild(struct clientparam* param) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
else if (!strncasecmp((char *)buf, "PASS ", 5)){
|
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);
|
param->extpassword = (unsigned char *)strdup((char *)buf+5);
|
||||||
inbuf = BUFSIZE;
|
inbuf = BUFSIZE;
|
||||||
res = ftplogin(param, (char *)buf, &inbuf);
|
res = ftplogin(param, (char *)buf, &inbuf);
|
||||||
@ -120,6 +131,7 @@ void * ftpprchild(struct clientparam* param) {
|
|||||||
clidatasock = INVALID_SOCKET;
|
clidatasock = INVALID_SOCKET;
|
||||||
}
|
}
|
||||||
if ((clidatasock=socket(SASOCK(¶m->sincl), SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET) {RETURN(821);}
|
if ((clidatasock=socket(SASOCK(¶m->sincl), SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET) {RETURN(821);}
|
||||||
|
if(intbindtodevice(param, clidatasock)){RETURN(822);}
|
||||||
*SAPORT(¶m->sincl) = 0;
|
*SAPORT(¶m->sincl) = 0;
|
||||||
if(param->srv->so._bind(param->sostate, clidatasock, (struct sockaddr *)¶m->sincl, SASIZE(¶m->sincl))){RETURN(822);}
|
if(param->srv->so._bind(param->sostate, clidatasock, (struct sockaddr *)¶m->sincl, SASIZE(¶m->sincl))){RETURN(822);}
|
||||||
if (pasv) {
|
if (pasv) {
|
||||||
@ -252,8 +264,11 @@ void * ftpprchild(struct clientparam* param) {
|
|||||||
}
|
}
|
||||||
sc = param->remsock;
|
sc = param->remsock;
|
||||||
param->remsock = ss;
|
param->remsock = ss;
|
||||||
|
#ifndef _WIN32
|
||||||
|
/* not on Windows, see the accepting side in proxymain.c */
|
||||||
param->srv->so._setsockopt(param->sostate, param->remsock, SOL_SOCKET, SO_LINGER, (char *)&lg, sizeof(lg));
|
param->srv->so._setsockopt(param->sostate, param->remsock, SOL_SOCKET, SO_LINGER, (char *)&lg, sizeof(lg));
|
||||||
param->srv->so._setsockopt(param->sostate, clidatasock, SOL_SOCKET, SO_LINGER, (char *)&lg, sizeof(lg));
|
param->srv->so._setsockopt(param->sostate, clidatasock, SOL_SOCKET, SO_LINGER, (char *)&lg, sizeof(lg));
|
||||||
|
#endif
|
||||||
param->clisock = clidatasock;
|
param->clisock = clidatasock;
|
||||||
res = mapsocket(param, conf.timeouts[CONNECTION_S]);
|
res = mapsocket(param, conf.timeouts[CONNECTION_S]);
|
||||||
if(param->remsock != INVALID_SOCKET) {
|
if(param->remsock != INVALID_SOCKET) {
|
||||||
|
|||||||
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;
|
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){
|
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;
|
PCRE2_SIZE *ovector;
|
||||||
int count = 0;
|
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)
|
#define pcrefd ((struct pcre_filter_data *)fc)
|
||||||
|
|
||||||
for(acl = pcrefd->acl; acl; acl=acl->next){
|
for(acl = pcrefd->acl; acl; acl=acl->next){
|
||||||
if(pl->ACLMatches(pcrefd->acl, param)){
|
if(pl->ACLMatches(acl, param)){
|
||||||
match = 1;
|
match = 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -324,12 +327,17 @@ static FILTER_ACTION pcre_filter_buffer(void *fc, struct clientparam *param, uns
|
|||||||
else if(*replace == '$' && isnumber(*(replace+1))){
|
else if(*replace == '$' && isnumber(*(replace+1))){
|
||||||
replace ++;
|
replace ++;
|
||||||
num = atoi(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(num > (count - 1)) continue;
|
||||||
if(ovector[(num<<1)] == PCRE2_UNSET) 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;
|
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)]);
|
memcpy(target, *buf_p + ovector[(num<<1)], ovector[(num<<1) + 1] - ovector[(num<<1)]);
|
||||||
target += (ovector[(num<<1) + 1] - ovector[(num<<1)]);
|
target += (ovector[(num<<1) + 1] - ovector[(num<<1)]);
|
||||||
while(isnumber(*replace)) replace++;
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
*target++ = *replace++;
|
*target++ = *replace++;
|
||||||
@ -338,7 +346,13 @@ static FILTER_ACTION pcre_filter_buffer(void *fc, struct clientparam *param, uns
|
|||||||
repsz = (int)(target - tmpbuf);
|
repsz = (int)(target - tmpbuf);
|
||||||
memcpy(target, *buf_p + ovector[1], *length_p - ovector[1]);
|
memcpy(target, *buf_p + ovector[1], *length_p - ovector[1]);
|
||||||
if((ovector[0] + replen + 1) > *bufsize_p){
|
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){
|
if(!newbuf){
|
||||||
pl->freefunc(tmpbuf);
|
pl->freefunc(tmpbuf);
|
||||||
return CONTINUE;
|
return CONTINUE;
|
||||||
@ -346,7 +360,7 @@ static FILTER_ACTION pcre_filter_buffer(void *fc, struct clientparam *param, uns
|
|||||||
memcpy(newbuf, *buf_p, ovector[0]);
|
memcpy(newbuf, *buf_p, ovector[0]);
|
||||||
pl->freefunc(*buf_p);
|
pl->freefunc(*buf_p);
|
||||||
*buf_p = (unsigned char *)newbuf;
|
*buf_p = (unsigned char *)newbuf;
|
||||||
*bufsize_p = ovector[0] + replen + 1;
|
*bufsize_p = newsize;
|
||||||
}
|
}
|
||||||
memcpy(*buf_p + ovector[0], tmpbuf, replen);
|
memcpy(*buf_p + ovector[0], tmpbuf, replen);
|
||||||
pl->freefunc(tmpbuf);
|
pl->freefunc(tmpbuf);
|
||||||
|
|||||||
46
src/proxy.c
46
src/proxy.c
@ -132,6 +132,12 @@ char * proxy_stringtable[] = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
#define LINESIZE 32768
|
#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 BUFSIZE (LINESIZE*2)
|
||||||
#define FTPBUFSIZE 1536
|
#define FTPBUFSIZE 1536
|
||||||
|
|
||||||
@ -151,6 +157,34 @@ 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]);
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Whether a request line names the host the previous one did, whatever its
|
||||||
|
method: the connection to the server is kept for the same host only, and
|
||||||
|
a POST after a GET to it is no reason to open another one. */
|
||||||
|
static int samehost(const unsigned char *line, int len, const unsigned char *host, int hostlen){
|
||||||
|
const unsigned char *p = (const unsigned char *)memchr(line, ' ', len);
|
||||||
|
|
||||||
|
if(!p || hostlen <= 0) return 0;
|
||||||
|
p++;
|
||||||
|
if(!strncasecmp((const char *)p, "http://", 7)) p += 7;
|
||||||
|
if((int)(p - line) + hostlen >= len || strncasecmp((const char *)p, (const char *)host, hostlen))
|
||||||
|
return 0;
|
||||||
|
return p[hostlen] == '/' || p[hostlen] == ' ';
|
||||||
|
}
|
||||||
|
|
||||||
static void freeptr(void *p){
|
static void freeptr(void *p){
|
||||||
void **pp = (void **)p;
|
void **pp = (void **)p;
|
||||||
if(*pp) { free(*pp); *pp = NULL; }
|
if(*pp) { free(*pp); *pp = NULL; }
|
||||||
@ -245,7 +279,7 @@ void * proxychild(struct clientparam* param) {
|
|||||||
int clhdrofs_req = -1;
|
int clhdrofs_req = -1;
|
||||||
int isconnect = 0;
|
int isconnect = 0;
|
||||||
int redirect = 0;
|
int redirect = 0;
|
||||||
int prefix = 0, ckeepalive=0;
|
int prefix = 0, hostofs = 0, ckeepalive=0;
|
||||||
int ftp = 0;
|
int ftp = 0;
|
||||||
int ssoff = 0;
|
int ssoff = 0;
|
||||||
#ifndef ANONYMOUS
|
#ifndef ANONYMOUS
|
||||||
@ -313,7 +347,7 @@ for(;;){
|
|||||||
buf[i] = 0;
|
buf[i] = 0;
|
||||||
|
|
||||||
if(req) {
|
if(req) {
|
||||||
if(!param->transparent && !param->srv->transparent && (i<=prefix || strncasecmp((char *)buf, (char *)req, prefix))){
|
if(!param->transparent && !param->srv->transparent && !samehost(buf, i, req + hostofs, prefix - hostofs)){
|
||||||
ckeepalive = 0;
|
ckeepalive = 0;
|
||||||
if(param->remsock != INVALID_SOCKET){
|
if(param->remsock != INVALID_SOCKET){
|
||||||
param->srv->so._shutdown(param->sostate, param->remsock, SHUT_RDWR);
|
param->srv->so._shutdown(param->sostate, param->remsock, SHUT_RDWR);
|
||||||
@ -368,6 +402,7 @@ for(;;){
|
|||||||
*se = 0;
|
*se = 0;
|
||||||
}
|
}
|
||||||
prefix = (int)(se - buf);
|
prefix = (int)(se - buf);
|
||||||
|
hostofs = (int)(sb - buf);
|
||||||
su = (unsigned char*)strrchr((char *)sb, '@');
|
su = (unsigned char*)strrchr((char *)sb, '@');
|
||||||
if(su) {
|
if(su) {
|
||||||
su = (unsigned char *)strdup((char *)sb);
|
su = (unsigned char *)strdup((char *)sb);
|
||||||
@ -587,6 +622,10 @@ for(;;){
|
|||||||
RETURN(0);
|
RETURN(0);
|
||||||
}
|
}
|
||||||
if(action != PASS) RETURN(517);
|
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;
|
param->nolongdatfilter = 0;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@ -620,6 +659,7 @@ for(;;){
|
|||||||
contentlength64 = param->cliinbuf;
|
contentlength64 = param->cliinbuf;
|
||||||
param->nolongdatfilter = 1;
|
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);
|
sprintf((char*)buf+strlen((char *)buf), "Content-Length: %"PRIu64"\r\n", contentlength64);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1097,6 +1137,7 @@ for(;;){
|
|||||||
RETURN(0);
|
RETURN(0);
|
||||||
}
|
}
|
||||||
if(action != PASS) RETURN(517);
|
if(action != PASS) RETURN(517);
|
||||||
|
if(growbuf(&buf, &bufsize, inbuf + HDRRESERVE)) RETURN(21);
|
||||||
|
|
||||||
param->nolongdatfilter = 0;
|
param->nolongdatfilter = 0;
|
||||||
|
|
||||||
@ -1120,6 +1161,7 @@ for(;;){
|
|||||||
}
|
}
|
||||||
if(action != PASS) RETURN(517);
|
if(action != PASS) RETURN(517);
|
||||||
contentlength64 = param->srvinbuf;
|
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);
|
sprintf((char*)buf+strlen((char *)buf), "Content-Length: %"PRIu64"\r\n", contentlength64);
|
||||||
hascontent = 1;
|
hascontent = 1;
|
||||||
}
|
}
|
||||||
|
|||||||
20
src/proxy.h
20
src/proxy.h
@ -135,6 +135,23 @@ void daemonize(void);
|
|||||||
#endif
|
#endif
|
||||||
#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
|
#ifndef _WIN32
|
||||||
size_t threadstacksize(int extra);
|
size_t threadstacksize(int extra);
|
||||||
#endif
|
#endif
|
||||||
@ -352,6 +369,9 @@ unsigned char * dologname (unsigned char *buf, unsigned char *name, const unsign
|
|||||||
int readconfig(FILE * fp);
|
int readconfig(FILE * fp);
|
||||||
void initcommands(void);
|
void initcommands(void);
|
||||||
int connectwithpoll(struct clientparam *param, SOCKET sock, struct sockaddr *sa, SASIZETYPE size, int to);
|
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);
|
uint32_t myrand(void);
|
||||||
|
|||||||
162
src/proxymain.c
162
src/proxymain.c
@ -7,6 +7,31 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "proxy.h"
|
#include "proxy.h"
|
||||||
|
|
||||||
|
#ifdef WITH_UN
|
||||||
|
/* A service bound to a Unix socket path notes its file, as a service of a
|
||||||
|
newer configuration may bind the same path before this one closes: the
|
||||||
|
file is then the other's, which closing must not remove. */
|
||||||
|
static void unbound(struct srvparam *srv){
|
||||||
|
struct stat st;
|
||||||
|
|
||||||
|
if(*SAFAMILY(&srv->intsa) == AF_UNIX && *SAADDR(&srv->intsa) &&
|
||||||
|
!stat((char *)SAADDR(&srv->intsa), &st)){
|
||||||
|
srv->undev = (uint64_t)st.st_dev;
|
||||||
|
srv->unino = (uint64_t)st.st_ino;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ununlink(struct srvparam *srv){
|
||||||
|
struct stat st;
|
||||||
|
|
||||||
|
if(*SAFAMILY(&srv->intsa) == AF_UNIX && *SAADDR(&srv->intsa) &&
|
||||||
|
!stat((char *)SAADDR(&srv->intsa), &st) &&
|
||||||
|
(uint64_t)st.st_dev == srv->undev && (uint64_t)st.st_ino == srv->unino)
|
||||||
|
unlink((char *)SAADDR(&srv->intsa));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef __linux__
|
#ifdef __linux__
|
||||||
#include <sched.h>
|
#include <sched.h>
|
||||||
#endif
|
#endif
|
||||||
@ -84,7 +109,7 @@ void * threadfunc (void *p) {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
if(socksendto(param, param->remsock, (struct sockaddr*)¶m->sinsr, (unsigned char *)"C", 1, CONNBACK_TO*1000) != 1){
|
if(socksend(param, param->remsock, (unsigned char *)"C", 1, CONNBACK_TO) != 1){
|
||||||
dolog(param, (unsigned char *)"Connect back sending command failed");
|
dolog(param, (unsigned char *)"Connect back sending command failed");
|
||||||
param->srv->so._closesocket(param->sostate, param->remsock);
|
param->srv->so._closesocket(param->sostate, param->remsock);
|
||||||
param->remsock = INVALID_SOCKET;
|
param->remsock = INVALID_SOCKET;
|
||||||
@ -306,7 +331,9 @@ int MODULEMAINFUNC (int argc, char** argv){
|
|||||||
unsigned char *cbc_string = NULL, *cbl_string = NULL;
|
unsigned char *cbc_string = NULL, *cbl_string = NULL;
|
||||||
PROXYSOCKADDRTYPE cbsa;
|
PROXYSOCKADDRTYPE cbsa;
|
||||||
FILE *fp = NULL;
|
FILE *fp = NULL;
|
||||||
|
#ifndef _WIN32
|
||||||
struct linger lg;
|
struct linger lg;
|
||||||
|
#endif
|
||||||
int nlog = 5000;
|
int nlog = 5000;
|
||||||
#ifdef __linux__
|
#ifdef __linux__
|
||||||
int saved_nsfd = -1;
|
int saved_nsfd = -1;
|
||||||
@ -391,6 +418,9 @@ int MODULEMAINFUNC (int argc, char** argv){
|
|||||||
WSADATA wd;
|
WSADATA wd;
|
||||||
WSAStartup(MAKEWORD( 1, 1 ), &wd);
|
WSAStartup(MAKEWORD( 1, 1 ), &wd);
|
||||||
|
|
||||||
|
#else
|
||||||
|
/* a client gone while it is written to is an error, not the end */
|
||||||
|
signal(SIGPIPE, SIG_IGN);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@ -685,7 +715,12 @@ int MODULEMAINFUNC (int argc, char** argv){
|
|||||||
else {
|
else {
|
||||||
#endif
|
#endif
|
||||||
#ifndef NOPORTMAP
|
#ifndef NOPORTMAP
|
||||||
if (error || argc != i+3 || *argv[i]=='-'|| (*SAPORT(&srv.intsa) = htons((uint16_t)atoi(argv[i])))==0 || (srv.targetport = htons((uint16_t)atoi(argv[i+2])))==0) {
|
/* the port of a Unix socket target is ignored, 0 as the manual has it */
|
||||||
|
if (error || argc != i+3 || *argv[i]=='-'|| (*SAPORT(&srv.intsa) = htons((uint16_t)atoi(argv[i])))==0 || ((srv.targetport = htons((uint16_t)atoi(argv[i+2])))==0
|
||||||
|
#ifdef WITH_UN
|
||||||
|
&& strncmp(argv[i+1], "unix:", 5)
|
||||||
|
#endif
|
||||||
|
)) {
|
||||||
#ifndef STDMAIN
|
#ifndef STDMAIN
|
||||||
haveerror = 1;
|
haveerror = 1;
|
||||||
#endif
|
#endif
|
||||||
@ -830,35 +865,25 @@ int MODULEMAINFUNC (int argc, char** argv){
|
|||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
opt = 1;
|
opt = 1;
|
||||||
if(srv.so._setsockopt(srv.so.state, sock, SOL_SOCKET, SO_REUSEADDR, (char *)&opt, sizeof(int)))perror("setsockopt()");
|
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
|
#endif
|
||||||
#ifdef SO_REUSEPORT
|
#ifdef SO_REUSEPORT
|
||||||
opt = 1;
|
opt = 1;
|
||||||
srv.so._setsockopt(srv.so.state, sock, SOL_SOCKET, SO_REUSEPORT, (char *)&opt, sizeof(int));
|
srv.so._setsockopt(srv.so.state, sock, SOL_SOCKET, SO_REUSEPORT, (char *)&opt, sizeof(int));
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
#if defined SO_BINDTODEVICE
|
#if defined SO_BINDTODEVICE || defined IP_BOUND_IF
|
||||||
if(srv.ibindtodevice && srv.so._setsockopt(srv.so.state, sock, SOL_SOCKET, SO_BINDTODEVICE, srv.ibindtodevice, strlen(srv.ibindtodevice) + 1)) {
|
if(bindtodevice(&srv.so, srv.so.state, sock, srv.ibindtodevice, *SAFAMILY(&srv.intsa))) {
|
||||||
dolog(&defparam, (unsigned char *)"failed to bind device");
|
dolog(&defparam, (unsigned char *)"failed to bind device");
|
||||||
return -12;
|
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
|
#endif
|
||||||
}
|
}
|
||||||
#ifdef WITH_UN
|
#ifdef WITH_UN
|
||||||
@ -878,6 +903,9 @@ int MODULEMAINFUNC (int argc, char** argv){
|
|||||||
return -3;
|
return -3;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#ifdef WITH_UN
|
||||||
|
unbound(&srv);
|
||||||
|
#endif
|
||||||
if(!isudp){
|
if(!isudp){
|
||||||
if(srv.so._listen (srv.so.state, sock, srv.backlog?srv.backlog : 1+(srv.maxchild>>3))==-1) {
|
if(srv.so._listen (srv.so.state, sock, srv.backlog?srv.backlog : 1+(srv.maxchild>>3))==-1) {
|
||||||
sprintf((char *)buf, "listen(): %s", strerror(errno));
|
sprintf((char *)buf, "listen(): %s", strerror(errno));
|
||||||
@ -1012,6 +1040,15 @@ int MODULEMAINFUNC (int argc, char** argv){
|
|||||||
setopts(new_sock, srv.cbcsockopts);
|
setopts(new_sock, srv.cbcsockopts);
|
||||||
|
|
||||||
parsehost(srv.family, cbc_string, (struct sockaddr *)&defparam.sincr);
|
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)) {
|
if(connectwithpoll(NULL, new_sock,(struct sockaddr *)&defparam.sincr,SASIZE(&defparam.sincr),CONNBACK_TO)) {
|
||||||
so._closesocket(so.state, new_sock);
|
so._closesocket(so.state, new_sock);
|
||||||
new_sock = INVALID_SOCKET;
|
new_sock = INVALID_SOCKET;
|
||||||
@ -1019,7 +1056,7 @@ int MODULEMAINFUNC (int argc, char** argv){
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(sockrecvfrom(NULL, new_sock,(struct sockaddr*)&defparam.sincr,buf,1,60*1000) != 1 || *buf!='C') {
|
if(sockrecvfrom(NULL, new_sock, NULL, buf, 1, 60*1000) != 1 || *buf!='C') {
|
||||||
so._closesocket(so.state, new_sock);
|
so._closesocket(so.state, new_sock);
|
||||||
new_sock = INVALID_SOCKET;
|
new_sock = INVALID_SOCKET;
|
||||||
usleep(SLEEPTIME);
|
usleep(SLEEPTIME);
|
||||||
@ -1094,10 +1131,14 @@ int MODULEMAINFUNC (int argc, char** argv){
|
|||||||
#else
|
#else
|
||||||
fcntl(new_sock,F_SETFL,O_NONBLOCK | fcntl(new_sock,F_GETFL));
|
fcntl(new_sock,F_SETFL,O_NONBLOCK | fcntl(new_sock,F_GETFL));
|
||||||
#endif
|
#endif
|
||||||
|
#ifndef _WIN32
|
||||||
|
/* Not on Windows: there closesocket() on a non-blocking socket with a linger
|
||||||
|
timeout fails with WSAEWOULDBLOCK while data is queued, leaving the socket
|
||||||
|
open. Without it the close completes in the background, data first. */
|
||||||
lg.l_onoff = 1;
|
lg.l_onoff = 1;
|
||||||
lg.l_linger = conf.timeouts[STRING_L];
|
lg.l_linger = conf.timeouts[STRING_L];
|
||||||
|
|
||||||
srv.so._setsockopt(srv.so.state, new_sock, SOL_SOCKET, SO_LINGER, (char *)&lg, sizeof(lg));
|
srv.so._setsockopt(srv.so.state, new_sock, SOL_SOCKET, SO_LINGER, (char *)&lg, sizeof(lg));
|
||||||
|
#endif
|
||||||
srv.so._setsockopt(srv.so.state, new_sock, SOL_SOCKET, SO_OOBINLINE, (char *)&opt, sizeof(int));
|
srv.so._setsockopt(srv.so.state, new_sock, SOL_SOCKET, SO_OOBINLINE, (char *)&opt, sizeof(int));
|
||||||
}
|
}
|
||||||
#ifndef NOUDPMAIN
|
#ifndef NOUDPMAIN
|
||||||
@ -1315,14 +1356,23 @@ void srvfree(struct srvparam * srv){
|
|||||||
if(srv->srvsock != INVALID_SOCKET) {
|
if(srv->srvsock != INVALID_SOCKET) {
|
||||||
so._closesocket(srv->so.state, srv->srvsock);
|
so._closesocket(srv->so.state, srv->srvsock);
|
||||||
#ifdef WITH_UN
|
#ifdef WITH_UN
|
||||||
if(*SAFAMILY(&srv->intsa) == AF_UNIX && *SAADDR(&srv->intsa))unlink((char *)SAADDR(&srv->intsa));
|
ununlink(srv);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
srv->srvsock = INVALID_SOCKET;
|
srv->srvsock = INVALID_SOCKET;
|
||||||
if(srv->cbsock != INVALID_SOCKET) so._closesocket(srv->so.state, srv->cbsock);
|
if(srv->cbsock != INVALID_SOCKET) so._closesocket(srv->so.state, srv->cbsock);
|
||||||
srv->cbsock = INVALID_SOCKET;
|
srv->cbsock = INVALID_SOCKET;
|
||||||
srv->service = S_ZOMBIE;
|
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
|
#ifndef STDMAIN
|
||||||
if(srv->filter){
|
if(srv->filter){
|
||||||
while(srv->nfilters){
|
while(srv->nfilters){
|
||||||
@ -1364,40 +1414,44 @@ void srvfree(struct srvparam * srv){
|
|||||||
void freeparam(struct clientparam * param) {
|
void freeparam(struct clientparam * param) {
|
||||||
if(param->srv){
|
if(param->srv){
|
||||||
if(param->srv->so.freefunc) param->srv->so.freefunc(param->sostate);
|
if(param->srv->so.freefunc) param->srv->so.freefunc(param->sostate);
|
||||||
_3proxy_mutex_lock(¶m->srv->counter_mutex);
|
|
||||||
#ifndef STDMAIN
|
#ifndef STDMAIN
|
||||||
if(param->srv->service == S_UDPPM) hashdelete(&udp_table, param);
|
if(param->srv->service == S_UDPPM){
|
||||||
#endif
|
_3proxy_mutex_lock(¶m->srv->counter_mutex);
|
||||||
if(param->prev || param->next || param->srv->child == param){
|
hashdelete(&udp_table, 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);
|
_3proxy_mutex_unlock(¶m->srv->counter_mutex);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
if(param->clibuf) free(param->clibuf);
|
if(param->clibuf) free(param->clibuf);
|
||||||
if(param->srvbuf) free(param->srvbuf);
|
if(param->srvbuf) free(param->srvbuf);
|
||||||
|
/* Not shut down on Windows: there shutting down receiving resets the
|
||||||
|
connection as soon as the peer sends anything more, and close()
|
||||||
|
alone sends whatever is queued before its FIN. Elsewhere it stays:
|
||||||
|
on the BSDs it discards what is left unread, so the close that
|
||||||
|
follows is not turned into a reset. */
|
||||||
if(param->srv) {
|
if(param->srv) {
|
||||||
if(param->ctrlsocksrv != INVALID_SOCKET && param->ctrlsocksrv != param->remsock) {
|
if(param->ctrlsocksrv != INVALID_SOCKET && param->ctrlsocksrv != param->remsock) {
|
||||||
|
#ifndef _WIN32
|
||||||
param->srv->so._shutdown(param->sostate, param->ctrlsocksrv, SHUT_RDWR);
|
param->srv->so._shutdown(param->sostate, param->ctrlsocksrv, SHUT_RDWR);
|
||||||
|
#endif
|
||||||
param->srv->so._closesocket(param->sostate, param->ctrlsocksrv);
|
param->srv->so._closesocket(param->sostate, param->ctrlsocksrv);
|
||||||
}
|
}
|
||||||
if(param->ctrlsock != INVALID_SOCKET && param->ctrlsock != param->clisock) {
|
if(param->ctrlsock != INVALID_SOCKET && param->ctrlsock != param->clisock) {
|
||||||
|
#ifndef _WIN32
|
||||||
param->srv->so._shutdown(param->sostate, param->ctrlsock, SHUT_RDWR);
|
param->srv->so._shutdown(param->sostate, param->ctrlsock, SHUT_RDWR);
|
||||||
|
#endif
|
||||||
param->srv->so._closesocket(param->sostate, param->ctrlsock);
|
param->srv->so._closesocket(param->sostate, param->ctrlsock);
|
||||||
}
|
}
|
||||||
if(param->remsock != INVALID_SOCKET) {
|
if(param->remsock != INVALID_SOCKET) {
|
||||||
|
#ifndef _WIN32
|
||||||
param->srv->so._shutdown(param->sostate, param->remsock, SHUT_RDWR);
|
param->srv->so._shutdown(param->sostate, param->remsock, SHUT_RDWR);
|
||||||
|
#endif
|
||||||
param->srv->so._closesocket(param->sostate, param->remsock);
|
param->srv->so._closesocket(param->sostate, param->remsock);
|
||||||
}
|
}
|
||||||
if(param->clisock != INVALID_SOCKET) {
|
if(param->clisock != INVALID_SOCKET) {
|
||||||
|
#ifndef _WIN32
|
||||||
param->srv->so._shutdown(param->sostate, param->clisock, SHUT_RDWR);
|
param->srv->so._shutdown(param->sostate, param->clisock, SHUT_RDWR);
|
||||||
|
#endif
|
||||||
param->srv->so._closesocket(param->sostate, param->clisock);
|
param->srv->so._closesocket(param->sostate, param->clisock);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1419,6 +1473,24 @@ void freeparam(struct clientparam * param) {
|
|||||||
}
|
}
|
||||||
if(param->connlim) stopconnlims(param);
|
if(param->connlim) stopconnlims(param);
|
||||||
#endif
|
#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->hostname) free(param->hostname);
|
||||||
if(param->username) free(param->username);
|
if(param->username) free(param->username);
|
||||||
if(param->password) free(param->password);
|
if(param->password) free(param->password);
|
||||||
@ -1658,9 +1730,17 @@ FILTER_ACTION makefilters (struct srvparam *srv, struct clientparam *param){
|
|||||||
|
|
||||||
for(i=0; i<srv->nfilters; i++){
|
for(i=0; i<srv->nfilters; i++){
|
||||||
if(!srv->filter[i].filter_client)continue;
|
if(!srv->filter[i].filter_client)continue;
|
||||||
|
/* the slots are not cleared when they are allocated */
|
||||||
|
param->filters[param->nfilters].data = NULL;
|
||||||
action = (*srv->filter[i].filter_client)(srv->filter[i].data, param, ¶m->filters[param->nfilters].data);
|
action = (*srv->filter[i].filter_client)(srv->filter[i].data, param, ¶m->filters[param->nfilters].data);
|
||||||
if(action == PASS) continue;
|
if(action == PASS) continue;
|
||||||
if(action > CONTINUE) return action;
|
if(action > CONTINUE) {
|
||||||
|
/* a filter refusing the connection is not kept, but it may
|
||||||
|
have made a state for it */
|
||||||
|
if(srv->filter[i].filter_clear && param->filters[param->nfilters].data)
|
||||||
|
(*srv->filter[i].filter_clear)(param->filters[param->nfilters].data);
|
||||||
|
return action;
|
||||||
|
}
|
||||||
param->filters[param->nfilters].filter = srv->filter + i;
|
param->filters[param->nfilters].filter = srv->filter + i;
|
||||||
if(srv->filter[i].filter_request)param->reqfilters[param->nreqfilters++] = param->filters + param->nfilters;
|
if(srv->filter[i].filter_request)param->reqfilters[param->nreqfilters++] = param->filters + param->nfilters;
|
||||||
if(srv->filter[i].filter_connect)param->connectfilters[param->nconnectfilters++] = param->filters + param->nfilters;
|
if(srv->filter[i].filter_connect)param->connectfilters[param->nconnectfilters++] = param->filters + param->nfilters;
|
||||||
|
|||||||
@ -159,7 +159,10 @@ void * smtppchild(struct clientparam* param) {
|
|||||||
i = de64(buf,username,255);
|
i = de64(buf,username,255);
|
||||||
if(i < 1) {RETURN(664);}
|
if(i < 1) {RETURN(664);}
|
||||||
username[i] = 0;
|
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]);
|
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]);
|
i = sockgetlinebuf(param, CLIENT, buf, sizeof(buf) - 10, '\n', conf.timeouts[STRING_S]);
|
||||||
if(i < 2) {RETURN(665);}
|
if(i < 2) {RETURN(665);}
|
||||||
@ -184,7 +187,7 @@ void * smtppchild(struct clientparam* param) {
|
|||||||
}
|
}
|
||||||
if(i < 3 || *username) {RETURN(668);}
|
if(i < 3 || *username) {RETURN(668);}
|
||||||
username[i] = 0;
|
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;
|
res = (int)strlen((char *)username+1) + 2;
|
||||||
if(res < i){
|
if(res < i){
|
||||||
if(param->extpassword) free(param->extpassword);
|
if(param->extpassword) free(param->extpassword);
|
||||||
|
|||||||
@ -60,14 +60,21 @@ int sockrecvfrom(struct clientparam *param, SOCKET sock, struct sockaddr * sin,
|
|||||||
|
|
||||||
fds.fd = sock;
|
fds.fd = sock;
|
||||||
fds.events = POLLIN;
|
fds.events = POLLIN;
|
||||||
|
for(;;){
|
||||||
if(conf.timetoexit) return EOF;
|
if(conf.timetoexit) return EOF;
|
||||||
res = param?param->srv->so._poll(param->sostate, &fds, 1, to):so._poll(so.state, &fds, 1, to);
|
res = param?param->srv->so._poll(param->sostate, &fds, 1, to):so._poll(so.state, &fds, 1, to);
|
||||||
if (res<1) return 0;
|
if (res<1) return 0;
|
||||||
sasize = SASIZE(sin);
|
sasize = sizeof(PROXYSOCKADDRTYPE);
|
||||||
|
/* sin NULL for a stream socket: nothing to learn the address into */
|
||||||
do {
|
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);
|
res = param?param->srv->so._recvfrom(param->sostate, sock, (char *)buf, bufsize, 0, (struct sockaddr *)sin, sin? &sasize : NULL):so._recvfrom(so.state, sock, (char *)buf, bufsize, 0, (struct sockaddr *)sin, sin? &sasize : NULL);
|
||||||
} while (res < 0 && (errno == EAGAIN || errno == EINTR));
|
} while (res < 0 && errno == EINTR);
|
||||||
return res;
|
/* readable and still nothing to read: over TLS a record not yet
|
||||||
|
whole. Read again, without polling, it would only be the same until
|
||||||
|
the rest came, a loop taking all of a CPU and never timing out: the
|
||||||
|
socket is polled for it instead. */
|
||||||
|
if(res >= 0 || errno != EAGAIN) return res;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int sockgetcharcli(struct clientparam * param, int timeosec, int timeousec){
|
int sockgetcharcli(struct clientparam * param, int timeosec, int timeousec){
|
||||||
|
|||||||
@ -49,6 +49,28 @@ ssize_t splice(int fd_in, loff_t *off_in, int fd_out, loff_t *off_out, size_t le
|
|||||||
before the sockets are closed. */
|
before the sockets are closed. */
|
||||||
#define SESSIONEND (!halfclose && (CLIENTTERMREAD || SERVERTERMREAD))
|
#define SESSIONEND (!halfclose && (CLIENTTERMREAD || SERVERTERMREAD))
|
||||||
|
|
||||||
|
/* A hang-up on a socket there is data to write to. With poll() it comes
|
||||||
|
once both sides are shut down, and the write tried then fails, which ends
|
||||||
|
it. WSAPoll reports it as soon as the peer has half-closed, a peer still
|
||||||
|
reading, and keeps reporting it whether the socket has room or not: room
|
||||||
|
is waited for with select() then, up to timeo seconds. Returns whether to
|
||||||
|
try the write. */
|
||||||
|
static int hupwrite(SOCKET s, short revents, int timeo){
|
||||||
|
#ifdef _WIN32
|
||||||
|
if(!(revents & POLLOUT)){
|
||||||
|
fd_set wfd;
|
||||||
|
struct timeval tv;
|
||||||
|
|
||||||
|
FD_ZERO(&wfd);
|
||||||
|
FD_SET(s, &wfd);
|
||||||
|
tv.tv_sec = timeo;
|
||||||
|
tv.tv_usec = 0;
|
||||||
|
if(select(0, NULL, &wfd, NULL, &tv) < 1) return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
int sockmap(struct clientparam * param, int timeo, int usesplice){
|
int sockmap(struct clientparam * param, int timeo, int usesplice){
|
||||||
int halfclose = param->srv->halfclose;
|
int halfclose = param->srv->halfclose;
|
||||||
uint64_t fromclient=0x7fffffffffffffff, fromserver =0x7fffffffffffffff;
|
uint64_t fromclient=0x7fffffffffffffff, fromserver =0x7fffffffffffffff;
|
||||||
@ -60,13 +82,16 @@ int sockmap(struct clientparam * param, int timeo, int usesplice){
|
|||||||
#endif
|
#endif
|
||||||
int HASERROR=0;
|
int HASERROR=0;
|
||||||
int CLIENTTERMREAD = 0, CLIENTTERMWRITE = 0, SERVERTERMREAD = 0, SERVERTERMWRITE = 0;
|
int CLIENTTERMREAD = 0, CLIENTTERMWRITE = 0, SERVERTERMREAD = 0, SERVERTERMWRITE = 0;
|
||||||
|
/* the side has hung up: closed by the peer after its own was shut down */
|
||||||
|
int CLIENTHUP = 0, SERVERHUP = 0;
|
||||||
|
/* whether the side's socket is in this round's poll() */
|
||||||
|
int clipolled = 1, srvpolled = 1;
|
||||||
int after = 0;
|
int after = 0;
|
||||||
struct pollfd fds[8];
|
struct pollfd fds[8];
|
||||||
int fdsc = 0;
|
int fdsc = 0;
|
||||||
int sleeptime = 0;
|
int sleeptime = 0;
|
||||||
FILTER_ACTION action;
|
FILTER_ACTION action;
|
||||||
int res = 0;
|
int res = 0;
|
||||||
SASIZETYPE sasize;
|
|
||||||
int needaction = 0;
|
int needaction = 0;
|
||||||
int graceclinum=0, gracesrvnum=0, graceclitraf=0, gracesrvtraf=0;
|
int graceclinum=0, gracesrvnum=0, graceclitraf=0, gracesrvtraf=0;
|
||||||
time_t gracetime = 0;
|
time_t gracetime = 0;
|
||||||
@ -220,8 +245,7 @@ log("send to server from buf");
|
|||||||
param->clioffset = param->cliinbuf = 0;
|
param->clioffset = param->cliinbuf = 0;
|
||||||
if(fromclient) TOCLIENTBUF = 1;
|
if(fromclient) TOCLIENTBUF = 1;
|
||||||
}
|
}
|
||||||
sasize = SASIZE(¶m->sinsr);
|
res = param->srv->so._sendto(param->sostate, param->remsock, (char *)param->clibuf + param->clioffset, (int)MIN(inclientbuf, fromclient), 0, NULL, 0);
|
||||||
res = param->srv->so._sendto(param->sostate, param->remsock, (char *)param->clibuf + param->clioffset, (int)MIN(inclientbuf, fromclient), 0, (struct sockaddr*)¶m->sinsr, sasize);
|
|
||||||
if(res <= 0) {
|
if(res <= 0) {
|
||||||
TOSERVER = 0;
|
TOSERVER = 0;
|
||||||
if(errno && errno != EAGAIN && errno != EINTR){
|
if(errno && errno != EAGAIN && errno != EINTR){
|
||||||
@ -267,8 +291,7 @@ log("send to client from buf");
|
|||||||
if(fromserver) TOSERVERBUF = 1;
|
if(fromserver) TOSERVERBUF = 1;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
sasize = SASIZE(¶m->sincr);
|
res = param->srv->so._sendto(param->sostate, param->clisock, (char *)param->srvbuf + param->srvoffset, (int)MIN(inserverbuf,fromserver), 0, NULL, 0);
|
||||||
res = param->srv->so._sendto(param->sostate, param->clisock, (char *)param->srvbuf + param->srvoffset, (int)MIN(inserverbuf,fromserver), 0, (struct sockaddr*)¶m->sincr, sasize);
|
|
||||||
if(res <= 0) {
|
if(res <= 0) {
|
||||||
TOCLIENT = 0;
|
TOCLIENT = 0;
|
||||||
if(errno && errno != EAGAIN && errno != EINTR){
|
if(errno && errno != EAGAIN && errno != EINTR){
|
||||||
@ -459,8 +482,7 @@ log("done read from server to pipe\n");
|
|||||||
#ifdef WITHLOG
|
#ifdef WITHLOG
|
||||||
log("read from client to buf");
|
log("read from client to buf");
|
||||||
#endif
|
#endif
|
||||||
sasize = sizeof(param->sincr);
|
res = param->srv->so._recvfrom(param->sostate, param->clisock, (char *)param->clibuf + param->cliinbuf, (int)MIN((uint64_t)param->clibufsize - param->cliinbuf, fromclient-inclientbuf), 0, NULL, NULL);
|
||||||
res = param->srv->so._recvfrom(param->sostate, param->clisock, (char *)param->clibuf + param->cliinbuf, (int)MIN((uint64_t)param->clibufsize - param->cliinbuf, fromclient-inclientbuf), 0, (struct sockaddr *)¶m->sincr, &sasize);
|
|
||||||
if(res <= 0) {
|
if(res <= 0) {
|
||||||
FROMCLIENT = 0;
|
FROMCLIENT = 0;
|
||||||
if(res == 0) {
|
if(res == 0) {
|
||||||
@ -492,8 +514,7 @@ log("done read from client to buf");
|
|||||||
#ifdef WITHLOG
|
#ifdef WITHLOG
|
||||||
log("read from server to buf");
|
log("read from server to buf");
|
||||||
#endif
|
#endif
|
||||||
sasize = sizeof(param->sinsr);
|
res = param->srv->so._recvfrom(param->sostate, param->remsock, (char *)param->srvbuf + param->srvinbuf, (int)MIN((uint64_t)param->srvbufsize - param->srvinbuf, fromserver-inserverbuf), 0, NULL, NULL);
|
||||||
res = param->srv->so._recvfrom(param->sostate, param->remsock, (char *)param->srvbuf + param->srvinbuf, (int)MIN((uint64_t)param->srvbufsize - param->srvinbuf, fromserver-inserverbuf), 0, (struct sockaddr *)¶m->sinsr, &sasize);
|
|
||||||
if(res <= 0) {
|
if(res <= 0) {
|
||||||
FROMSERVER = 0;
|
FROMSERVER = 0;
|
||||||
if(res == 0) {
|
if(res == 0) {
|
||||||
@ -569,6 +590,11 @@ log("done read from server to buf");
|
|||||||
#endif
|
#endif
|
||||||
))
|
))
|
||||||
cli_events |= POLLOUT;
|
cli_events |= POLLOUT;
|
||||||
|
/* poll() reports a hang-up whatever is asked, and would
|
||||||
|
return at once every time: the socket is left out then,
|
||||||
|
rather than given as an invalid one, which WSAPoll takes
|
||||||
|
for an error */
|
||||||
|
clipolled = cli_events || !CLIENTHUP;
|
||||||
if(cli_events){
|
if(cli_events){
|
||||||
fds[fdsc].fd = param->clisock;
|
fds[fdsc].fd = param->clisock;
|
||||||
fds[fdsc].events = cli_events;
|
fds[fdsc].events = cli_events;
|
||||||
@ -580,6 +606,8 @@ log("wait writing to client");
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if(!clipolled){
|
||||||
|
}
|
||||||
else if(cli_events){
|
else if(cli_events){
|
||||||
if(fds[fdsc].revents & (POLLERR|POLLNVAL)) {
|
if(fds[fdsc].revents & (POLLERR|POLLNVAL)) {
|
||||||
CLIENTTERMREAD = 1;
|
CLIENTTERMREAD = 1;
|
||||||
@ -601,14 +629,21 @@ log("ready to write to client");
|
|||||||
}
|
}
|
||||||
if(fds[fdsc].revents & (POLLHUP)) {
|
if(fds[fdsc].revents & (POLLHUP)) {
|
||||||
if(fds[fdsc].events & POLLIN) FROMCLIENT = 1;
|
if(fds[fdsc].events & POLLIN) FROMCLIENT = 1;
|
||||||
if(fds[fdsc].events & POLLOUT) CLIENTTERMWRITE = 1;
|
if(fds[fdsc].events & POLLOUT){
|
||||||
|
if(hupwrite(param->clisock, fds[fdsc].revents, timeo)) TOCLIENT = 1;
|
||||||
|
else CLIENTTERMWRITE = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if(fds[fdsc].revents & (POLLERR|POLLNVAL|POLLHUP)) {
|
}
|
||||||
|
} else if(fds[fdsc].revents & (POLLERR|POLLNVAL)) {
|
||||||
CLIENTTERMREAD = 1;
|
CLIENTTERMREAD = 1;
|
||||||
CLIENTTERMWRITE = 1;
|
CLIENTTERMWRITE = 1;
|
||||||
|
} else if(fds[fdsc].revents & POLLHUP) {
|
||||||
|
/* what the client sent before it closed is still to be
|
||||||
|
read, once the buffer has room for it */
|
||||||
|
CLIENTHUP = 1;
|
||||||
}
|
}
|
||||||
fdsc++;
|
if(clipolled) fdsc++;
|
||||||
|
|
||||||
// if(!SERVERTERMREAD || !SERVERTERMWRITE){
|
// if(!SERVERTERMREAD || !SERVERTERMWRITE){
|
||||||
if(!after){
|
if(!after){
|
||||||
@ -629,6 +664,7 @@ log("ready to write to client");
|
|||||||
#endif
|
#endif
|
||||||
))
|
))
|
||||||
srv_events |= POLLOUT;
|
srv_events |= POLLOUT;
|
||||||
|
srvpolled = srv_events || !SERVERHUP;
|
||||||
if(srv_events){
|
if(srv_events){
|
||||||
fds[fdsc].fd = param->remsock;
|
fds[fdsc].fd = param->remsock;
|
||||||
fds[fdsc].events = srv_events;
|
fds[fdsc].events = srv_events;
|
||||||
@ -640,6 +676,8 @@ log("wait writing from server");
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if(!srvpolled){
|
||||||
|
}
|
||||||
else if(srv_events){
|
else if(srv_events){
|
||||||
if(fds[fdsc].revents & (POLLERR|POLLNVAL)) {
|
if(fds[fdsc].revents & (POLLERR|POLLNVAL)) {
|
||||||
#ifdef WITHLOG
|
#ifdef WITHLOG
|
||||||
@ -668,14 +706,20 @@ log("ready to write to server");
|
|||||||
log("server terminated connection");
|
log("server terminated connection");
|
||||||
#endif
|
#endif
|
||||||
if(fds[fdsc].events & POLLIN) FROMSERVER = 1;
|
if(fds[fdsc].events & POLLIN) FROMSERVER = 1;
|
||||||
if(fds[fdsc].events & POLLOUT) SERVERTERMWRITE = 1;
|
if(fds[fdsc].events & POLLOUT){
|
||||||
|
if(hupwrite(param->remsock, fds[fdsc].revents, timeo)) TOSERVER = 1;
|
||||||
|
else SERVERTERMWRITE = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if(fds[fdsc].revents & (POLLERR|POLLNVAL|POLLHUP)) {
|
}
|
||||||
|
} else if(fds[fdsc].revents & (POLLERR|POLLNVAL)) {
|
||||||
SERVERTERMREAD = 1;
|
SERVERTERMREAD = 1;
|
||||||
SERVERTERMWRITE = 1;
|
SERVERTERMWRITE = 1;
|
||||||
|
} else if(fds[fdsc].revents & POLLHUP) {
|
||||||
|
/* the rest of the answer may still be waiting to be read */
|
||||||
|
SERVERHUP = 1;
|
||||||
}
|
}
|
||||||
fdsc++;
|
if(srvpolled) fdsc++;
|
||||||
// }
|
// }
|
||||||
#ifdef WITHSPLICE
|
#ifdef WITHSPLICE
|
||||||
if(usesplice){
|
if(usesplice){
|
||||||
@ -819,9 +863,6 @@ log("timeout");
|
|||||||
else if(inclientpipe || inserverpipe) res = 94;
|
else if(inclientpipe || inserverpipe) res = 94;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if((param->nwrites > 0 && !SERVERTERMWRITE) || (param->nreads > 0 && !CLIENTTERMWRITE))
|
|
||||||
usleep(SLEEPTIME * 10);
|
|
||||||
|
|
||||||
CLEANRET:
|
CLEANRET:
|
||||||
|
|
||||||
#ifdef WITHSPLICE
|
#ifdef WITHSPLICE
|
||||||
|
|||||||
15
src/socks.c
15
src/socks.c
@ -185,6 +185,7 @@ void * sockschild(struct clientparam* param) {
|
|||||||
if(command == 2){
|
if(command == 2){
|
||||||
if ((param->remsock=param->srv->so._socket(param->sostate, SASOCK(¶m->req), SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET) {RETURN (11);}
|
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);
|
setopts(param->remsock, param->srv->lissockopts);
|
||||||
|
if(extbindtodevice(param, param->remsock)) {RETURN (12);}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -226,7 +227,7 @@ fprintf(stderr, "%hu bound to communicate with server\n", *SAPORT(¶m->sinsl)
|
|||||||
fflush(stderr);
|
fflush(stderr);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
sasize = SASIZE(¶m->sinsl);
|
sasize = sizeof(param->sinsl);
|
||||||
param->srv->so._getsockname(param->sostate, param->remsock, (struct sockaddr *)¶m->sinsl, &sasize);
|
param->srv->so._getsockname(param->sostate, param->remsock, (struct sockaddr *)¶m->sinsl, &sasize);
|
||||||
}
|
}
|
||||||
if(command == 3) {
|
if(command == 3) {
|
||||||
@ -241,10 +242,11 @@ fflush(stderr);
|
|||||||
#else
|
#else
|
||||||
fcntl(param->clisock, F_SETFL, O_NONBLOCK | fcntl(param->clisock, F_GETFL));
|
fcntl(param->clisock, F_SETFL, O_NONBLOCK | fcntl(param->clisock, F_GETFL));
|
||||||
#endif
|
#endif
|
||||||
|
if(intbindtodevice(param, param->clisock)) {RETURN (12);}
|
||||||
sin = param->sincl;
|
sin = param->sincl;
|
||||||
*SAPORT(&sin) = 0;
|
*SAPORT(&sin) = 0;
|
||||||
if(param->srv->so._bind(param->sostate, param->clisock,(struct sockaddr *)&sin,SASIZE(&sin))) {RETURN (12);}
|
if(param->srv->so._bind(param->sostate, param->clisock,(struct sockaddr *)&sin,SASIZE(&sin))) {RETURN (12);}
|
||||||
sasize = SASIZE(&sin);
|
sasize = sizeof(sin);
|
||||||
param->srv->so._getsockname(param->sostate, param->clisock, (struct sockaddr *)&sin, &sasize);
|
param->srv->so._getsockname(param->sostate, param->clisock, (struct sockaddr *)&sin, &sasize);
|
||||||
#if SOCKSTRACE > 0
|
#if SOCKSTRACE > 0
|
||||||
fprintf(stderr, "%hu binded to communicate with client\n",
|
fprintf(stderr, "%hu binded to communicate with client\n",
|
||||||
@ -266,13 +268,18 @@ CLEANRET:
|
|||||||
int repcode;
|
int repcode;
|
||||||
|
|
||||||
sasize = sizeof(sin);
|
sasize = sizeof(sin);
|
||||||
if(command != 3 && param->remsock != INVALID_SOCKET) param->srv->so._getsockname(param->sostate, param->remsock, (struct sockaddr *)&sin, &sasize);
|
/* CONNECT and BIND report the address of the socket towards the
|
||||||
if(command != 3 && !SAISNULL(¶m->srv->extNat)){
|
destination, UDP ASSOCIATE the one the client sends its datagrams
|
||||||
|
to, as does a request which never got a socket of its own */
|
||||||
|
if(command != 3 && param->remsock != INVALID_SOCKET){
|
||||||
|
param->srv->so._getsockname(param->sostate, param->remsock, (struct sockaddr *)&sin, &sasize);
|
||||||
|
if(!SAISNULL(¶m->srv->extNat)){
|
||||||
uint16_t port;
|
uint16_t port;
|
||||||
port = *SAPORT(&sin);
|
port = *SAPORT(&sin);
|
||||||
sin = param->srv->extNat;
|
sin = param->srv->extNat;
|
||||||
*SAPORT(&sin) = port;
|
*SAPORT(&sin) = port;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
param->srv->so._getsockname(param->sostate, param->clisock, (struct sockaddr *)&sin, &sasize);
|
param->srv->so._getsockname(param->sostate, param->clisock, (struct sockaddr *)&sin, &sasize);
|
||||||
if(command == 3 && !SAISNULL(¶m->srv->intNat)){
|
if(command == 3 && !SAISNULL(¶m->srv->intNat)){
|
||||||
|
|||||||
11
src/ssl.c
11
src/ssl.c
@ -779,7 +779,7 @@ static FILTER_ACTION ssl_filter_client(void *fo, struct clientparam * param, voi
|
|||||||
}
|
}
|
||||||
|
|
||||||
static FILTER_ACTION ssl_filter_connect(void *fc, struct clientparam * param){
|
static FILTER_ACTION ssl_filter_connect(void *fc, struct clientparam * param){
|
||||||
if(PCONF->cli && !client_mode) {
|
if(PCONF->cli && !PCONF->client_mode) {
|
||||||
if(docli(param)) {
|
if(docli(param)) {
|
||||||
return REJECT;
|
return REJECT;
|
||||||
}
|
}
|
||||||
@ -788,7 +788,7 @@ static FILTER_ACTION ssl_filter_connect(void *fc, struct clientparam * param){
|
|||||||
}
|
}
|
||||||
|
|
||||||
static FILTER_ACTION ssl_filter_afterauth(void *fc, struct clientparam * param){
|
static FILTER_ACTION ssl_filter_afterauth(void *fc, struct clientparam * param){
|
||||||
if(PCONF->cli && client_mode == 1) {
|
if(PCONF->cli && PCONF->client_mode == 1) {
|
||||||
if(docli(param)) {
|
if(docli(param)) {
|
||||||
return REJECT;
|
return REJECT;
|
||||||
}
|
}
|
||||||
@ -806,7 +806,7 @@ static FILTER_ACTION ssl_filter_predata(void *fc, struct clientparam * param){
|
|||||||
if(!param->redirectfunc) param->redirectfunc = proxyfunc;
|
if(!param->redirectfunc) param->redirectfunc = proxyfunc;
|
||||||
return CONTINUE;
|
return CONTINUE;
|
||||||
}
|
}
|
||||||
else if(PCONF->cli && client_mode == 2) {
|
else if(PCONF->cli && PCONF->client_mode == 2) {
|
||||||
if(docli(param)) {
|
if(docli(param)) {
|
||||||
return REJECT;
|
return REJECT;
|
||||||
}
|
}
|
||||||
@ -815,7 +815,7 @@ static FILTER_ACTION ssl_filter_predata(void *fc, struct clientparam * param){
|
|||||||
}
|
}
|
||||||
|
|
||||||
static FILTER_ACTION ssl_parent(struct clientparam * param){
|
static FILTER_ACTION ssl_parent(struct clientparam * param){
|
||||||
if(PCONF->cli && client_mode == 3) {
|
if(PCONF->cli && PCONF->client_mode == 3) {
|
||||||
if(docli(param)) {
|
if(docli(param)) {
|
||||||
return REJECT;
|
return REJECT;
|
||||||
}
|
}
|
||||||
@ -867,6 +867,9 @@ static void ssl_filter_close(void *fo){
|
|||||||
free(CONFIG->client_ca_file);
|
free(CONFIG->client_ca_file);
|
||||||
free(CONFIG->client_ca_dir);
|
free(CONFIG->client_ca_dir);
|
||||||
free(CONFIG->client_ca_store);
|
free(CONFIG->client_ca_store);
|
||||||
|
free(CONFIG->server_ca_file);
|
||||||
|
free(CONFIG->server_ca_dir);
|
||||||
|
free(CONFIG->server_ca_store);
|
||||||
free(CONFIG->client_sni);
|
free(CONFIG->client_sni);
|
||||||
if(CONFIG->client_alpn_protos.protos_len){
|
if(CONFIG->client_alpn_protos.protos_len){
|
||||||
free(CONFIG->client_alpn_protos.protos);
|
free(CONFIG->client_alpn_protos.protos);
|
||||||
|
|||||||
58
src/ssllib.c
58
src/ssllib.c
@ -22,6 +22,7 @@
|
|||||||
#include <wolfssl/openssl/pem.h>
|
#include <wolfssl/openssl/pem.h>
|
||||||
#include <wolfssl/openssl/ssl.h>
|
#include <wolfssl/openssl/ssl.h>
|
||||||
#include <wolfssl/openssl/err.h>
|
#include <wolfssl/openssl/err.h>
|
||||||
|
#include <wolfssl/openssl/bn.h>
|
||||||
#else
|
#else
|
||||||
#include <openssl/crypto.h>
|
#include <openssl/crypto.h>
|
||||||
#include <openssl/x509.h>
|
#include <openssl/x509.h>
|
||||||
@ -29,6 +30,7 @@
|
|||||||
#include <openssl/pem.h>
|
#include <openssl/pem.h>
|
||||||
#include <openssl/ssl.h>
|
#include <openssl/ssl.h>
|
||||||
#include <openssl/err.h>
|
#include <openssl/err.h>
|
||||||
|
#include <openssl/bn.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "proxy.h"
|
#include "proxy.h"
|
||||||
@ -84,7 +86,11 @@ static int copy_ext(X509 *dst_cert, X509 *src_cert, int nid)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifndef WITH_WOLFSSL
|
#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;
|
X509_EXTENSION *ex;
|
||||||
X509V3_CTX ctx;
|
X509V3_CTX ctx;
|
||||||
@ -92,10 +98,8 @@ static int add_ext(X509 *cert, int nid, const char *value)
|
|||||||
/* This sets the 'context' of the extensions. */
|
/* This sets the 'context' of the extensions. */
|
||||||
/* No configuration database */
|
/* No configuration database */
|
||||||
X509V3_set_ctx_nodb(&ctx);
|
X509V3_set_ctx_nodb(&ctx);
|
||||||
/* Issuer and subject certs: both the target since it is self signed,
|
/* No request and no CRL */
|
||||||
* no request and no CRL
|
X509V3_set_ctx(&ctx, issuer, cert, NULL, NULL, 0);
|
||||||
*/
|
|
||||||
X509V3_set_ctx(&ctx, cert, cert, NULL, NULL, 0);
|
|
||||||
/* value is char * prior to OpenSSL 1.1.0 */
|
/* value is char * prior to OpenSSL 1.1.0 */
|
||||||
ex = X509V3_EXT_conf_nid(NULL, &ctx, nid, (char *)value);
|
ex = X509V3_EXT_conf_nid(NULL, &ctx, nid, (char *)value);
|
||||||
if (!ex)
|
if (!ex)
|
||||||
@ -105,8 +109,39 @@ static int add_ext(X509 *cert, int nid, const char *value)
|
|||||||
X509_EXTENSION_free(ex);
|
X509_EXTENSION_free(ex);
|
||||||
return err > 0;
|
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
|
#endif
|
||||||
|
|
||||||
|
/* A serial number of the copy's own, when the source's cannot be set back:
|
||||||
|
* positive, from the hash of the source certificate, so the same for the
|
||||||
|
* same certificate and different for another. wolfSSL built with
|
||||||
|
* WOLFSSL_QT, as Ubuntu 26.04 has it, returns a serial number without the
|
||||||
|
* ASN.1 header its own X509_set_serialNumber() requires.
|
||||||
|
*/
|
||||||
|
static int set_serial_hash(X509 *cert, const unsigned char *hash)
|
||||||
|
{
|
||||||
|
unsigned char serial[16];
|
||||||
|
BIGNUM *bn;
|
||||||
|
ASN1_INTEGER *ai;
|
||||||
|
int res = 0;
|
||||||
|
|
||||||
|
memcpy(serial, hash, sizeof(serial));
|
||||||
|
serial[0] &= 0x7f;
|
||||||
|
if(!serial[0]) serial[0] = 1;
|
||||||
|
if(!(bn = BN_bin2bn(serial, sizeof(serial), NULL))) return 0;
|
||||||
|
if((ai = BN_to_ASN1_INTEGER(bn, NULL))){
|
||||||
|
res = X509_set_serialNumber(cert, ai);
|
||||||
|
ASN1_INTEGER_free(ai);
|
||||||
|
}
|
||||||
|
BN_free(bn);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
SSL_CERT ssl_copy_cert(SSL_CERT cert, SSL_CONFIG *config)
|
SSL_CERT ssl_copy_cert(SSL_CERT cert, SSL_CONFIG *config)
|
||||||
{
|
{
|
||||||
int err = -1;
|
int err = -1;
|
||||||
@ -154,7 +189,8 @@ SSL_CERT ssl_copy_cert(SSL_CERT cert, SSL_CONFIG *config)
|
|||||||
}
|
}
|
||||||
/* v3 is required, extensions are added below */
|
/* v3 is required, extensions are added below */
|
||||||
X509_set_version(dst_cert, 2);
|
X509_set_version(dst_cert, 2);
|
||||||
if(!X509_set_serialNumber(dst_cert, X509_get_serialNumber(src_cert))
|
if((!X509_set_serialNumber(dst_cert, X509_get_serialNumber(src_cert))
|
||||||
|
&& !set_serial_hash(dst_cert, hash_sha256))
|
||||||
|| !X509_set_subject_name(dst_cert, X509_get_subject_name(src_cert))
|
|| !X509_set_subject_name(dst_cert, X509_get_subject_name(src_cert))
|
||||||
|| !X509_set_issuer_name(dst_cert, X509_get_subject_name(config->CA_cert))){
|
|| !X509_set_issuer_name(dst_cert, X509_get_subject_name(config->CA_cert))){
|
||||||
X509_free(dst_cert);
|
X509_free(dst_cert);
|
||||||
@ -199,6 +235,16 @@ SSL_CERT ssl_copy_cert(SSL_CERT cert, SSL_CONFIG *config)
|
|||||||
add_ext(dst_cert, NID_basic_constraints, "critical,CA:FALSE");
|
add_ext(dst_cert, NID_basic_constraints, "critical,CA:FALSE");
|
||||||
if(!copy_ext(dst_cert, src_cert, NID_ext_key_usage))
|
if(!copy_ext(dst_cert, src_cert, NID_ext_key_usage))
|
||||||
add_ext(dst_cert, NID_ext_key_usage, "serverAuth");
|
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
|
#else
|
||||||
copy_ext(dst_cert, src_cert, NID_basic_constraints);
|
copy_ext(dst_cert, src_cert, NID_basic_constraints);
|
||||||
copy_ext(dst_cert, src_cert, NID_ext_key_usage);
|
copy_ext(dst_cert, src_cert, NID_ext_key_usage);
|
||||||
|
|||||||
@ -105,6 +105,7 @@ int
|
|||||||
|
|
||||||
#ifdef WITH_UN
|
#ifdef WITH_UN
|
||||||
#include <sys/un.h>
|
#include <sys/un.h>
|
||||||
|
#include <stddef.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define ALLOW 0
|
#define ALLOW 0
|
||||||
@ -152,7 +153,9 @@ int
|
|||||||
#define UN_SAADDR(sa) (((struct sockaddr_un *)sa)->sun_family == AF_UNIX)? (unsigned char *)((struct sockaddr_un *)sa)->sun_path :
|
#define UN_SAADDR(sa) (((struct sockaddr_un *)sa)->sun_family == AF_UNIX)? (unsigned char *)((struct sockaddr_un *)sa)->sun_path :
|
||||||
#define UN_SAADDRLEN(sa) (((struct sockaddr_un *)sa)->sun_family == AF_UNIX)? (int)sizeof(((struct sockaddr_un *)sa)->sun_path) :
|
#define UN_SAADDRLEN(sa) (((struct sockaddr_un *)sa)->sun_family == AF_UNIX)? (int)sizeof(((struct sockaddr_un *)sa)->sun_path) :
|
||||||
#define UN_SASOCK(sa) (((struct sockaddr_un *)sa)->sun_family == AF_UNIX)? PF_UNIX :
|
#define UN_SASOCK(sa) (((struct sockaddr_un *)sa)->sun_family == AF_UNIX)? PF_UNIX :
|
||||||
#define UN_SASIZE(sa) (((struct sockaddr_un *)sa)->sun_family == AF_UNIX)? sizeof(struct sockaddr_un) :
|
/* an abstract name (Linux) is its bytes after the leading 0, no more:
|
||||||
|
padded with zeros it would be another name */
|
||||||
|
#define UN_SASIZE(sa) (((struct sockaddr_un *)sa)->sun_family == AF_UNIX)? (((struct sockaddr_un *)sa)->sun_path[0] || !((struct sockaddr_un *)sa)->sun_path[1]? sizeof(struct sockaddr_un) : offsetof(struct sockaddr_un, sun_path) + 1 + strlen(((struct sockaddr_un *)sa)->sun_path + 1)) :
|
||||||
#define UN_SAISNULL(sa) (((struct sockaddr_un *)sa)->sun_family == AF_UNIX)? (((struct sockaddr_un *)sa)->sun_path[0] == 0 && ((struct sockaddr_un *)sa)->sun_path[1] == 0) :
|
#define UN_SAISNULL(sa) (((struct sockaddr_un *)sa)->sun_family == AF_UNIX)? (((struct sockaddr_un *)sa)->sun_path[0] == 0 && ((struct sockaddr_un *)sa)->sun_path[1] == 0) :
|
||||||
#else
|
#else
|
||||||
#define UN_SAPORT(sa)
|
#define UN_SAPORT(sa)
|
||||||
@ -527,6 +530,8 @@ struct srvparam {
|
|||||||
AUTHFUNC authfunc;
|
AUTHFUNC authfunc;
|
||||||
PROXYFUNC pf;
|
PROXYFUNC pf;
|
||||||
SOCKET srvsock, cbsock;
|
SOCKET srvsock, cbsock;
|
||||||
|
/* the file of a Unix socket bound to a path, to remove only it */
|
||||||
|
uint64_t undev, unino;
|
||||||
int childcount;
|
int childcount;
|
||||||
int maxchild;
|
int maxchild;
|
||||||
int backlog;
|
int backlog;
|
||||||
|
|||||||
@ -121,6 +121,11 @@ int udpbind(struct clientparam *param)
|
|||||||
fcntl(s, F_SETFL, O_NONBLOCK | fcntl(s, F_GETFL));
|
fcntl(s, F_SETFL, O_NONBLOCK | fcntl(s, F_GETFL));
|
||||||
#endif
|
#endif
|
||||||
param->remsock = s;
|
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,
|
if (param->srv->so._bind(param->sostate, param->remsock,
|
||||||
(struct sockaddr *)¶m->sinsl, SASIZE(¶m->sinsl))) {
|
(struct sockaddr *)¶m->sinsl, SASIZE(¶m->sinsl))) {
|
||||||
*SAPORT(¶m->sinsl) = 0;
|
*SAPORT(¶m->sinsl) = 0;
|
||||||
@ -131,7 +136,7 @@ int udpbind(struct clientparam *param)
|
|||||||
return 12;
|
return 12;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sasize = SASIZE(¶m->sinsl);
|
sasize = sizeof(param->sinsl);
|
||||||
param->srv->so._getsockname(param->sostate, param->remsock,
|
param->srv->so._getsockname(param->sostate, param->remsock,
|
||||||
(struct sockaddr *)¶m->sinsl, &sasize);
|
(struct sockaddr *)¶m->sinsl, &sasize);
|
||||||
return 0;
|
return 0;
|
||||||
@ -284,6 +289,12 @@ int udpsockmap(struct clientparam *param, int timeo)
|
|||||||
}
|
}
|
||||||
default: return 997;
|
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);
|
memcpy(SAPORT(&dst), base + i, 2);
|
||||||
i += 2;
|
i += 2;
|
||||||
|
|
||||||
|
|||||||
@ -1,14 +1,14 @@
|
|||||||
#ifndef VERSION
|
#ifndef VERSION
|
||||||
#define VERSION "3proxy-0.9.9"
|
#define VERSION "3proxy-0.9.9.2"
|
||||||
#endif
|
#endif
|
||||||
#ifndef BUILDDATE
|
#ifndef BUILDDATE
|
||||||
#define BUILDDATE ""
|
#define BUILDDATE "261024120357"
|
||||||
#endif
|
#endif
|
||||||
#define MAJOR3PROXY 0
|
#define MAJOR3PROXY 0
|
||||||
#define SUBMAJOR3PROXY 9
|
#define SUBMAJOR3PROXY 9
|
||||||
#define MINOR3PROXY 9
|
#define MINOR3PROXY 9
|
||||||
#define SUBMINOR3PROXY 0
|
#define SUBMINOR3PROXY 2
|
||||||
#define RELEASE3PROXY "3proxy-0.9.9(" BUILDDATE ")\0"
|
#define RELEASE3PROXY "3proxy-0.9.9.2(" BUILDDATE ")\0"
|
||||||
#ifndef YEAR3PROXY
|
#ifndef YEAR3PROXY
|
||||||
#define YEAR3PROXY "2026"
|
#define YEAR3PROXY "2026"
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user