Compare commits

...

4 Commits

Author SHA1 Message Date
Vladimir Dubrovin
757ad916ec Sign docker images
Some checks failed
C/C++ CI Linux / ${{ matrix.target }} (ubuntu-24.04-arm) (push) Has been cancelled
C/C++ CI Linux / ${{ matrix.target }} (ubuntu-latest) (push) Has been cancelled
C/C++ CI MacOS / ${{ matrix.target }} (macos-15) (push) Has been cancelled
C/C++ CI Windows / ${{ matrix.target }} (windows-2022) (push) Has been cancelled
C/C++ CI cmake / ${{ matrix.target }} (macos-15) (push) Has been cancelled
C/C++ CI cmake / ${{ matrix.target }} (ubuntu-24.04-arm) (push) Has been cancelled
C/C++ CI cmake / ${{ matrix.target }} (ubuntu-latest) (push) Has been cancelled
C/C++ CI cmake / ${{ matrix.target }} (windows-2022) (push) Has been cancelled
2026-06-02 18:12:48 +03:00
Vladimir Dubrovin
fbc3ed5a18 Update README.md 2026-06-02 16:36:38 +03:00
Vladimir Dubrovin
69862b67cb Check bandlims for UDP traffic 2026-06-02 14:23:52 +03:00
Vladimir Dubrovin
fd7b25bf06 Use non-blocking sockets for UDP 2026-06-02 13:43:56 +03:00
8 changed files with 89 additions and 26 deletions

View File

@ -8,6 +8,7 @@ on:
permissions: permissions:
contents: read contents: read
packages: write packages: write
id-token: write
env: env:
REGISTRY: ghcr.io REGISTRY: ghcr.io
@ -46,6 +47,9 @@ jobs:
- name: Set up Docker Buildx - name: Set up Docker Buildx
uses: docker/setup-buildx-action@v4 uses: docker/setup-buildx-action@v4
- name: Install cosign
uses: sigstore/cosign-installer@v3
- name: Login to GHCR - name: Login to GHCR
if: github.event_name != 'pull_request' if: github.event_name != 'pull_request'
uses: docker/login-action@v4 uses: docker/login-action@v4
@ -81,3 +85,15 @@ jobs:
push: ${{ github.event_name != 'pull_request' }} push: ${{ github.event_name != 'pull_request' }}
tags: ${{ steps.tags.outputs.full }} 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

View File

@ -7,6 +7,7 @@ on:
permissions: permissions:
contents: read contents: read
id-token: write
env: env:
REGISTRY: docker.io REGISTRY: docker.io
@ -44,6 +45,9 @@ jobs:
- name: Set up Docker Buildx - name: Set up Docker Buildx
uses: docker/setup-buildx-action@v4 uses: docker/setup-buildx-action@v4
- name: Install cosign
uses: sigstore/cosign-installer@v3
- name: Login to Docker Hub - name: Login to Docker Hub
if: github.event_name != 'pull_request' if: github.event_name != 'pull_request'
uses: docker/login-action@v4 uses: docker/login-action@v4
@ -77,3 +81,15 @@ jobs:
platforms: linux/amd64,linux/arm64,linux/arm/v7,ppc64le platforms: linux/amd64,linux/arm64,linux/arm/v7,ppc64le
push: ${{ github.event_name != 'pull_request' }} push: ${{ github.event_name != 'pull_request' }}
tags: ${{ steps.tags.outputs.full }} 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

View File

@ -33,26 +33,38 @@ Documentation (man pages and HTML) available with download, on https://3proxy.or
### Default image (`:latest`): ### Default image (`:latest`):
Full installation requires to mount /etc/3proxy directory with 3proxy.cfg files. Full installation requires to mount /etc/3proxy/3proxy.cfg files.
to run: For docker, config can be provided via `docker config`
``` ```
echo " echo "log
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
``` ```
`podman` does not support `config` as above.
Mounts may be used as config alternative. `podman` used in example below can be replaced with `docker`:
```
echo "log
nserver 8.8.8.8
nscache 65536
proxy -p3129" >/path/to/local/config/directory/3proxy.cfg
podman run --read-only -p 3129:3129 -v /path/to/local/config/directory/3proxy.cfg:/etc/3proxy/3proxy.cfg --name 3proxy.full 3proxy.full
```
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 :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 (`:busybox`):
Full with busybox added, to allow shell commands 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 `:minimal` image:

View File

@ -147,9 +147,9 @@ void * dnsprchild(struct clientparam* param) {
} }
else { else {
#ifdef _WIN32 #ifdef _WIN32
/* ioctlsocket(param->remsock, FIONBIO, &ul); */ ioctlsocket(param->remsock, FIONBIO, &ul);
#else #else
/* fcntl(param->remsock,F_SETFL,O_NONBLOCK); */ fcntl(param->remsock, F_SETFL, O_NONBLOCK | fcntl(param->remsock, F_GETFL));
#endif #endif
} }

View File

@ -1020,6 +1020,7 @@ int MODULEMAINFUNC (int argc, char** argv){
if(hashresolv(&udp_table, &defparam, &toparam, NULL)) { if(hashresolv(&udp_table, &defparam, &toparam, NULL)) {
int i, len=0; int i, len=0;
if(!toparam->bandlimfunc || !(*toparam->bandlimfunc)(toparam, 0, srv.udplen)){
if(toparam->udp_nhops){ if(toparam->udp_nhops){
for(i=1; i < toparam->udp_nhops; i++){ for(i=1; i < toparam->udp_nhops; i++){
len+=socks5_udp_build_hdr(srv.udpbuf2+len, &toparam->udp_relay[i-1]); len+=socks5_udp_build_hdr(srv.udpbuf2+len, &toparam->udp_relay[i-1]);
@ -1031,6 +1032,7 @@ int MODULEMAINFUNC (int argc, char** argv){
srv.so._sendto(toparam->sostate, toparam->remsock, (char *)srv.udpbuf2, len, 0, (struct sockaddr *)&toparam->sinsr, SASIZE(&toparam->sinsr)); srv.so._sendto(toparam->sostate, toparam->remsock, (char *)srv.udpbuf2, len, 0, (struct sockaddr *)&toparam->sinsr, SASIZE(&toparam->sinsr));
toparam->statscli64 += srv.udplen; toparam->statscli64 += srv.udplen;
toparam->nwrites++; toparam->nwrites++;
}
_3proxy_sem_unlock(udpinit); _3proxy_sem_unlock(udpinit);
continue; continue;
} }

View File

@ -255,6 +255,11 @@ void * sockschild(struct clientparam* param) {
if(switch_ns(param->srv, param->srv->o_nsfd)) {RETURN(11);} if(switch_ns(param->srv, param->srv->o_nsfd)) {RETURN(11);}
#endif #endif
if ((param->remsock=param->srv->so._socket(param->sostate, SASOCK(&param->req), SOCK_DGRAM, IPPROTO_UDP)) == INVALID_SOCKET) {RETURN (11);} if ((param->remsock=param->srv->so._socket(param->sostate, SASOCK(&param->req), SOCK_DGRAM, IPPROTO_UDP)) == INVALID_SOCKET) {RETURN (11);}
#ifdef _WIN32
{ unsigned long ul = 1; ioctlsocket(param->remsock, FIONBIO, &ul); }
#else
fcntl(param->remsock, F_SETFL, O_NONBLOCK | fcntl(param->remsock, F_GETFL));
#endif
} }
if(command > 1) { if(command > 1) {
@ -275,6 +280,11 @@ fflush(stderr);
#endif #endif
param->clisock = param->srv->so._socket(param->sostate, SASOCK(&param->sincr), SOCK_DGRAM, IPPROTO_UDP); param->clisock = param->srv->so._socket(param->sostate, SASOCK(&param->sincr), SOCK_DGRAM, IPPROTO_UDP);
if(param->clisock == INVALID_SOCKET) {RETURN(11);} if(param->clisock == INVALID_SOCKET) {RETURN(11);}
#ifdef _WIN32
{ unsigned long ul = 1; ioctlsocket(param->clisock, FIONBIO, &ul); }
#else
fcntl(param->clisock, F_SETFL, O_NONBLOCK | fcntl(param->clisock, F_GETFL));
#endif
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);}

View File

@ -61,6 +61,7 @@ void * udppmchild(struct clientparam* param) {
if(!(param->srvbuf = malloc(UDPBUFSIZE)))RETURN(11); if(!(param->srvbuf = malloc(UDPBUFSIZE)))RETURN(11);
param->srvbufsize = UDPBUFSIZE; param->srvbufsize = UDPBUFSIZE;
} }
if(!param->bandlimfunc || !(*param->bandlimfunc)(param, 0, param->srv->udplen)){
if(param->udp_nhops){ if(param->udp_nhops){
for(i=1; i < param->udp_nhops; i++){ for(i=1; i < param->udp_nhops; i++){
len+=socks5_udp_build_hdr(param->srvbuf+len, &param->udp_relay[i-1]); len+=socks5_udp_build_hdr(param->srvbuf+len, &param->udp_relay[i-1]);
@ -70,10 +71,11 @@ void * udppmchild(struct clientparam* param) {
memcpy(param->srvbuf+len, param->srv->udpbuf, param->srv->udplen > UDPBUFSIZE - len?UDPBUFSIZE - len : param->srv->udplen); memcpy(param->srvbuf+len, param->srv->udpbuf, param->srv->udplen > UDPBUFSIZE - len?UDPBUFSIZE - len : param->srv->udplen);
len += param->srv->udplen > UDPBUFSIZE - len?UDPBUFSIZE - len : param->srv->udplen; len += param->srv->udplen > UDPBUFSIZE - len?UDPBUFSIZE - len : param->srv->udplen;
param->srv->so._sendto(param->sostate, param->remsock, (char *)param->srvbuf, len, 0, (struct sockaddr *)&param->sinsr, SASIZE(&param->sinsr)); param->srv->so._sendto(param->sostate, param->remsock, (char *)param->srvbuf, len, 0, (struct sockaddr *)&param->sinsr, SASIZE(&param->sinsr));
_3proxy_sem_unlock(udpinit);
param->statscli64 += param->srvinbuf; param->statscli64 += param->srvinbuf;
param->srvinbuf = 0;
param->nwrites++; param->nwrites++;
}
_3proxy_sem_unlock(udpinit);
param->srvinbuf = 0;
param->clisock = param->srv->srvsock; param->clisock = param->srv->srvsock;
param->waitserver64 = 0x7fffffffffffffff; param->waitserver64 = 0x7fffffffffffffff;
param->res = udpsockmap(param, conf.timeouts[STRING_L]); param->res = udpsockmap(param, conf.timeouts[STRING_L]);

View File

@ -106,6 +106,7 @@ int udpsockmap(struct clientparam *param, int timeo)
len = param->srv->so._recvfrom(param->sostate, param->clisock, len = param->srv->so._recvfrom(param->sostate, param->clisock,
(char *)param->srvbuf + recvoff, UDPBUFSIZE - recvoff, (char *)param->srvbuf + recvoff, UDPBUFSIZE - recvoff,
0, (struct sockaddr *)&sin, &sasize); 0, (struct sockaddr *)&sin, &sasize);
if (len < 0 && (errno == EAGAIN || errno == EINTR)) continue;
if (len <= 0) return 482; if (len <= 0) return 482;
if (SAADDRLEN(&sin) != SAADDRLEN(&param->sincr) || if (SAADDRLEN(&sin) != SAADDRLEN(&param->sincr) ||
@ -123,6 +124,8 @@ int udpsockmap(struct clientparam *param, int timeo)
continue; continue;
} }
if(param->bandlimfunc && (*param->bandlimfunc)(param, 0, len)) continue;
if (nhops == 0) { if (nhops == 0) {
int i; int i;
if (len < 10 || param->srvbuf[0] || param->srvbuf[1] || param->srvbuf[2]) if (len < 10 || param->srvbuf[0] || param->srvbuf[1] || param->srvbuf[2])
@ -182,6 +185,7 @@ int udpsockmap(struct clientparam *param, int timeo)
len = param->srv->so._recvfrom(param->sostate, param->remsock, len = param->srv->so._recvfrom(param->sostate, param->remsock,
(char *)param->srvbuf + hdrsize, UDPBUFSIZE - hdrsize, 0, (char *)param->srvbuf + hdrsize, UDPBUFSIZE - hdrsize, 0,
(struct sockaddr *)&from, &sasize); (struct sockaddr *)&from, &sasize);
if (len < 0 && (errno == EAGAIN || errno == EINTR)) continue;
if (len <= 0) return 486; if (len <= 0) return 486;
if (nhops >= 1) { if (nhops >= 1) {
if (!SAISNULL(&param->sinsr) && *SAPORT(&param->sinsr)) { if (!SAISNULL(&param->sinsr) && *SAPORT(&param->sinsr)) {
@ -193,6 +197,7 @@ int udpsockmap(struct clientparam *param, int timeo)
} }
param->statssrv64 += len; param->statssrv64 += len;
param->nreads++; param->nreads++;
if(param->bandlimfunc && (*param->bandlimfunc)(param, len, 0)) continue;
sendlen = len; sendlen = len;
if (nhops == 0) { if (nhops == 0) {
param->srvbuf[0] = param->srvbuf[1] = param->srvbuf[2] = 0; param->srvbuf[0] = param->srvbuf[1] = param->srvbuf[2] = 0;