Compare commits

..

No commits in common. "a11427afe93de57573e1546c6d91f56221c196fc" and "754ba7115a48bf0681afa8e46da16ef9cbe56917" have entirely different histories.

4 changed files with 0 additions and 724 deletions

View File

@ -1,139 +0,0 @@
name: OpenWrt ipk build
on:
release:
types: [published]
workflow_dispatch:
permissions:
contents: read
env:
OPENWRT_RELEASE: 24.10.0
jobs:
ipk:
permissions:
contents: write
id-token: write
attestations: write
name: "${{ matrix.arch }}"
strategy:
fail-fast: false
matrix:
include:
- target: ramips/mt7621
arch: mipsel_24kc
- target: ath79/generic
arch: mips_24kc
- target: ipq40xx/generic
arch: arm_cortex-a7_neon-vfpv4
- target: mediatek/filogic
arch: aarch64_cortex-a53
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- name: env
run: echo "RELEASE=$(tr -d ' \t\r\n' < RELEASE)" >> $GITHUB_ENV
- name: Install build dependencies
run: |
sudo apt-get update
sudo apt-get install -y build-essential libncurses-dev zlib1g-dev gawk git \
gettext libssl-dev xsltproc wget unzip python3 rsync file zstd
- name: Fetch SDK
run: |
BASE="https://downloads.openwrt.org/releases/$OPENWRT_RELEASE/targets/${{ matrix.target }}"
# The SDK file name carries the toolchain flavour, which differs between
# targets (musl vs musl_eabi), so take it from the directory listing.
NAME=$(curl -fsSL "$BASE/" | grep -oE 'openwrt-sdk-[^"]*\.tar\.zst' | head -1)
if [ -z "$NAME" ]; then echo "no SDK for ${{ matrix.target }}"; exit 1; fi
echo "fetching $NAME"
curl -fsSL "$BASE/$NAME" -o sdk.tar.zst
tar --zstd -xf sdk.tar.zst
mv "${NAME%.tar.zst}" sdk
rm sdk.tar.zst
- name: Stage the package
run: |
mkdir -p sdk/package/3proxy sdk/dl
cp -a scripts/openwrt/. sdk/package/3proxy/
# Build the checkout rather than a published tarball, so the workflow
# does not depend on the release archive existing yet.
git archive --format=tar.gz --prefix="3proxy-$RELEASE/" -o "sdk/dl/3proxy-$RELEASE.tar.gz" HEAD
HASH=$(sha256sum "sdk/dl/3proxy-$RELEASE.tar.gz" | cut -d' ' -f1)
sed -i "s|^PKG_VERSION:=.*|PKG_VERSION:=$RELEASE|" sdk/package/3proxy/Makefile
sed -i "s|^PKG_HASH:=.*|PKG_HASH:=$HASH|" sdk/package/3proxy/Makefile
- name: Build
run: |
cd sdk
./scripts/feeds update base packages
./scripts/feeds install libopenssl libpcre2
echo CONFIG_PACKAGE_3proxy=m >> .config
make defconfig
make package/3proxy/compile -j$(nproc)
- name: Collect
run: |
find sdk/bin -name '3proxy_*.ipk' -exec cp {} . \;
ls -l *.ipk
for f in *.ipk; do echo "$f"; done
- name: Get artifact ipk
uses: actions/upload-artifact@v7
with:
name: "3proxy-${{ env.RELEASE }}-${{ matrix.arch }}.ipk"
path: "*.ipk"
- name: Import signing key
if: github.event_name == 'release'
env:
GPG_PRIVATE_KEY: ${{ secrets.GPG_PRIVATE_KEY }}
GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }}
run: |
if [ -z "$GPG_PRIVATE_KEY" ]; then echo "GPG_PRIVATE_KEY is not set"; exit 1; fi
mkdir -p ~/.gnupg && chmod 700 ~/.gnupg
printf 'allow-loopback-pinentry\ndefault-cache-ttl 7200\nmax-cache-ttl 7200\n' > ~/.gnupg/gpg-agent.conf
gpgconf --kill gpg-agent || true
printf '%s' "$GPG_PRIVATE_KEY" | gpg --batch --import
KEYID=$(gpg --list-secret-keys --with-colons | awk -F: '/^sec:/{print $5; exit}')
echo "GPG_KEYID=$KEYID" >> $GITHUB_ENV
echo prime > /tmp/prime.txt
gpg --batch --yes --pinentry-mode loopback --passphrase "$GPG_PASSPHRASE" \
-u "$KEYID" --detach-sign -o /dev/null /tmp/prime.txt
rm -f /tmp/prime.txt
- name: Checksums and detached signatures
if: github.event_name == 'release'
env:
GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }}
run: |
# opkg verifies the signature of a feed index, never of a package file,
# so the checksums and their signature are what a manual install can be
# checked against.
sha256sum *.ipk > SHA256SUMS-openwrt-${{ matrix.arch }}
for f in *.ipk SHA256SUMS-openwrt-${{ matrix.arch }}; do
gpg --batch --yes --pinentry-mode loopback --passphrase "$GPG_PASSPHRASE" \
-u "$GPG_KEYID" --armor --detach-sign "$f"
done
sha256sum -c SHA256SUMS-openwrt-${{ matrix.arch }}
gpg --verify SHA256SUMS-openwrt-${{ matrix.arch }}.asc SHA256SUMS-openwrt-${{ matrix.arch }}
- name: Attest build provenance
if: github.event_name == 'release'
uses: actions/attest-build-provenance@v2
with:
subject-path: |
*.ipk
- name: Upload to release
if: github.event_name == 'release'
env:
GH_TOKEN: ${{ github.token }}
TAG: ${{ github.event.release.tag_name }}
run: |
gh release upload "$TAG" *.ipk *.ipk.asc \
SHA256SUMS-openwrt-${{ matrix.arch }} SHA256SUMS-openwrt-${{ matrix.arch }}.asc

View File

@ -1,66 +0,0 @@
#
# 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))

View File

@ -1,59 +0,0 @@
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'

View File

@ -1,460 +0,0 @@
#!/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
}