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

Feature: Use tcp for traceroute #112

Closed
1 task done
niklastreml opened this issue Feb 21, 2024 · 2 comments · Fixed by #159
Closed
1 task done

Feature: Use tcp for traceroute #112

niklastreml opened this issue Feb 21, 2024 · 2 comments · Fixed by #159
Assignees
Labels
request Indicates a feature request
Milestone

Comments

@niklastreml
Copy link
Contributor

Is there an existing feature request for this?

  • I have searched the existing issues

Problem Description

The current implementation of the traceroute check uses udp to perform its logic. This is not ideal since udp is not connection oriented. This means that the check can never really know whether a packet reached its destination, unless that destination sends back an ICMP packet, which tends to be blocked by firewalls.

Solution Description

We can get around the above issues by reimplementing the traceroute functionality on top of TCP instead of UDP. We can essentially send a TCP SYN packet to initiate a handshake with a server on its open port. The underlying logic of the check stays the same, we're only changing the protocol.

Who can address the issue?

Anyone who wants to read some RFCs and feels like playing around with berkeley sockets

Additional Context

https://en.wikipedia.org/wiki/Berkeley_sockets
https://www.ietf.org/rfc/rfc793.txt#:~:text=Transmission%20Control%20Protocol-,3.%20%20FUNCTIONAL%20SPECIFICATION,-3.1.%20%20Header%20Format
https://github.com/mct/tcptraceroute/blob/master/probe.c#L80

@niklastreml niklastreml added the request Indicates a feature request label Feb 21, 2024
@niklastreml niklastreml mentioned this issue Feb 21, 2024
2 tasks
@puffitos puffitos added this to the 0.4.0 milestone Apr 22, 2024
@lvlcn-t
Copy link
Member

lvlcn-t commented May 23, 2024

I've started to implement this in feat/tcp-traceroute. Unfortunately, we cannot get any useful information with a pure tcp traceroute because of the nature of the tcp protocol. We can only know how many hops we have done without a successful connection (a response in form of a RST packet) but any further information is not possible because the routers in between only send back an ICMP packet if the ttl has expired (traceroute uses this to get the hops). I also implemented the other forms of traceroute in the branch (udp/icmp & raw sockets/icmp) to allow the user to choose the method they want to use but as you may know both of these methods either need the CAP_NET_RAW capability or root privileges which is not ideal. I will continue to work on this but I wanted to share my progress so far. Additionally I'm planning to adjust the user configuration options as follows:

traceroute:
  protocol: tcp
  interval: 10s
  timeout: 400s
  maxHops: 64
  retry:
    count: 5
    delay: 1s
  targets:
    - addr: example.com
      port: 80
    - addr: google.com
      port: 80

This way the user can choose the protocol they want to use. I'm also planning to adjust the API response to the following schema:

// result represents the result of a single hop in the traceroute
type result struct {
	// Duration represents the total duration of the traceroute
	Duration float64
	// Hops represents the hops to the target
	Hops []traceroute.Hop
}

// Hop represents the result of a single hop in the traceroute
type Hop struct {
	// Tracepoint represents the hop number
	Tracepoint int
	// IP represents the IP address of the hop
	IP net.IP
	// Error represents the error that occurred during the hop
	Error string
	// Duration represents the time it took to reach the hop
	Duration float64
	// ReachedTarget indicates whether the target was reached with this hop
	ReachedTarget bool
}

I also tried to implement as much concurrency as possible to speed up the traceroute process as it takes a long time to complete. I will continue to work on it and update you on my progress.

@niklastreml
Copy link
Contributor Author

Sounds good so far. I've done a fair bit of research on this and there just isn't a way to get useful data without capabilities. We should just let the user choose, if they need that extra info or not.

To actually get the data from icmp, you'll probably need to parse the time exceeded response in some way. Since ICMP doesn't know about ports, that response includes 64 bits of the previous packet's payload. This is just about enough to fit in the tcp source and destination ports and the sequence number. If you can get your hands on the source port you should be able to map the icmp response back to your correct request

@niklastreml niklastreml mentioned this issue Aug 7, 2024
4 tasks
@niklastreml niklastreml self-assigned this Aug 7, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
request Indicates a feature request
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants