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

Create a local tunnel interface #28

Closed
2-face opened this issue May 27, 2019 · 4 comments
Closed

Create a local tunnel interface #28

2-face opened this issue May 27, 2019 · 4 comments

Comments

@2-face
Copy link

2-face commented May 27, 2019

I have created for a test function relayToOS and checked it on OSX.
Basically idea is to have a local tunnel interface and push traffic thru it via gtp-u to a gateway.
It was created on a code that I checked out more than a month ago so it is inefficient taking into account that recently there were made some improvements yet it proves the idea.
Upon session creation:

  • create a local tunnel interface
  • assign IP address to it from a session
  • add a route to some destination via the tunnel
@wmnsk
Copy link
Owner

wmnsk commented May 27, 2019

Thank you for your idea.
Could you show me the codes that you wrote with the older implementation of the package?

If it isn’t OSX-specific, I can try embedding into the package itself.

Just FYI, I’m working on implementing netlink support that works only on Linux where Kernel-based GTP-U is supported, which I think the most efficient way for vast majority.
#24

@2-face
Copy link
Author

2-face commented May 27, 2019

Yep seen that you're working on netlink based GTP-U.

Checked it on OSX and on Ubuntu. In the following way I was pushing whole traffic via tun via the session.

Two extra libraries required:

"github.com/songgao/water"
"github.com/vishvananda/netlink"

In relay.go:

// Until peer information is registered by AddPeer(), it just drops packets.
func (r *RelayToOS) Run() {
	// from left to right
	go func() {
		buf := make([]byte, 1600)
		for {
			select {
			case <-r.closed():
				return
			default:
				// do nothing and go forward.
			}

			n, err := r.leftConn.Read(buf)
			if err != nil {
				continue
			}

			if _, err := r.rightConn.WriteToGTP(r.rightConnPeer.teid, buf[:n], r.rightConnPeer.addr); err != nil {
				continue
			}
		}
	}()

	// from right to left
	go func() {
		buf := make([]byte, 1600)
		for {
			select {
			case <-r.closed():
				return
			default:
				// do nothing and go forward.
			}

			n, _, _, err := r.rightConn.ReadFromGTP(buf)
			if err != nil {
				continue
			}

			if _, err := r.leftConn.Write(buf[:n]); err != nil {
				continue
			}
		}
	}()
}

// Close closes Relay. It does not close the UPlaneConn given at first.
func (r *RelayToOS) Close() error {
	//FIXME original line was: r.leftConn.SetReadDeadline(time.Now().Add(time.Duration(1 * time.Millisecond)))
	if err := r.leftConn.Close(); err != nil {
		return err
	}
	if err := r.rightConn.SetReadDeadline(time.Now().Add(time.Duration(1 * time.Millisecond))); err != nil {
		return err
	}
	close(r.closeCh)
	return nil
}

func (r *RelayToOS) closed() <-chan struct{} {
	return r.closeCh
}

// AddPeer adds a peer information with the TEID contained in the incoming meesage.
func (r *RelayToOS) AddPeer(teid uint32, raddr net.Addr) {
	r.mu.Lock()
	defer r.mu.Unlock()

	r.rightConnPeer = &peer{teid, raddr}
}

In examples/mme/mock.go:

func (m mockUEeNB) run(errCh chan error)

OSX (I was adding route manually via tun):

func (m mockUEeNB) run(errCh chan error) {
	if uConn == nil {
		// Listen on eNB S1-U interface.
		enbUPlaneAddr, err := net.ResolveUDPAddr("udp", *s1enb)
		if err != nil {
			log.Fatal(err)
		}
		m.laddr = enbUPlaneAddr

		uConn, err = v1.ListenAndServeUPlane(m.laddr, 0, errCh)
		if err != nil {
			errCh <- err
			return
		}

		ifce, err := water.New(water.Config{
			DeviceType: water.TUN,
		})
		if err != nil {
			log.Fatal(err)
		}
		loggerCh <- fmt.Sprintf("Created ifce %s", ifce.Name())
		
		//On MAC
		//Assign subscriber IP to interface
		_, err = exec.Command("/sbin/ifconfig", "utun2", m.subscriberIP, m.subscriberIP, "up").Output()

		// handle it here
		if err != nil {
			fmt.Printf("%s", err)
		}

		relayToOS := v1.NewRelayToOS(ifce, uConn)
		relayToOS.AddPeer(m.teidOut, m.raddr)
		go relayToOS.Run()
	}

Ubuntu:

func (m mockUEeNB) run(errCh chan error) {
	if uConn == nil {
		// Listen on eNB S1-U interface.
		enbUPlaneAddr, err := net.ResolveUDPAddr("udp", *s1enb)
		if err != nil {
			log.Fatal(err)
		}
		m.laddr = enbUPlaneAddr

		uConn, err = v1.ListenAndServeUPlane(m.laddr, 0, errCh)
		if err != nil {
			errCh <- err
			return
		}
		
		//On MAC
		/*ifce, err := water.New(water.Config{
			DeviceType: water.TUN,
		})
		if err != nil {
			log.Fatal(err)
		}
		loggerCh <- fmt.Sprintf("Created ifce %s", ifce.Name())

		//On Linux
		ifce, err := water.New(water.Config{
			DeviceType: water.TUN,
		})
		if err != nil {
			log.Fatal(err)
		}
		loggerCh <- fmt.Sprintf("Created ifce %s", ifce.Name())

		tun, _ := netlink.LinkByName(ifce.Name())
		addr, _ := netlink.ParseAddr(m.subscriberIP + "/32")
		loggerCh <- fmt.Sprintf("Address for tun %s", addr)
		
		//add IP address from subscriber session
		err = netlink.AddrAdd(tun, addr)
		if err != nil {
			log.Fatal(err)
		}
		
		//bring up the interface
		err = netlink.LinkSetUp(tun)
		if err != nil {
			log.Fatal(err)
		}

		//delete existing default route
		dst := &net.IPNet{
			IP:   net.IPv4(0, 0, 0, 0),
			Mask: net.CIDRMask(0, 0),
		}
		err = netlink.RouteDel(&netlink.Route{LinkIndex: tun.Attrs().Index, Dst: dst})
		if err != nil {
			fmt.Printf("%s", err)
		}

		//add new default route via tun interface
		err = netlink.RouteAdd(&netlink.Route{LinkIndex: tun.Attrs().Index, Dst: dst})
		if err != nil {
			log.Fatal(err)
		}


		relayToOS := v1.NewRelayToOS(ifce, uConn)
		relayToOS.AddPeer(m.teidOut, m.raddr)
		go relayToOS.Run()
	}

@wmnsk
Copy link
Owner

wmnsk commented May 28, 2019

Looks so useful for testing. Thanks!
Could you please give me a PR with current implementation? Otherwise, I’ll try to add some built-in funcs and examples according to your idea in the future.

@wmnsk
Copy link
Owner

wmnsk commented Jun 3, 2019

Let me know if you have anything to discuss further. Thanks.

@wmnsk wmnsk closed this as completed Jun 3, 2019
wmnsk pushed a commit that referenced this issue Feb 23, 2024
* fix HasUASI

* Implemented Extended Common Flags and Flags II

---------

Co-authored-by: Dmitrijs Zvancuks <[email protected]>
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

No branches or pull requests

2 participants