github.com/nxtrace/NTrace-core@v1.3.1-0.20240513132635-39169291e8c9/trace/icmp_ipv6.go (about) 1 package trace 2 3 import ( 4 "bytes" 5 "encoding/binary" 6 "log" 7 "net" 8 "os" 9 "strconv" 10 "sync" 11 "time" 12 13 "golang.org/x/net/context" 14 "golang.org/x/net/icmp" 15 "golang.org/x/net/ipv6" 16 17 "github.com/nxtrace/NTrace-core/trace/internal" 18 ) 19 20 type ICMPTracerv6 struct { 21 Config 22 wg sync.WaitGroup 23 res Result 24 ctx context.Context 25 resCh chan Hop 26 inflightRequest map[int]chan Hop 27 inflightRequestRWLock sync.RWMutex 28 icmpListen net.PacketConn 29 final int 30 finalLock sync.Mutex 31 fetchLock sync.Mutex 32 } 33 34 func (t *ICMPTracerv6) PrintFunc() { 35 defer t.wg.Done() 36 var ttl = t.Config.BeginHop - 1 37 for { 38 if t.AsyncPrinter != nil { 39 t.AsyncPrinter(&t.res) 40 } 41 42 // 接收的时候检查一下是不是 3 跳都齐了 43 if len(t.res.Hops)-1 > ttl { 44 if len(t.res.Hops[ttl]) == t.NumMeasurements { 45 if t.RealtimePrinter != nil { 46 t.RealtimePrinter(&t.res, ttl) 47 } 48 ttl++ 49 50 if ttl == t.final-1 || ttl >= t.MaxHops-1 { 51 return 52 } 53 } 54 } 55 <-time.After(200 * time.Millisecond) 56 } 57 } 58 59 func (t *ICMPTracerv6) Execute() (*Result, error) { 60 t.inflightRequestRWLock.Lock() 61 t.inflightRequest = make(map[int]chan Hop) 62 t.inflightRequestRWLock.Unlock() 63 64 if len(t.res.Hops) > 0 { 65 return &t.res, ErrTracerouteExecuted 66 } 67 68 var err error 69 70 t.icmpListen, err = internal.ListenICMP("ip6:58", t.SrcAddr) 71 if err != nil { 72 return &t.res, err 73 } 74 defer t.icmpListen.Close() 75 76 var cancel context.CancelFunc 77 t.ctx, cancel = context.WithCancel(context.Background()) 78 defer cancel() 79 t.resCh = make(chan Hop) 80 t.final = -1 81 82 go t.listenICMP() 83 t.wg.Add(1) 84 go t.PrintFunc() 85 for ttl := t.BeginHop; ttl <= t.MaxHops; ttl++ { 86 t.inflightRequestRWLock.Lock() 87 t.inflightRequest[ttl] = make(chan Hop, t.NumMeasurements) 88 t.inflightRequestRWLock.Unlock() 89 if t.final != -1 && ttl > t.final { 90 break 91 } 92 for i := 0; i < t.NumMeasurements; i++ { 93 t.wg.Add(1) 94 go t.send(ttl) 95 <-time.After(time.Millisecond * time.Duration(t.Config.PacketInterval)) 96 } 97 <-time.After(time.Millisecond * time.Duration(t.Config.TTLInterval)) 98 } 99 // for ttl := t.BeginHop; ttl <= t.MaxHops; ttl++ { 100 // if t.final != -1 && ttl > t.final { 101 // break 102 // } 103 // for i := 0; i < t.NumMeasurements; i++ { 104 // t.wg.Add(1) 105 // go t.send(ttl) 106 // } 107 // // 一组TTL全部退出(收到应答或者超时终止)以后,再进行下一个TTL的包发送 108 // t.wg.Wait() 109 // if t.RealtimePrinter != nil { 110 // t.RealtimePrinter(&t.res, ttl-1) 111 // } 112 113 // if t.AsyncPrinter != nil { 114 // t.AsyncPrinter(&t.res) 115 // } 116 // } 117 t.wg.Wait() 118 t.res.reduce(t.final) 119 if t.final != -1 { 120 if t.RealtimePrinter != nil { 121 t.RealtimePrinter(&t.res, t.final-1) 122 } 123 } else { 124 for i := 0; i < t.NumMeasurements; i++ { 125 t.res.add(Hop{ 126 Success: false, 127 Address: nil, 128 TTL: 30, 129 RTT: 0, 130 Error: ErrHopLimitTimeout, 131 }) 132 } 133 if t.RealtimePrinter != nil { 134 t.RealtimePrinter(&t.res, t.MaxHops-1) 135 } 136 } 137 138 return &t.res, nil 139 } 140 141 func (t *ICMPTracerv6) listenICMP() { 142 lc := NewPacketListener(t.icmpListen, t.ctx) 143 psize = t.Config.PktSize 144 go lc.Start() 145 for { 146 select { 147 case <-t.ctx.Done(): 148 return 149 case msg := <-lc.Messages: 150 if msg.N == nil { 151 continue 152 } 153 if msg.Msg[0] == 129 { 154 rm, err := icmp.ParseMessage(58, msg.Msg[:*msg.N]) 155 if err != nil { 156 log.Println(err) 157 continue 158 } 159 160 echoReply, ok := rm.Body.(*icmp.Echo) 161 162 if ok { 163 ttl := echoReply.Seq // This is the TTL value 164 165 if ttl > 100 { 166 continue 167 } 168 if msg.Peer.String() == t.DestIP.String() { 169 t.handleICMPMessage(msg, 1, rm.Body.(*icmp.Echo).Data, ttl) 170 } 171 } 172 173 } 174 ttl := int64(binary.BigEndian.Uint16(msg.Msg[54:56])) 175 packetId := strconv.FormatInt(int64(binary.BigEndian.Uint16(msg.Msg[52:54])), 2) 176 if processId, _, err := reverseID(packetId); err == nil { 177 if processId == int64(os.Getpid()&0x7f) { 178 dstip := net.IP(msg.Msg[32:48]) 179 // 无效包本地环回包 180 if dstip.String() == "::" { 181 continue 182 } 183 if dstip.Equal(t.DestIP) || dstip.Equal(net.IPv6zero) { 184 // 匹配再继续解析包,否则直接丢弃 185 rm, err := icmp.ParseMessage(58, msg.Msg[:*msg.N]) 186 if err != nil { 187 log.Println(err) 188 continue 189 } 190 191 switch rm.Type { 192 case ipv6.ICMPTypeTimeExceeded: 193 t.handleICMPMessage(msg, 0, rm.Body.(*icmp.TimeExceeded).Data, int(ttl)) 194 case ipv6.ICMPTypeEchoReply: 195 t.handleICMPMessage(msg, 1, rm.Body.(*icmp.Echo).Data, int(ttl)) 196 case ipv6.ICMPTypeDestinationUnreachable: 197 t.handleICMPMessage(msg, 2, rm.Body.(*icmp.DstUnreach).Data, int(ttl)) 198 default: 199 // log.Println("received icmp message of unknown type", rm.Type) 200 } 201 } 202 } 203 } 204 // dstip := net.IP(msg.Msg[32:48]) 205 // if binary.BigEndian.Uint16(msg.Msg[52:54]) != uint16(os.Getpid()&0xffff) { 206 // // // 如果类型为应答消息,且应答消息包的进程ID与主进程相同时不跳过 207 // if binary.BigEndian.Uint16(msg.Msg[52:54]) != 0 { 208 // continue 209 // } else { 210 // if dstip.String() != "::" { 211 // continue 212 // } 213 // if msg.Peer.String() != t.DestIP.String() { 214 // continue 215 // } 216 // } 217 // } 218 219 // if dstip.Equal(t.DestIP) || dstip.Equal(net.IPv6zero) { 220 // rm, err := icmp.ParseMessage(58, msg.Msg[:*msg.N]) 221 // if err != nil { 222 // log.Println(err) 223 // continue 224 // } 225 // // log.Println(msg.Peer) 226 // switch rm.Type { 227 // case ipv6.ICMPTypeTimeExceeded: 228 // t.handleICMPMessage(msg, 0, rm.Body.(*icmp.TimeExceeded).Data) 229 // case ipv6.ICMPTypeEchoReply: 230 // t.handleICMPMessage(msg, 1, rm.Body.(*icmp.Echo).Data) 231 // default: 232 // // log.Println("received icmp message of unknown type", rm.Type) 233 // } 234 // } 235 } 236 } 237 238 } 239 240 func (t *ICMPTracerv6) handleICMPMessage(msg ReceivedMessage, icmpType int8, data []byte, ttl int) { 241 if icmpType == 2 { 242 if t.DestIP.String() != msg.Peer.String() { 243 return 244 } 245 } 246 t.inflightRequestRWLock.RLock() 247 defer t.inflightRequestRWLock.RUnlock() 248 249 mpls := extractMPLS(msg, data) 250 if _, ok := t.inflightRequest[ttl]; ok { 251 t.inflightRequest[ttl] <- Hop{ 252 Success: true, 253 Address: msg.Peer, 254 MPLS: mpls, 255 } 256 } 257 } 258 259 func (t *ICMPTracerv6) send(ttl int) error { 260 defer t.wg.Done() 261 if t.final != -1 && ttl > t.final { 262 return nil 263 } 264 //id := gernerateID(ttl) 265 id := gernerateID(0) 266 267 //data := []byte{byte(ttl)} 268 data := []byte{byte(0)} 269 data = append(data, bytes.Repeat([]byte{1}, t.Config.PktSize-5)...) 270 data = append(data, 0x00, 0x00, 0x4f, 0xff) 271 272 icmpHeader := icmp.Message{ 273 Type: ipv6.ICMPTypeEchoRequest, Code: 0, 274 Body: &icmp.Echo{ 275 ID: id, 276 //Data: []byte("HELLO-R-U-THERE"), 277 Data: data, 278 Seq: ttl, 279 }, 280 } 281 282 p := ipv6.NewPacketConn(t.icmpListen) 283 284 icmpHeader.Body.(*icmp.Echo).Seq = ttl 285 err := p.SetHopLimit(ttl) 286 if err != nil { 287 return err 288 } 289 290 wb, err := icmpHeader.Marshal(nil) 291 if err != nil { 292 log.Fatal(err) 293 } 294 295 start := time.Now() 296 if _, err := t.icmpListen.WriteTo(wb, &net.IPAddr{IP: t.DestIP}); err != nil { 297 log.Fatal(err) 298 } 299 if err := t.icmpListen.SetReadDeadline(time.Now().Add(3 * time.Second)); err != nil { 300 log.Fatal(err) 301 } 302 303 select { 304 case <-t.ctx.Done(): 305 return nil 306 case h := <-t.inflightRequest[ttl]: 307 rtt := time.Since(start) 308 if t.final != -1 && ttl > t.final { 309 return nil 310 } 311 if addr, ok := h.Address.(*net.IPAddr); ok && addr.IP.Equal(t.DestIP) { 312 t.finalLock.Lock() 313 if t.final == -1 || ttl < t.final { 314 t.final = ttl 315 } 316 t.finalLock.Unlock() 317 } else if addr, ok := h.Address.(*net.TCPAddr); ok && addr.IP.Equal(t.DestIP) { 318 t.finalLock.Lock() 319 if t.final == -1 || ttl < t.final { 320 t.final = ttl 321 } 322 t.finalLock.Unlock() 323 } 324 325 h.TTL = ttl 326 h.RTT = rtt 327 328 t.fetchLock.Lock() 329 defer t.fetchLock.Unlock() 330 err := h.fetchIPData(t.Config) 331 if err != nil { 332 return err 333 } 334 335 t.res.add(h) 336 337 case <-time.After(t.Timeout): 338 if t.final != -1 && ttl > t.final { 339 return nil 340 } 341 342 t.res.add(Hop{ 343 Success: false, 344 Address: nil, 345 TTL: ttl, 346 RTT: 0, 347 Error: ErrHopLimitTimeout, 348 }) 349 } 350 351 return nil 352 }