Skip to content
This repository has been archived by the owner on Dec 19, 2023. It is now read-only.

Refactor main networking code #8

Merged
merged 32 commits into from
Aug 17, 2022
Merged

Refactor main networking code #8

merged 32 commits into from
Aug 17, 2022

Conversation

reethikar
Copy link
Contributor

Refactor code to improve readability and modularity
For now,

  • I've pushed zeroTrace items to its own file, and refactored the functions
  • Reduced the number of variables functions take, and use a zeroTrace instance to carry necessary variables

This is still a work in progress

@reethikar reethikar changed the title Refaactor main networking code Refactor main networking code Aug 8, 2022
@reethikar reethikar marked this pull request as ready for review August 8, 2022 13:44
@reethikar
Copy link
Contributor Author

@NullHypothesis marking this ready to get preliminary feedback on how I'm going about with the refactoring. Let me know if this is a good start.

@NullHypothesis
Copy link
Contributor

Unrelated to the actual code: Take a look at the commit guidelines of the Pro Git book. You're doing pretty well on that front already but the section contains a few helpful suggestions, like limiting the first line of a commit message to <=50 characters.

Copy link
Contributor

@NullHypothesis NullHypothesis left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Left a bunch of comments. I hope it's helpful!

clientIP, clPort, _ := net.SplitHostPort(clientIPstr)
clientPort, _ := strconv.Atoi(clPort)

zeroTraceInstance := newZeroTrace(deviceName, myConn, uuid, clientIP, clientPort)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would only pass myConn to newZeroTrace. The function can then extract IP addresses and ports from the connection. No need to pass them separately.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 7dd7051

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a big improvement in clarity. Nice!

@@ -16,3 +21,61 @@ func isValidUUID(u string) bool {
func fmtTimeMs(value time.Duration) float64 {
return (float64(value) / float64(time.Millisecond))
}

// getMeanIcmpRTT gets Avg RTT from all successful ICMP measurements, to display on webpage
func getMeanIcmpRTT(icmp []RtItem) float64 {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is RtItem short for? Round Trip Item? I've always been a bit confused by the name. Some suggestions for a better name:

  • RttResult
  • RttMsmt
  • HopResult
  • HopMsmt

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 7dd7051


const (
beginTTLValue = 5
MaxTTLHops = 32
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Inconsistent capitalization of constants. I generally suggest lowercase unless you want to export a constant for use outside of this package.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 7dd7051

)

var (
buffer gopacket.SerializeBuffer
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some of these variables are only used once and don't need to be global. In that case, I suggest inlining them.

Copy link
Contributor Author

@reethikar reethikar Aug 16, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 7dd7051 and 0e14997

icmpPktError = errors.New("IP header unavailable")
)

type SentPacketData struct {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe add a doc string explaining what this is used for? It's not immediately clear from the name only.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added in 0e14997

}

// recvPackets listens on the provided pcap handler for packets sent, processes TCP and ICMP packets differently
func (z *zeroTrace) recvPackets(pcapHdl *pcap.Handle, hops chan HopRTT) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it possible that this function won't return if we never get the ICMP packets that we're expecting? It should probably take as input some sort of abort signal from the caller, instructing the function to return when the caller is done.

Copy link
Contributor Author

@reethikar reethikar Aug 11, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's right. I'll add an abort signal that makes this function return when the tracerouteHopTimeout is reached (and yet no ICMP packets are received) for the last probe. Added in c08b5db.

return nil, err
}
if err = pcapHdl.SetBPFFilter(fmt.Sprintf("(tcp and port %d and host %s) or icmp", z.ClientPort, z.ClientIP)); err != nil {
ErrLogger.Fatal(err)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's not exit the program here, and simply propagate the error. It should be up to the code that's using zeroTrace to decide what to do with that error.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in b5c2e3d

// Create the packet with the layers
buffer = gopacket.NewSerializeBuffer()

serializeErr := gopacket.SerializeLayers(buffer, options,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nitpick: I'd simply call each error err. That's both idiomatic and reduces the cognitive load of reviewers because if every error is called err, there are fewer variables to keep track of.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in ffe573f

gopacket.Payload(rawBytes),
)
if serializeErr != nil {
ErrLogger.Println("Send Packet Error: Serialize: ", serializeErr)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could save ourselves all these log messages if the caller checks if sendTracePacket returned and error, and if so, we can do something like:

if err := z.sendTracePacket(ttlValue); err != nil {
  ErrLogger.Println("Send Packet Error: ", err)
  return traceroute, sendError
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed, and done in ffe573f

PcapHdl *pcap.Handle
ClientIP string
ClientPort int
IPIdHop map[int][]SentPacketData
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are we anticipating concurrent reads/writes to this map?

Copy link
Contributor Author

@reethikar reethikar Aug 15, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(I've renamed this map to SentPktsIPId in 0e14997)
It is a map of the IPIds and sent times of the sent packets for each TTL. I don't expect concurrent reads or writes because each packet---sent packet (writes to this) or received packet (reads from this)---is dealt with sequentially.

Comment on lines +142 to +144
select {
case <-quit:
return
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've found an issue with this:
In this file L:113, we feed "true" to the quit channel once the sendTTLIncrementingProbes function returns. But since I am working with the packet stream here, I need to wait until another packet is seen on this handle before being able to quit. Moving the select statement out also does not work since the execution will be stuck in the for packet := range packetStream.Packets() loop.

Trying to fix this now

Copy link
Contributor Author

@reethikar reethikar Aug 16, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A fix has been pushed in a89c1d2

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's the same fix that I had in mind when reviewing the code 👍

Fix issue by reading from packet stream as a channel, do not check for isClientReached? in recvPackets, instead let sender figure it out and abort the receive goroutine
@NullHypothesis
Copy link
Contributor

Thanks for addressing all the feedback and for doing it in separate commits. That makes it much easier for me to see what changed. Let's not have the perfect be the enemy of the good, and merge this. We can still improve the code and add tests in follow-up PRs.

Input form to collect user details
@reethikar reethikar merged commit ac898cf into main Aug 17, 2022
@reethikar
Copy link
Contributor Author

Merged PR#9 into this and then this PR into main. Thanks for your comments! 🚀

@reethikar reethikar deleted the refactor branch August 17, 2022 13:55
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants