meh / rust-tun

TUN device creation and handling.
340 stars 133 forks source link

Could you elaborate on what routing needs to be done for MacOs? #57

Open franklee26 opened 1 year ago

franklee26 commented 1 year ago

I'm referring to this section of the readme:

It just werks, but you have to set up routing manually.

I'm not receiving any packets on my MacOs (similar to #53). Here's my skeleton setup:

// server
let mut config = tun::Configuration::default();
config
    .address((192, 168, 55, 0))
    .netmask((255, 255, 255, 0))
    .up();

let mut dev = tun::create(&config).unwrap();

let _ = Command::new("route")
    .args(["-n", "add", "-net", "192.168.55.0/24", "10.0.0.1"])
    .output();

let mut buffer = vec![0; 1504]; // MTU + 4 for the header
loop {
    let nbytes = dev.read(&mut buffer).unwrap();
    // Output bytes (nothing gets read...)
}

// client
let socket = UdpSocket::bind("0.0.0.0:34254")?;
socket
    .connect("192.168.55.2:31416")
    .expect("connect function failed");

    // sending non-empty buffer
    socket.send(&buf)?;

I see this device in my ifconfig output:

utun4: flags=8051<UP,POINTOPOINT,RUNNING,MULTICAST> mtu 1500
    inet 192.168.55.0 --> 10.0.0.255 netmask 0xffffff00
M0dEx commented 1 year ago

Had the same issue a couple of months before.

I was unfortunately not able to figure out the cause and had to switch to another library (tunio), which is having issues assigning addresses to TUN interfaces.

M0dEx commented 1 year ago

As for the routing needed - you need to add routes for ip route add 10.0.0.0/8 dev utun4 (you need the ip Homebrew cask installed).

xmh0511 commented 10 months ago

I am also confused by this. The tun in my code is created as

fn main() {
    let mut config = tun::Configuration::default();
    config.address((10, 0, 0, 1))
           .netmask((255, 255, 255, 0))
           .up();

    let mut dev = tun::create(&config).unwrap();
    let mut buf = [0; 4096];

    loop {
        let amount = dev.read(&mut buf).unwrap();
        println!("{:?}", &buf[0 .. amount]);
    }
}

Then running the command ifconfig -a, I can see the created tun device:

 utun3: flags=8051<UP,POINTOPOINT,RUNNING,MULTICAST> mtu 1500
    inet 10.0.0.1 --> 10.0.0.255 netmask 0xffffff00 

The address is exactly the set one. However, when I run ping 10.0.0.2, I cannot see any prints in my program. What's the wrong here? Is it caused by I didn't set the "route"? What value should I set for the "route" and how do I run ping to see the reaction?

M0dEx commented 10 months ago

I am also confused by this. The tun in my code is created as

fn main() {
  let mut config = tun::Configuration::default();
  config.address((10, 0, 0, 1))
         .netmask((255, 255, 255, 0))
         .up();

  let mut dev = tun::create(&config).unwrap();
  let mut buf = [0; 4096];

  loop {
      let amount = dev.read(&mut buf).unwrap();
      println!("{:?}", &buf[0 .. amount]);
  }
}

Then running the command ifconfig -a, I can see the created tun device:

 utun3: flags=8051<UP,POINTOPOINT,RUNNING,MULTICAST> mtu 1500
  inet 10.0.0.1 --> 10.0.0.255 netmask 0xffffff00 

The address is exactly the set one. However, when I run ping 10.0.0.2, I cannot see any prints in my program. What's the wrong here? Is it caused by I didn't set the "route"? What value should I set for the "route" and how do I run ping to see the reaction?

The route on MacOS needs to be set manually, unfortunately.

See my comment above.

xmh0511 commented 10 months ago

The route on MacOS needs to be set manually, unfortunately.

Could you please tell me what value I should manually set for the "route"? Should I set the value with 192.168.2.21, which is my physical address? Or, it can be arbitrary ipv4 address as I want?

M0dEx commented 10 months ago

The route on MacOS needs to be set manually, unfortunately.

Could you please tell me what value I should manually set for the "route"? Should I set the value with 192.168.2.21, which is my physical address? Or, it can be arbitrary ipv4 address as I want?

For the TUN interface you posted, the appropriate route would probably be:

ip route add 10.0.0.0/24 dev utun3
xmh0511 commented 10 months ago

The route on MacOS needs to be set manually, unfortunately.

Could you please tell me what value I should manually set for the "route"? Should I set the value with 192.168.2.21, which is my physical address? Or, it can be arbitrary ipv4 address as I want?

For the TUN interface you posted, the appropriate route would probably be:

ip route add 10.0.0.0/24 dev utun3

Thanks, It works for me. What does the route mean here? Why should I set it as 10.0.0.0/24 and then it will work? If I set it as 192.168.10.0, will it work?

M0dEx commented 10 months ago

The route on MacOS needs to be set manually, unfortunately.

Could you please tell me what value I should manually set for the "route"? Should I set the value with 192.168.2.21, which is my physical address? Or, it can be arbitrary ipv4 address as I want?

For the TUN interface you posted, the appropriate route would probably be:

ip route add 10.0.0.0/24 dev utun3

Thanks, It works for me. What does the route mean here? Why should I set it as 10.0.0.0/24 and then it will work? If I set it as 192.168.10.0, will it work?

It depends on what traffic you want to send over the tunnel.

If you want to route traffic to devices with IP addresses in a 192.168.10.0/24 subnet, you will need to set the routes appropriately, eg. 192.168.10.0/24 dev utun3.

xmh0511 commented 10 months ago

If you want to route traffic to devices with IP addresses in a 192.168.10.0/24 subnet, you will need to set the routes appropriately, eg. 192.168.10.0/24 dev utun3.

Thanks. IIUC, this means, all access to 192.168.10.x will be processed by untun3, right?

M0dEx commented 10 months ago

If you want to route traffic to devices with IP addresses in a 192.168.10.0/24 subnet, you will need to set the routes appropriately, eg. 192.168.10.0/24 dev utun3.

Thanks. IIUC, this means, all access to 192.168.10.x will be processed by untun3, right?

Yes.

xmh0511 commented 10 months ago

@M0dEx Hi, I still have an issue with the routing, If I set the routing to 10.0.0.0/24 via

ip route add 10.0.0.0/24 dev utun3

Then, with the ICMP packet

source ip: 10.0.0.1, dest ip: 10.0.0.2

which is produced by ping 10.0.0.2 and this request is delivered to my program via utun3, then I write the echo-reply packet with source ip: 10.0.0.2, dest ip: 10.0.0.1 to utun3, and the ping command successfully receives the response. In this whole progress, I have a doubt: Why was my response packet not re-delivered to my "tun" program again, which would cause the infinite loop, IIUC?

My prior understanding is that if I set the route with 10.0.0.0/24 to my utun3, then all associated packets with 10.0.0.x would be delivered to my utun3 program, with this understanding, the response packet with source ip 10.0.0.2 and destination ip 10.0.0.1 are exactly relevant, however, this packed written by my utun3 program didn't re-delivered to my program, I just wonder why? Any answers would be appreciated.

M0dEx commented 10 months ago

@M0dEx Hi, I still have an issue with the routing, If I set the routing to 10.0.0.0/24 via

ip route add 10.0.0.0/24 dev utun3

Then, with the ICMP packet

source ip: 10.0.0.1, dest ip: 10.0.0.2

which is produced by ping 10.0.0.2 and this request is delivered to my program via utun3, then I write the echo-reply packet with source ip: 10.0.0.2, dest ip: 10.0.0.1 to utun3, and the ping command successfully receives the response. In this whole progress, I have a doubt: Why was my response packet not re-delivered to my "tun" program again, which would cause the infinite loop, IIUC?

My prior understanding is that if I set the route with 10.0.0.0/24 to my utun3, then all associated packets with 10.0.0.x would be delivered to my utun3 program, with this understanding, the response packet with source ip 10.0.0.2 and destination ip 10.0.0.1 are exactly relevant, however, this packed written by my utun3 program didn't re-delivered to my program, I just wonder why? Any answers would be appreciated.

This is because the utun3 interface itself has the IP 10.0.0.1. This means that when a packet is received, on that interface, with that IP, it gets sent to whatever application is associated with the socket specified by the destination IP (and port, if applicable). In your case, this application was the ping command, so the responses with destination IP 10.0.0.1 got "routed" to it.

xmh0511 commented 10 months ago

Thanks, that means, I don't need to worry about a packet written by the utun3 program "reflux" into the utun3 program again if the destination IP of the packet is the address of the utun3 devices, In my example it's 10.0.0.1, right?

So, it seems to be the interpretation of the example of the simpletun. The client ran on machine A with the tun device configured with:

6.6.6.1/24

and its real physical address of eth0 is 192.168.1.10. On machine B, which is the tun server, whose tun device has the configuration:

6.6.6.2/24

the physical address of B is 192.168.1.15. Then on machine A, running the command ping 10.0.0.2, the produced packet will be processed by the "tun program" of A, it sends the packet via TCP to machine B(192.168.1.10 -> 192.168.1.15), then B reads the packet from TCP socket, the acquired packet(from the network) will be directly written into the tun device of B, then B reads the associated result from tun and deliver the result via TCP to A.

In this whole process, note the emphasized part, the packet with source ip: 10.0.0.1, destination ip: 10.0.0.2 is directly written into the tun of B, IIUC, the reason why this packet didn't reflux into tun program of B again is because of the destination IP in this packet is that of the tun of B, right? Then this packet will be delivered to an appropriate program that can resolve this packet, then the produced packet from that program will have source ip: 10.0.0.2, destination ip: 10.0.0.1, and in this packet, the destination IP is 10.0.0.1, which is not the address of tun on B(that is 10.0.0.2), hence this packet will be delivered to tun program of B, so, this is the reason why tun program of B can read the resulting packet(ICMP reply) from tun device, right?

xmh0511 commented 10 months ago

This is because the utun3 interface itself has the IP 10.0.0.1. This means that when a packet is received, on that interface, with that IP, it gets sent to whatever application is associated with the socket specified by the destination IP (and port, if applicable).

I'm not sure whether I 100% understand your answers. With the default code in https://github.com/meh/rust-tun/blob/master/examples/ping-tun.rs, and set the route for utun3 in my machine

ip route add 10.0.0.0/24 dev utun3

When I run the command ping 10.0.0.1, this produced packet is still routed to the utun3 program, The packet has src IP: 10.0.0.1, dest IP: 10.0.0.1, as interpreted in your answer, this packet should just not be processed by my utun program since the destination IP of the packet is the address of the tun device. Or, you just mean when writing packet to the utun device via the utun program, the packet with a destination IP that is the same as that of the address of utun devices won't be re-read by utun program itself again.