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

feat: TUN Support #2541

Merged
merged 28 commits into from Oct 23, 2023
Merged

feat: TUN Support #2541

merged 28 commits into from Oct 23, 2023

Conversation

AkinoKaede
Copy link
Contributor

@AkinoKaede AkinoKaede commented May 28, 2023

TODO

  • Fix TCP Handler
  • Fix UDP Handler
  • IP Address assign
  • Route Options
  • Socket Options
  • Sniff Support
  • Support for Microsoft Windows
  • Support for Mac OS X
  • Support for not amd64 or arm64 Linux device
  • Unit Test
  • PacketAddr support @xiaokangwang
  • Global bindToDevice option

@codecov-commenter
Copy link

codecov-commenter commented May 28, 2023

Codecov Report

Attention: 550 lines in your changes are missing coverage. Please review.

Comparison is base (442eb44) 38.27% compared to head (0ca8496) 37.74%.

❗ Your organization needs to install the Codecov GitHub app to enable full functionality.

Additional details and impacted files
@@            Coverage Diff             @@
##           master    #2541      +/-   ##
==========================================
- Coverage   38.27%   37.74%   -0.53%     
==========================================
  Files         637      654      +17     
  Lines       38147    38720     +573     
==========================================
+ Hits        14600    14616      +16     
- Misses      21938    22489     +551     
- Partials     1609     1615       +6     
Files Coverage Δ
app/tun/packetparse/errors.generated.go 100.00% <100.00%> (ø)
transport/internet/domainsocket/config.go 63.15% <100.00%> (ø)
transport/internet/domainsocket/config.pb.go 39.13% <ø> (ø)
app/tun/device/errors.generated.go 0.00% <0.00%> (ø)
app/tun/device/gvisor/errors.generated.go 0.00% <0.00%> (ø)
app/tun/errors.generated.go 0.00% <0.00%> (ø)
app/tun/net/net.go 0.00% <0.00%> (ø)
app/tun/tunsorter/errors.generated.go 0.00% <0.00%> (ø)
transport/internet/udp/dispatcher_packetaddr.go 0.00% <0.00%> (ø)
app/tun/packetaddradaptar.go 0.00% <0.00%> (ø)
... and 10 more

... and 3 files with indirect coverage changes

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@Vigilans
Copy link
Contributor

Vigilans commented May 29, 2023

One use case of tun may be for supporting ICMP for Fake IPs. With tproxy, only TCP and UDP can be handled by V2Ray, but with tun, v2ray can convert Fake IP to real IP and forward ICMP requests for it.

I may help to do such ICMP forwarding, write corresponding tests, and add v2ray v4 config support.

  • If already exists, bind to existing device instead of create one?

@rurirei
Copy link
Contributor

rurirei commented May 29, 2023

1 app/tun/handler_tcp.go app/tun/handler_udp.go a unneed channel (unbuffered even) to receives the conn.
2 app/tun/handler_udp.go note the unsupported udp nat-cone as gvisor warps a udp-conn with given target.
3 app/tun/handler_tcp.go app/tun/handler_udp.go do not implements a inbound-handler here (app/tun/), you could implements the handler as io.ReadWriteCloser instead. or implements a proxy-inbound like this. https://github.com/rurirei/v2ray-core/tree/init/proxy/tun

@AkinoKaede
Copy link
Contributor Author

@rurirei Thanks for your suggestions. I don't know much about how gVisor's UDP works, can you give some advice?

@AkinoKaede
Copy link
Contributor Author

One use case of tun may be for supporting ICMP for Fake IPs. With tproxy, only TCP and UDP can be handled by V2Ray, but with tun, v2ray can convert Fake IP to real IP and forward ICMP requests for it.

I may help to do such ICMP forwarding, write corresponding tests, and add v2ray v4 config support.

  • If already exists, bind to existing device instead of create one?

The goal of handling ICMP can be difficult to achieve, most proxy protocols do not support ICMP forwarding.

@Vigilans
Copy link
Contributor

Vigilans commented May 30, 2023

The goal of handling ICMP can be difficult to achieve, most proxy protocols do not support ICMP forwarding.

One of the reason may be related to this issue:
google/gvisor#8657

May need dig into the source code to find a way out. If achieved, there may be following icmp forward options: 1) fake, instantly response icmp echo packet (current behavior), 2) local/direct, send the icmp echo packet locally (like dns server's local), and 3) route/proxy. may we use something like packetaddr's special domain to wrap icmp payload and sent via procotols like vmess, finally handled by direct outbound?

@rurirei
Copy link
Contributor

rurirei commented May 30, 2023

@rurirei Thanks for your suggestions. I don't know much about how gVisor's UDP works, can you give some advice?

https://github.com/xjasonlyu/tun2socks/blob/main/core/udp.go https://github.com/SagerNet/sing-tun/blob/dev/gvisor_udp.go

@AkinoKaede
Copy link
Contributor Author

AkinoKaede commented May 30, 2023

1 app/tun/handler_tcp.go app/tun/handler_udp.go a unneed channel (unbuffered even) to receives the conn. 2 app/tun/handler_udp.go note the unsupported udp nat-cone as gvisor warps a udp-conn with given target. 3 app/tun/handler_tcp.go app/tun/handler_udp.go do not implements a inbound-handler here (app/tun/), you could implements the handler as io.ReadWriteCloser instead. or implements a proxy-inbound like this. https://github.com/rurirei/v2ray-core/tree/init/proxy/tun

Consider that TUN is not a proxy, so I implements it as App.

@AkinoKaede
Copy link
Contributor Author

The goal of handling ICMP can be difficult to achieve, most proxy protocols do not support ICMP forwarding.

One of the reason may be related to this issue: google/gvisor#8657

May need dig into the source code to find a way out. If achieved, there may be following icmp forward options: 1) fake, instantly response icmp echo packet (current behavior), 2) local/direct, send the icmp echo packet locally (like dns server's local), and 3) route/proxy. may we use something like packetaddr's special domain to wrap icmp payload and sent via procotols like vmess, finally handled by direct outbound?

I think the first option and the third option are feasible.

@AkinoKaede
Copy link
Contributor Author

AkinoKaede commented May 30, 2023

I test it on my Fedora VM, its' works.
Here this is a example config:

{
    "services": {
        "tun": {
            "name": "tun0",
            "mtu": 1500,
            "tag": "tun",
            "ips": [
                {
                    "ip": [192, 18, 0, 1],
                    "prefix": 24
                }
            ],
            "routes": [
                {
                    "ip": [0, 0, 0, 0],
                    "prefix": 0
                }
            ],
            "enablePromiscuousMode": true,
            "enableSpoofing": true
        }
    },
    "log": {
        "error": {
            "level": "Debug",
            "type": "Console"
        },
        "access": {
            "type": "None"
        }
    },
    "outbounds": [
        {
            "protocol": "freedom",
            "streamSettings": {
                "socketSettings": {
                    "bindToDevice": "eth0"
                }
            }
        }
    ]
}

@github-actions
Copy link
Contributor

It has been open 120 days with no activity. Remove stale label or comment or this will be closed in 5 days

@xiaokangwang
Copy link
Contributor

I have added packetEncoding option to tun app and it should just works.

You can test it by:

On a environment with network access

Run a server provides network access to other process with access to its domain socket with:

{
  "log": {
    "error": {
      "level": "Debug",
      "type": "Console"
    },
    "access": {
      "type": "None"
    }
  },
  "outbounds": [
    {
      "protocol": "freedom"
    }
  ],
  "inbounds": [
    {
      "protocol": "vmess",
      "settings": {
        "users": [
          "9aea4057-dae2-4e2a-b50a-26eada70323a"
        ]
      },
      "listen": "/run/shm/v2rayvmess"
    }
  ]
}

Run tun with fullcone enabled in a separate network namespace

Create a separate user, network, mount namespace with

unshare -r
unshare -n
unshare -m

In this environment, run the v2ray with following configuration in the background:

{
  "log": {
    "error": {
      "level": "Debug",
      "type": "Console"
    },
    "access": {
      "type": "None"
    }
  },
  "outbounds": [
    {
      "protocol": "vmess",
      "settings": {
        "uuid": "9aea4057-dae2-4e2a-b50a-26eada70323a",
        "address": "@v2rayvmess"
      },
      "streamSettings": {
        "transport": "domainsocket",
        "transportSettings": {
          "path": "/run/shm/v2rayvmess",
          "abstract": false
        }
      }
    }
  ],
  "services": {
    "tun": {
      "name": "tun0",
      "mtu": 1500,
      "tag": "tun",
      "ips": [
        {
          "ip": [192, 18, 0, 1],
          "prefix": 24
        }
      ],
      "routes": [
        {
          "ip": [0, 0, 0, 0],
          "prefix": 0
        }
      ],
      "enablePromiscuousMode": true,
      "enableSpoofing": true,
      "packetEncoding": "Packet"
    }
  }
}

Finalize network setup with:

ip link set tun0 up
ip addr add 192.18.0.1/24 dev tun0
ip route add default dev tun0

You may need to fix the dns settings, as the default system setting may not work in this environment:

echo 'nameserver 1.1.1.1' > resolv.conf
mount --bind  resolv.conf /etc/resolv.conf

Then you have finished the setup of a separate tun based network ready for testing.

@xiaokangwang xiaokangwang merged commit 0ca8496 into v2fly:master Oct 23, 2023
48 of 50 checks passed
@lluu131
Copy link

lluu131 commented Oct 31, 2023

image
使用tun作爲網關的時候,本機可以正常通過wget進行訪問,但是其他計算機使用網關的時候,wget卡住,curl正常

@sakurawald
Copy link

sakurawald commented Nov 7, 2023

I test it on my Fedora VM, its' works. Here this is a example config:

{
    "services": {
        "tun": {
            "name": "tun0",
            "mtu": 1500,
            "tag": "tun",
            "ips": [
                {
                    "ip": [192, 18, 0, 1],
                    "prefix": 24
                }
            ],
            "routes": [
                {
                    "ip": [0, 0, 0, 0],
                    "prefix": 0
                }
            ],
            "enablePromiscuousMode": true,
            "enableSpoofing": true
        }
    },
    "log": {
        "error": {
            "level": "Debug",
            "type": "Console"
        },
        "access": {
            "type": "None"
        }
    },
    "outbounds": [
        {
            "protocol": "freedom",
            "streamSettings": {
                "socketSettings": {
                    "bindToDevice": "eth0"
                }
            }
        }
    ]
}

Got error message using this template config:
Failed to start: main/commands: failed to load config: [./v.json] > infra/conf/v4: Cannot load service > infra/conf/v4: in V2Ray 5.9.0 (V2Fly, a community-driven edition of V2Ray.) Custom (go1.21.3 linux/amd64) A unified platform for anti-censorship.

Is the format changed ?

@lluu131
Copy link

lluu131 commented Nov 7, 2023

I test it on my Fedora VM, its' works. Here this is a example config:

{
    "services": {
        "tun": {
            "name": "tun0",
            "mtu": 1500,
            "tag": "tun",
            "ips": [
                {
                    "ip": [192, 18, 0, 1],
                    "prefix": 24
                }
            ],
            "routes": [
                {
                    "ip": [0, 0, 0, 0],
                    "prefix": 0
                }
            ],
            "enablePromiscuousMode": true,
            "enableSpoofing": true
        }
    },
    "log": {
        "error": {
            "level": "Debug",
            "type": "Console"
        },
        "access": {
            "type": "None"
        }
    },
    "outbounds": [
        {
            "protocol": "freedom",
            "streamSettings": {
                "socketSettings": {
                    "bindToDevice": "eth0"
                }
            }
        }
    ]
}

Got error message using this template config: Failed to start: main/commands: failed to load config: [./v.json] > infra/conf/v4: Cannot load service > infra/conf/v4: in V2Ray 5.9.0 (V2Fly, a community-driven edition of V2Ray.) Custom (go1.21.3 linux/amd64) A unified platform for anti-censorship.

Is the format changed ?

V5才支持

@r3a1d3a1
Copy link

r3a1d3a1 commented Nov 8, 2023

Same config parsing issue with this. Renamed the config to config.v5.json to no avail.

@AkinoKaede
Copy link
Contributor Author

Considering that the PR has been merged, it is recommended to submit issues for questions about use.

@r3a1d3a1
Copy link

r3a1d3a1 commented Nov 8, 2023

image
Jk, figured out the -format=jsonv5 arg. A link to differences vs v4 would still be appreciated however.

@sakurawald
Copy link

image
Jk, figured out the -format=jsonv5 arg. A link to differences vs v4 would still be appreciated however.

You guys just hide so many secreeeeets.

@Kein
Copy link

Kein commented Mar 20, 2024

Does anyone have an example how to tunnel ALL QUERIES from only specific application under Windows but at the same time also support SOCKS inbounds as well for others?
What are server/side configurations required

@Losalado
Copy link

Losalado commented Apr 25, 2024

One use case of tun may be for supporting ICMP for Fake IPs. With tproxy, only TCP and UDP can be handled by V2Ray, but with tun, v2ray can convert Fake IP to real IP and forward ICMP requests for it.

I may help to do such ICMP forwarding, write corresponding tests, and add v2ray v4 config support.

  • If already exists, bind to existing device instead of create one?

v5 config is WIP status, is it possible to add v2ray v4 config support for TUN?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet