Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Making a network gateway with a transparent proxy in v2ray docker image #56

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/docker-push.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,14 @@ on:
push:
paths:
- "v2ray.sh"
- "entrypoint.sh"
- "Dockerfile"
- ".github/workflows/docker-push.yml"
pull_request:
types: [opened, synchronize, reopened]
paths:
- "v2ray.sh"
- "entrypoint.sh"
- "Dockerfile"
- ".github/workflows/docker-push.yml"

Expand Down
11 changes: 10 additions & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
FROM --platform=${TARGETPLATFORM} alpine:latest
LABEL maintainer="V2Fly Community <dev@v2fly.org>"

RUN apk add iptables

WORKDIR /root
ARG TARGETPLATFORM
ARG TAG
Expand All @@ -15,4 +17,11 @@ RUN set -ex \
&& chmod +x /root/v2ray.sh \
&& /root/v2ray.sh "${TARGETPLATFORM}" "${TAG}"

ENTRYPOINT ["/usr/bin/v2ray"]
COPY entrypoint.sh /root/entrypoint.sh
RUN chmod +x /root/entrypoint.sh

ENV TPROXY false
ENV DOKODEMO_DOOR_PORT 12345
ENV BYPASS_SUBNETS ""

ENTRYPOINT ["/root/entrypoint.sh"]
199 changes: 199 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,203 @@ docker run --rm v2fly/v2fly-core help
docker run --name v2ray v2fly/v2fly-core $v2ray_args (help, eun etc...)

docker run -d --name v2ray -v /path/to/config.json:/etc/v2fly/config.json -p 10086:10086 v2fly/v2fly-core run -c /etc/v2fly/config.json
```
---
# Gateway mode
You can use v2ray as a network gateway for serving a proxied network to another container or other devices in the network.

For running the container in gateway mode you need to make some changes in you v2ray config file.

1. Add an additional inbound with the dokodemo-door protocol for listening on the 12345 port (like example)
2. Add a mark of 255 to all the outbounds

### Example of config file for gateway mode
```json
{
"inbounds": [
{
"port": 1080,
"protocol": "socks",
"sniffing": {
"enabled": true,
"destOverride": ["http", "tls"]
},
"settings": {
"auth": "noauth"
}
},
{
"tag":"transparent",
"port": 12345,
"protocol": "dokodemo-door",
"settings": {
"network": "tcp,udp",
"followRedirect": true
},
"sniffing": {
"enabled": true,
"destOverride": [
"http",
"tls"
]
},
"streamSettings": { // it's necessary
"sockopt": {
"tproxy": "tproxy",
"mark":255
}
}
}
],
"outbounds": [
{
"tag": "proxy-1",
"protocol": "vmess",
"settings": {
"vnext": [
...
]
},
"streamSettings": {
"sockopt": { // You should add these settings for all of the outbounds
"mark": 255
}
}
},
{
"tag": "direct",
"protocol": "freedom",
"settings": {
"domainStrategy": "UseIP"
},
"streamSettings": {
"sockopt": { // Even for freedom
"mark": 255
}
}
},
{
"tag": "block",
"protocol": "blackhole",
"settings": {
"response": {
"type": "http"
}
}
},
{
"tag": "dns-out",
"protocol": "dns",
"streamSettings": {
"sockopt": {
"mark": 255
}
}
}
],
"dns": {
"servers": [
...
]
},
"routing": {
"domainStrategy": "IPOnDemand",
"rules": [
{
"type": "field",
"inboundTag": [
"transparent"
],
"port": 53,
"network": "udp",
"outboundTag": "dns-out"
},
{ // Directly connect to port 123 UDP traffic (NTP protocol)
"type": "field",
"inboundTag": [
"transparent"
],
"port": 123,
"network": "udp",
"outboundTag": "direct"
},
...
]
}
}

```

Please read [this topic](https://guide.v2fly.org/app/tproxy.html) for more details.


### Example of a home network gateway with docker compose
```yaml
version: '3.4'
services:
v2ray:
image: v2fly/v2fly-core
cap_add:
- NET_ADMIN # Required in gateway mode
volumes:
- ./testConfig.json:/etc/v2ray/config.json
environment:
- TPROXY=true # Active the gateway mode
command: ['run','-c','/etc/v2ray/config.json']
networks:
vlan:
ipv4_address: 192.168.1.254 # The IP address of this container which other devices can use this IP as a gateway.

networks:
vlan:
driver: macvlan
driver_opts:
parent: ens3 # The ethernet adaptor in the host system
ipam:
driver: default
config:
- subnet: 192.168.1.0/24 # Home network subnet
gateway: 192.168.1.1 # Home network gateway (your router ip)

```


### Example of a gateway for other containers with docker compose
```yaml
version: '3.4'
services:
v2ray:
image: v2fly/v2fly-core
cap_add:
- NET_ADMIN # Required in gateway mode
volumes:
- ./testConfig.json:/etc/v2ray/config.json
environment:
- TPROXY=true # Active the gateway mode
command: ['run','-c','/etc/v2ray/config.json']
networks:
bridgenetwork:
ipv4_address: 192.168.30.1

test-conatiner:
image: weibeld/ubuntu-networking
depends_on:
- v2ray
stdin_open: true
privileged: true
networks:
bridgenetwork:

command: > # Adding the v2ray container IP as a default gateway
sh -c "ip route del default &&
ip route add default via 192.168.30.1 &&
tail -f /dev/null"
networks:
bridgenetwork:
driver: bridge
ipam:
driver: default
config:
- subnet: "192.168.30.0/24"
gateway: "192.168.30.254"
```
72 changes: 72 additions & 0 deletions entrypoint.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
#!/bin/sh


setupTProxy() {

local docker_network="$(ip -o addr show dev eth0 | awk '$3 == "inet" {print $4}')"
local default_gateway=$(ip -4 route | grep 'default via' | awk '{print $3}')
local dokodemo_port=12345

if [[ $DOKODEMO_DOOR_PORT ]]; then
dokodemo_port=$DOKODEMO_DOOR_PORT
fi

echo "
--- Setting up the gateway iptables rules ----
dokodemo-door port: ${dokodemo_port}
Bypassed subnets: ${docker_network}, ${BYPASS_SUBNETS}
Default gateway: ${default_gateway}
Pay attention: This gateway handles the TCP and UDP requests. The Dokodemo-door doesn't support ICMP packets!"

# Reference: https://guide.v2fly.org/app/tproxy.html#%E8%AE%BE%E7%BD%AE%E7%BD%91%E5%85%B3
# Set policy routing
ip rule add fwmark 1 table 100
ip route add local 0.0.0.0/0 dev lo table 100
# Proxy LAN device
iptables -t mangle -N V2RAY
iptables -t mangle -A V2RAY -d 127.0.0.1/24 -j RETURN
iptables -t mangle -A V2RAY -d 224.0.0.0/4 -j RETURN
iptables -t mangle -A V2RAY -d 255.255.255.255/32 -j RETURN
iptables -t mangle -A V2RAY -d ${docker_network} -p tcp -j RETURN # Directly connect to the LAN to avoid SSH that cannot connect to the gateway when V2Ray cannot be started. If you configure other network segments (such as 10.x.x.x, etc.), modify it to your own
iptables -t mangle -A V2RAY -d ${docker_network} -p udp ! --dport 53 -j RETURN # Directly connected to the LAN, except port 53 (because V2Ray's DNS is used)
if [[ $BYPASS_SUBNETS ]]; then
for subnet in ${BYPASS_SUBNETS//,/ }; do
iptables -t mangle -A V2RAY -d "$subnet" -p tcp -j RETURN
iptables -t mangle -A V2RAY -d "$subnet" -p udp ! --dport 53 -j RETURN
done
fi
iptables -t mangle -A V2RAY -j RETURN -m mark --mark 0xff # Directly connect to the traffic whose SO_MARK is 0xff (0xff is a hexadecimal number, which is equivalent to 255 in the above V2Ray configuration). The purpose of this rule is to solve the problem that v2ray takes up a lot of CPU(https://github.com/v2ray/v2ray-core/issues/2621)
iptables -t mangle -A V2RAY -p udp -j TPROXY --on-ip 127.0.0.1 --on-port ${dokodemo_port} --tproxy-mark 1 # Mark UDP as 1 and forward to port 12345
iptables -t mangle -A V2RAY -p tcp -j TPROXY --on-ip 127.0.0.1 --on-port ${dokodemo_port} --tproxy-mark 1 # Mark the TCP with 1 and forward it to port 12345
iptables -t mangle -A PREROUTING -j V2RAY # application rules

# proxy gateway native
iptables -t mangle -N V2RAY_MASK
iptables -t mangle -A V2RAY_MASK -d 224.0.0.0/4 -j RETURN
iptables -t mangle -A V2RAY_MASK -d 255.255.255.255/32 -j RETURN
iptables -t mangle -A V2RAY_MASK -d ${docker_network} -p tcp -j RETURN # Direct LAN
iptables -t mangle -A V2RAY_MASK -d ${docker_network} -p udp ! --dport 53 -j RETURN # Directly connected to LAN, except port 53 (because V2Ray's DNS is used)
if [[ $BYPASS_SUBNETS ]]; then
for subnet in ${BYPASS_SUBNETS//,/ }; do
iptables -t mangle -A V2RAY_MASK -d "$subnet" -p tcp -j RETURN # Direct LAN
iptables -t mangle -A V2RAY_MASK -d "$subnet" -p udp ! --dport 53 -j RETURN # Directly connected to LAN, except port 53 (because V2Ray's DNS is used)
done
fi
iptables -t mangle -A V2RAY_MASK -j RETURN -m mark --mark 0xff # Directly connect to traffic whose SO_MARK is 0xff (0xff is a hexadecimal number, which is equivalent to 255 in the above V2Ray configuration). The purpose of this rule is to avoid the loopback problem of proxy local (gateway) traffic
iptables -t mangle -A V2RAY_MASK -p udp -j MARK --set-mark 1 # Mark UDP, reroute
iptables -t mangle -A V2RAY_MASK -p tcp -j MARK --set-mark 1 # Mark TCP, reroute
iptables -t mangle -A OUTPUT -j V2RAY_MASK # application rules

# Create a new DIVERT rule to prevent existing connected packets from passing through TPROXY twice, theoretically, there is a certain performance improvement
iptables -t mangle -N DIVERT
iptables -t mangle -A DIVERT -j MARK --set-mark 1
iptables -t mangle -A DIVERT -j ACCEPT
iptables -t mangle -I PREROUTING -p tcp -m socket -j DIVERT
}


if [[ "$TPROXY" = "true" ]]; then
setupTProxy &
fi

/usr/bin/v2ray "$@"