in cmd/ziffy/node/sender.go [173:241]
func (s *Sender) traceRoute(destinationIP string, sendingPort int, sweep bool) ([]SwitchTrafficInfo, error) {
var route []SwitchTrafficInfo
ptpUDPAddr, err := net.ResolveUDPAddr("udp", net.JoinHostPort(destinationIP, fmt.Sprint(s.Config.DestinationPort)))
if err != nil {
return nil, fmt.Errorf("traceRoute unable to resolve UDPAddr: %w", err)
}
ptpAddr := timestamp.IPToSockaddr(ptpUDPAddr.IP, s.Config.DestinationPort)
domain := unix.AF_INET6
if ptpUDPAddr.IP.To4() != nil {
domain = unix.AF_INET
}
connFd, err := unix.Socket(domain, unix.SOCK_DGRAM, unix.IPPROTO_UDP)
if err != nil {
return nil, fmt.Errorf("traceRoute unable to create connection: %w", err)
}
defer unix.Close(connFd)
// set SO_REUSEPORT so we can trace network path from same source port that ptp4u uses
if err = unix.SetsockoptInt(connFd, unix.SOL_SOCKET, unix.SO_REUSEPORT, 1); err != nil {
return nil, fmt.Errorf("setting SO_REUSEPORT on sender socket: %s", err)
}
localAddr := timestamp.IPToSockaddr(net.IPv6zero, sendingPort)
if err := unix.Bind(connFd, localAddr); err != nil {
return nil, fmt.Errorf("traceRoute unable to bind %v connection: %w", localAddr, err)
}
destReached := false
hopMax := s.Config.HopMax
// if sweep is activated and the destination was found
if sweep && s.destHop > 0 {
hopMax = s.destHop - 1
}
// Stop incrementing hops when either the max hop count is reached or
// the destination has responded unless continue is specified
for hop := s.Config.HopMin; hop <= hopMax && (!destReached || s.Config.ContReached); hop++ {
if err := unix.SetsockoptInt(connFd, unix.IPPROTO_IPV6, unix.IPV6_UNICAST_HOPS, hop); err != nil {
return route, err
}
// First 2 bits from Traffic Class are unused, so we shift the value 2 bits
if err := unix.SetsockoptInt(connFd, unix.IPPROTO_IPV6, unix.IPV6_TCLASS, s.Config.DSCP<<2); err != nil {
return route, err
}
var p ptp.Packet
switch s.Config.MessageType {
case ptp.MessageSync, ptp.MessageDelayReq:
p = formSyncPacket(s.Config.MessageType, hop, s.currentRoute)
case ptp.MessageSignaling:
p = formSignalingPacket(hop, s.currentRoute)
default:
return route, fmt.Errorf("unsupported packet type %v", s.Config.MessageType)
}
if err := s.sendEventMsg(p, connFd, ptpAddr); err != nil {
return route, err
}
select {
case sw := <-s.inputQueue:
s.routes[sw.routeIdx].switches = append(s.routes[sw.routeIdx].switches, *sw)
if net.ParseIP(sw.ip).Equal(ptpUDPAddr.IP) {
destReached = true
s.destHop = hop
}
case <-time.After(s.Config.IcmpTimeout):
continue
}
}
return route, nil
}