1
0
mirror of https://github.com/SoftEtherVPN/SoftEtherVPN.git synced 2025-04-03 18:00:08 +03:00

Compare commits

...

4 Commits

Author SHA1 Message Date
Alexey Kryuchkov
c8d2fff2dc
Merge a366bdbf02 into f525b4d660 2025-02-12 23:49:12 +00:00
Ilya Shipitsin
f525b4d660
Merge pull request #2101 from chipitsine/master
CI: move docker build machinery to the main repo
2025-02-10 19:59:22 +01:00
Ilia Shipitsin
a081fdd5c8 CI: move docker build machinery to the main repo
more details: https://github.com/SoftEtherVPN/SoftetherVPN-docker/issues/4
2025-02-09 23:32:26 +01:00
Alexey Kryuchkov
a366bdbf02 Add server option 'JsonRpcWebApiAllowedSubnet' to restrict access to JSON-RPC API based on client IP address 2023-06-02 00:00:43 +03:00
14 changed files with 315 additions and 4 deletions

59
.github/workflows/docker-vpnbridge.yml vendored Normal file
View File

@ -0,0 +1,59 @@
name: docker-vpnbridge
on:
push:
branches:
- 'master'
tags:
- '*'
pull_request:
workflow_dispatch:
jobs:
docker-vpnbridge:
strategy:
matrix:
variant: [
{ name: amd64, platform: "linux/amd64", repo: "softethervpn/vpnbridge" },
{ name: arm64, platform: "linux/arm64", repo: "softethervpn/vpnbridge-arm64" }
]
name: vpnbridge/${{ matrix.variant.name }}
runs-on: ubuntu-latest
if: ${{ github.repository_owner == 'SoftEtherVPN' }}
steps:
-
name: Docker meta
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ matrix.variant.repo }}
tags: |
type=raw,value=latest,enable={{is_default_branch}}
type=ref,event=pr
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
-
name: Set up QEMU
uses: docker/setup-qemu-action@v3
with:
image: tonistiigi/binfmt:qemu-v9.2.0
-
name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
-
name: Login to DockerHub
if: github.event_name != 'pull_request'
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
-
name: Build and push
uses: docker/build-push-action@v6
with:
file: ./Dockerfile
target: vpnbridge
platforms: ${{ matrix.variant.platform }}
push: ${{ github.event_name != 'pull_request' }}
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}

59
.github/workflows/docker-vpnclient.yml vendored Normal file
View File

@ -0,0 +1,59 @@
name: docker-vpnclient
on:
push:
branches:
- 'master'
tags:
- '*'
pull_request:
workflow_dispatch:
jobs:
docker-vpnclient:
strategy:
matrix:
variant: [
{ name: amd64, platform: "linux/amd64", repo: "softethervpn/vpnclient" },
{ name: arm64, platform: "linux/arm64", repo: "softethervpn/vpnclient-arm64" }
]
name: vpnclient/${{ matrix.variant.name }}
runs-on: ubuntu-latest
if: ${{ github.repository_owner == 'SoftEtherVPN' }}
steps:
-
name: Docker meta
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ matrix.variant.repo }}
tags: |
type=raw,value=latest,enable={{is_default_branch}}
type=ref,event=pr
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
-
name: Set up QEMU
uses: docker/setup-qemu-action@v3
with:
image: tonistiigi/binfmt:qemu-v9.2.0
-
name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
-
name: Login to DockerHub
if: ${{ github.event_name != 'pull_request' }}
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
-
name: Build and push
uses: docker/build-push-action@v6
with:
file: ./Dockerfile
target: vpnclient
platforms: ${{ matrix.variant.platform }}
push: ${{ github.event_name != 'pull_request' }}
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}

59
.github/workflows/docker-vpnserver.yml vendored Normal file
View File

@ -0,0 +1,59 @@
name: docker-vpnserver
on:
push:
branches:
- 'master'
tags:
- '*'
pull_request:
workflow_dispatch:
jobs:
docker:
strategy:
matrix:
variant: [
{ name: amd64, platform: "linux/amd64", repo: "softethervpn/vpnserver" },
{ name: arm64, platform: "linux/arm64", repo: "softethervpn/vpnserver-arm64" }
]
name: vpnserver/${{ matrix.variant.name }}
runs-on: ubuntu-latest
if: ${{ github.repository_owner == 'SoftEtherVPN' }}
steps:
-
name: Docker meta
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ matrix.variant.repo }}
tags: |
type=raw,value=latest,enable={{is_default_branch}}
type=ref,event=pr
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
-
name: Set up QEMU
uses: docker/setup-qemu-action@v3
with:
image: tonistiigi/binfmt:qemu-v9.2.0
-
name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
-
name: Login to DockerHub
if: ${{ github.event_name != 'pull_request' }}
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
-
name: Build and push
uses: docker/build-push-action@v6
with:
file: ./Dockerfile
target: vpnserver
push: ${{ github.event_name != 'pull_request' }}
platforms: ${{ matrix.variant.platform }}
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}

51
Dockerfile Normal file
View File

@ -0,0 +1,51 @@
FROM alpine AS builder
RUN mkdir /usr/local/src && apk add binutils --no-cache\
linux-headers \
build-base \
readline-dev \
openssl-dev \
ncurses-dev \
git \
cmake \
zlib-dev \
libsodium-dev \
gnu-libiconv
ENV LD_PRELOAD=/usr/lib/preloadable_libiconv.so
ADD ./ /usr/local/src/SoftEtherVPN/
WORKDIR /usr/local/src
ENV USE_MUSL=YES
ENV CMAKE_FLAGS="-DSE_PIDDIR=/run/softether -DSE_LOGDIR=/var/log/softether -DSE_DBDIR=/var/lib/softether"
RUN cd SoftEtherVPN &&\
./configure &&\
make -j $(getconf _NPROCESSORS_ONLN) -C build
FROM alpine AS base
RUN apk add --no-cache readline \
openssl \
libsodium \
gnu-libiconv \
iptables
ENV LD_PRELOAD=/usr/lib/preloadable_libiconv.so
WORKDIR /usr/local/bin
VOLUME /var/log/softether
VOLUME /var/lib/softether
VOLUME /run/softether
COPY --from=builder /usr/local/src/SoftEtherVPN/build/vpncmd /usr/local/src/SoftEtherVPN/build/hamcore.se2 ./
COPY --from=builder /usr/local/src/SoftEtherVPN/build/libcedar.so /usr/local/src/SoftEtherVPN/build/libmayaqua.so /usr/local/lib/
FROM base AS vpnserver
COPY --from=builder /usr/local/src/SoftEtherVPN/build/vpnserver ./
EXPOSE 443/tcp 992/tcp 1194/tcp 1194/udp 5555/tcp 500/udp 4500/udp
CMD ["/usr/local/bin/vpnserver", "execsvc"]
FROM base AS vpnclient
COPY --from=builder /usr/local/src/SoftEtherVPN/build/vpnclient ./
CMD ["/usr/local/bin/vpnclient", "execsvc"]
FROM base AS vpnbridge
COPY --from=builder /usr/local/src/SoftEtherVPN/build/vpnbridge ./
CMD ["/usr/local/bin/vpnbridge", "execsvc"]

View File

@ -30,6 +30,7 @@
<ul>
<li>Older versions of SoftEther VPN before June 2019 don't support JSON-RPC APIs.</li>
<li>If you want to completely disable the JSON-RPC on your VPN Server, set the <code>DisableJsonRpcWebApi</code> variable to <code>true</code> on the <code>vpn_server.config</code>.</li>
<li>You may also restrict access to JSON-RPC API to a specific subnet, e.g. your internal network, by setting the <code>JsonRpcWebApiAllowedSubnet</code> variable to, for example, <code>192.168.0.0/16</code>.</li>
</ul>
<h3 id="json-rpc-specification">JSON-RPC specification</h3>
<p>You must use HTTPS 1.1 <code>POST</code> method to call each of JSON-RPC APIs.<br />

View File

@ -25,6 +25,7 @@ https://<vpn_server_hostname>:<port>/api/
- Older versions of SoftEther VPN before June 2019 don't support JSON-RPC APIs.
- If you want to completely disable the JSON-RPC on your VPN Server, set the `DisableJsonRpcWebApi` variable to `true` on the `vpn_server.config`.
- You may also restrict access to JSON-RPC API to a specific subnet, e.g. your internal network, by setting the `JsonRpcWebApiAllowedSubnet` variable to, for example, `192.168.0.0/16`.
### JSON-RPC specification

View File

@ -25,6 +25,7 @@ https://<vpn_server_hostname>:<port>/api/
- Older versions of SoftEther VPN before June 2019 don't support JSON-RPC APIs.
- If you want to completely disable the JSON-RPC on your VPN Server, set the `DisableJsonRpcWebApi` variable to `true` on the `vpn_server.config`.
- You may also restrict access to JSON-RPC API to a specific subnet, e.g. your internal network, by setting the `JsonRpcWebApiAllowedSubnet` variable to, for example, `192.168.0.0/16`.
### JSON-RPC specification

View File

@ -0,0 +1,16 @@
version: '3'
services:
softether:
image: softethervpn/vpnclient:latest
devices:
- /dev/net/tun:/dev/net/tun
cap_add:
- NET_ADMIN
restart: always
volumes:
- "/etc/localtime:/etc/localtime:ro"
- "/etc/timezone:/etc/timezone:ro"
- "./softether_data:/var/lib/softether"
- "./softether_log:/var/log/softether"
# - "./adminip.txt:/var/lib/softether/adminip.txt:ro"

23
docker-compose.yaml Normal file
View File

@ -0,0 +1,23 @@
version: '3'
services:
softether:
image: softethervpn/vpnserver:latest
cap_add:
- NET_ADMIN
restart: always
ports:
#- 53:53 #DNS tunneling
- 443:443 #Management and HTTPS tunneling
- 992:992 #HTTPS tunneling
#- 1194:1194/udp #OpenVPN
#- 5555:5555 #HTTPS tunneling
#- 500:500/udp #IPsec/L2TP
#- 4500:4500/udp #IPsec/L2TP
#- 1701:1701/udp #IPsec/L2TP
volumes:
- "/etc/localtime:/etc/localtime:ro"
- "/etc/timezone:/etc/timezone:ro"
- "./softether_data:/var/lib/softether"
- "./softether_log:/var/log/softether"
# - "./adminip.txt:/var/lib/softether/adminip.txt:ro"

View File

@ -5740,6 +5740,7 @@ bool ServerDownloadSignature(CONNECTION *c, char **error_detail_str)
UINT num = 0, max = 19;
SERVER *server;
char *vpn_http_target = HTTP_VPN_TARGET2;
bool disableJsonRpcWebApi;
// Validate arguments
if (c == NULL)
{
@ -5750,6 +5751,15 @@ bool ServerDownloadSignature(CONNECTION *c, char **error_detail_str)
s = c->FirstSock;
disableJsonRpcWebApi = server->DisableJsonRpcWebApi;
if (!disableJsonRpcWebApi && !IsZeroIP(&server->JsonRpcWebApiAllowedSubnetAddr)
&& !IsZeroIP(&server->JsonRpcWebApiAllowedSubnetMask)) {
// restrict JSON-RPC Web API to specified subnet only
if (!IsInSameNetwork(&s->RemoteIP, &server->JsonRpcWebApiAllowedSubnetAddr, &server->JsonRpcWebApiAllowedSubnetMask)) {
disableJsonRpcWebApi = true;
}
}
while (true)
{
bool not_found_error = false;
@ -5782,7 +5792,7 @@ bool ServerDownloadSignature(CONNECTION *c, char **error_detail_str)
// Receive the data since it's POST
data_size = GetContentLength(h);
if (server->DisableJsonRpcWebApi == false)
if (disableJsonRpcWebApi == false)
{
if (StrCmpi(h->Target, "/api") == 0 || StrCmpi(h->Target, "/api/") == 0)
{
@ -5868,7 +5878,7 @@ bool ServerDownloadSignature(CONNECTION *c, char **error_detail_str)
}
else if (StrCmpi(h->Method, "OPTIONS") == 0)
{
if (server->DisableJsonRpcWebApi == false)
if (disableJsonRpcWebApi == false)
{
if (StrCmpi(h->Target, "/api") == 0 || StrCmpi(h->Target, "/api/") == 0 || StartWith(h->Target, "/admin"))
{
@ -5939,7 +5949,7 @@ bool ServerDownloadSignature(CONNECTION *c, char **error_detail_str)
BUF *b = NULL;
*error_detail_str = "HTTP_ROOT";
if (server->DisableJsonRpcWebApi == false)
if (disableJsonRpcWebApi == false)
{
b = ReadDump("|wwwroot/index.html");
}
@ -6019,7 +6029,7 @@ bool ServerDownloadSignature(CONNECTION *c, char **error_detail_str)
if (b == false)
{
if (server->DisableJsonRpcWebApi == false)
if (disableJsonRpcWebApi == false)
{
if (StartWith(h->Target, "/api?") || StartWith(h->Target, "/api/") || StrCmpi(h->Target, "/api") == 0)
{

View File

@ -30,6 +30,7 @@
#include "Mayaqua/Internat.h"
#include "Mayaqua/Memory.h"
#include "Mayaqua/Microsoft.h"
#include "Mayaqua/Network.h"
#include "Mayaqua/Object.h"
#include "Mayaqua/OS.h"
#include "Mayaqua/Pack.h"
@ -6032,6 +6033,15 @@ void SiLoadServerCfg(SERVER *s, FOLDER *f)
// Disable JSON-RPC Web API
s->DisableJsonRpcWebApi = CfgGetBool(f, "DisableJsonRpcWebApi");
char tmpaddr[MAX_PATH];
if (CfgGetStr(f, "JsonRpcWebApiAllowedSubnet", tmpaddr, sizeof(tmpaddr))) {
IP _subnet, _mask;
if (ParseIpAndMask46(tmpaddr, &_subnet, &_mask)) {
s->JsonRpcWebApiAllowedSubnetAddr = _subnet;
s->JsonRpcWebApiAllowedSubnetMask = _mask;
}
}
// Bits of Diffie-Hellman parameters
c->DhParamBits = CfgGetInt(f, "DhParamBits");
if (c->DhParamBits == 0)
@ -6365,6 +6375,11 @@ void SiWriteServerCfg(FOLDER *f, SERVER *s)
// Disable JSON-RPC Web API
CfgAddBool(f, "DisableJsonRpcWebApi", s->DisableJsonRpcWebApi);
char tmpaddr[MAX_PATH];
IPAndMaskToStr(tmpaddr, sizeof(tmpaddr),
&s->JsonRpcWebApiAllowedSubnetAddr, &s->JsonRpcWebApiAllowedSubnetMask);
CfgAddStr(f, "JsonRpcWebApiAllowedSubnet", tmpaddr);
}
Unlock(c->lock);
}

View File

@ -276,6 +276,9 @@ struct SERVER
IP ListenIP; // Listen IP
bool StrictSyslogDatetimeFormat; // Make syslog datetime format strict RFC3164
bool DisableJsonRpcWebApi; // Disable JSON-RPC Web API
IP JsonRpcWebApiAllowedSubnetAddr; // If set, allow access to JSON-RPC Web API from
IP JsonRpcWebApiAllowedSubnetMask; // this subnet only
};

View File

@ -6993,6 +6993,18 @@ void IPToStr6Inner(char *str, IP *ip)
}
}
// Format IP and subnet mask as "<ip>/<masksize>"
void IPAndMaskToStr(char *str, UINT size, IP *ip, IP *subnet)
{
int iplen;
UINT masksize;
IPToStr(str, size, ip);
iplen = StrLen(str);
masksize = SubnetMaskToInt(subnet);
Format(str + iplen, size - iplen, "/%d", masksize);
}
// Convert the string to an IP address
bool StrToIP6(IP *ip, char *str)
{

View File

@ -1293,6 +1293,7 @@ void IPToStr6(char *str, UINT size, IP *ip);
void IP6AddrToStr(char *str, UINT size, IPV6_ADDR *addr);
void IPToStr6Array(char *str, UINT size, UCHAR *bytes);
void IPToStr6Inner(char *str, IP *ip);
void IPAndMaskToStr(char *str, UINT size, IP *ip, IP *subnet);
void IntToSubnetMask6(IP *ip, UINT i);
void IPAnd6(IP *dst, IP *a, IP *b);
void GetAllRouterMulticastAddress6(IP *ip);