Serve listens for responses to the requests until context is done
(ctx context.Context)
| 196 | |
| 197 | // Serve listens for responses to the requests until context is done |
| 198 | func (ip *icmpProxy) Serve(ctx context.Context) error { |
| 199 | go func() { |
| 200 | <-ctx.Done() |
| 201 | ip.conn.Close() |
| 202 | }() |
| 203 | go func() { |
| 204 | ip.srcFunnelTracker.ScheduleCleanup(ctx, ip.idleTimeout) |
| 205 | }() |
| 206 | buf := make([]byte, mtu) |
| 207 | icmpDecoder := packet.NewICMPDecoder() |
| 208 | for { |
| 209 | n, from, err := ip.conn.ReadFrom(buf) |
| 210 | if err != nil { |
| 211 | return err |
| 212 | } |
| 213 | reply, err := parseReply(from, buf[:n]) |
| 214 | if err != nil { |
| 215 | ip.logger.Debug().Err(err).Str("dst", from.String()).Msg("Failed to parse ICMP reply, continue to parse as full packet") |
| 216 | // In unit test, we found out when the listener listens on 0.0.0.0, the socket reads the full packet after |
| 217 | // the second reply |
| 218 | if err := ip.handleFullPacket(ctx, icmpDecoder, buf[:n]); err != nil { |
| 219 | ip.logger.Debug().Err(err).Str("dst", from.String()).Msg("Failed to parse ICMP reply as full packet") |
| 220 | } |
| 221 | continue |
| 222 | } |
| 223 | if !isEchoReply(reply.msg) { |
| 224 | ip.logger.Debug().Str("dst", from.String()).Msgf("Drop ICMP %s from reply", reply.msg.Type) |
| 225 | continue |
| 226 | } |
| 227 | if err := ip.sendReply(ctx, reply); err != nil { |
| 228 | ip.logger.Debug().Err(err).Str("dst", from.String()).Msg("Failed to send ICMP reply") |
| 229 | continue |
| 230 | } |
| 231 | } |
| 232 | } |
| 233 | |
| 234 | func (ip *icmpProxy) handleFullPacket(ctx context.Context, decoder *packet.ICMPDecoder, rawPacket []byte) error { |
| 235 | icmpPacket, err := decoder.Decode(packet.RawPacket{Data: rawPacket}) |
nothing calls this directly
no test coverage detected