Repository: fujiapple852/trippy (language: rust)

Issue:
Add last icmp packet code column



Discussion / hints:

Fix patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 99146991f..6257125df 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -12,7 +12,8 @@ to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
 - Added Ubuntu PPA package ([#859](https://github.com/fujiapple852/trippy/issues/859))
 - Added `--generate-man` flags for generating [ROFF](https://en.wikipedia.org/wiki/Roff_(software)) man
   page ([#85](https://github.com/fujiapple852/trippy/issues/85))
-- Added support for last icmp packet code (`T`) column ([#1105](https://github.com/fujiapple852/trippy/issues/1105))
+- Added support for last icmp packet type (`T`) column ([#1105](https://github.com/fujiapple852/trippy/issues/1105))
+- Added support for last icmp packet code (`C`) column ([#1109](https://github.com/fujiapple852/trippy/issues/1109))
 
 ### Changed
 
diff --git a/README.md b/README.md
index 89022c43a..236b1349e 100644
--- a/README.md
+++ b/README.md
@@ -850,6 +850,7 @@ configuration file.
 | `Sprt`  | `S`  | The source port for last probe for the hop                                                                                                                                                                                                                                                                                                            |
 | `Dprt`  | `P`  | The destination port for last probe for the hop                                                                                                                                                                                                                                                                                                       |
 | `Type`  | `T`  | The icmp packet type for last probe for the hop:<br/>- TE TimeExceeded<br/>- ER EchoReply<br/>- DU Destination Unreachable<br/>- NA NotApplicable                                                                                                                                                                                                     |
+| `Code`  | `C`  | The icmp packet code for last probe for the hop                                                                                                                                                                                                                                                                                                       |
 
 The default columns are `holsravbwdt`.
 
diff --git a/src/config/columns.rs b/src/config/columns.rs
index 01f81b9f1..fba6fdcb4 100644
--- a/src/config/columns.rs
+++ b/src/config/columns.rs
@@ -87,6 +87,8 @@ pub enum TuiColumn {
     LastSeq,
     /// The icmp packet type for the last probe for this hop.
     LastIcmpPacketType,
+    /// The icmp packet code for the last probe for this hop.
+    LastIcmpPacketCode,
 }
 
 impl TryFrom<char> for TuiColumn {
@@ -113,6 +115,7 @@ impl TryFrom<char> for TuiColumn {
             'P' => Ok(Self::LastDestPort),
             'Q' => Ok(Self::LastSeq),
             'T' => Ok(Self::LastIcmpPacketType),
+            'C' => Ok(Self::LastIcmpPacketCode),
             c => Err(anyhow!(format!("unknown column code: {c}"))),
         }
     }
@@ -140,6 +143,7 @@ impl Display for TuiColumn {
             Self::LastDestPort => write!(f, "P"),
             Self::LastSeq => write!(f, "Q"),
             Self::LastIcmpPacketType => write!(f, "T"),
+            Self::LastIcmpPacketCode => write!(f, "C"),
         }
     }
 }
diff --git a/src/frontend/columns.rs b/src/frontend/columns.rs
index 9d3831374..4299cd838 100644
--- a/src/frontend/columns.rs
+++ b/src/frontend/columns.rs
@@ -180,6 +180,8 @@ pub enum ColumnType {
     LastSeq,
     /// The icmp packet type for the last probe for this hop.
     LastIcmpPacketType,
+    /// The icmp packet code for the last probe for this hop.
+    LastIcmpPacketCode,
 }
 
 impl From<ColumnType> for char {
@@ -204,6 +206,7 @@ impl From<ColumnType> for char {
             ColumnType::LastDestPort => 'P',
             ColumnType::LastSeq => 'Q',
             ColumnType::LastIcmpPacketType => 'T',
+            ColumnType::LastIcmpPacketCode => 'C',
         }
     }
 }
@@ -230,6 +233,7 @@ impl From<TuiColumn> for Column {
             TuiColumn::LastDestPort => Self::new_shown(ColumnType::LastDestPort),
             TuiColumn::LastSeq => Self::new_shown(ColumnType::LastSeq),
             TuiColumn::LastIcmpPacketType => Self::new_shown(ColumnType::LastIcmpPacketType),
+            TuiColumn::LastIcmpPacketCode => Self::new_shown(ColumnType::LastIcmpPacketCode),
         }
     }
 }
@@ -256,6 +260,7 @@ impl Display for ColumnType {
             Self::LastDestPort => write!(f, "Dprt"),
             Self::LastSeq => write!(f, "Seq"),
             Self::LastIcmpPacketType => write!(f, "Type"),
+            Self::LastIcmpPacketCode => write!(f, "Code"),
         }
     }
 }
@@ -284,6 +289,7 @@ impl ColumnType {
             Self::LastDestPort => ColumnWidth::Fixed(7),
             Self::LastSeq => ColumnWidth::Fixed(7),
             Self::LastIcmpPacketType => ColumnWidth::Fixed(7),
+            Self::LastIcmpPacketCode => ColumnWidth::Fixed(7),
         }
     }
 }
@@ -341,6 +347,7 @@ mod tests {
                 Column::new_hidden(ColumnType::LastDestPort),
                 Column::new_hidden(ColumnType::LastSeq),
                 Column::new_hidden(ColumnType::LastIcmpPacketType),
+                Column::new_hidden(ColumnType::LastIcmpPacketCode),
             ])
         );
     }
diff --git a/src/frontend/render/table.rs b/src/frontend/render/table.rs
index 5e3b53ebe..95ad7aa97 100644
--- a/src/frontend/render/table.rs
+++ b/src/frontend/render/table.rs
@@ -164,6 +164,7 @@ fn new_cell(
         ColumnType::LastDestPort => render_port_cell(hop.last_dest_port()),
         ColumnType::LastSeq => render_usize_cell(usize::from(hop.last_sequence())),
         ColumnType::LastIcmpPacketType => render_icmp_packet_type_cell(hop.last_icmp_packet_type()),
+        ColumnType::LastIcmpPacketCode => render_icmp_packet_code_cell(hop.last_icmp_packet_type()),
     }
 }
 
@@ -213,13 +214,24 @@ fn render_status_cell(hop: &Hop, is_target: bool) -> Cell<'static> {
 fn render_icmp_packet_type_cell(icmp_packet_type: Option<IcmpPacketType>) -> Cell<'static> {
     match icmp_packet_type {
         None => Cell::from("n/a"),
-        Some(IcmpPacketType::TimeExceeded) => Cell::from("TE"),
-        Some(IcmpPacketType::EchoReply) => Cell::from("ER"),
-        Some(IcmpPacketType::Unreachable) => Cell::from("DU"),
+        Some(IcmpPacketType::TimeExceeded(_)) => Cell::from("TE"),
+        Some(IcmpPacketType::EchoReply(_)) => Cell::from("ER"),
+        Some(IcmpPacketType::Unreachable(_)) => Cell::from("DU"),
         Some(IcmpPacketType::NotApplicable) => Cell::from("NA"),
     }
 }
 
+fn render_icmp_packet_code_cell(icmp_packet_type: Option<IcmpPacketType>) -> Cell<'static> {
+    match icmp_packet_type {
+        Some(
+            IcmpPacketType::Unreachable(code)
+            | IcmpPacketType::TimeExceeded(code)
+            | IcmpPacketType::EchoReply(code),
+        ) => Cell::from(format!("{}", code.0)),
+        _ => Cell::from("n/a"),
+    }
+}
+
 fn render_port_cell(port: u16) -> Cell<'static> {
     if port > 0 {
         Cell::from(format!("{port}"))
diff --git a/src/tracing/net/ipv4.rs b/src/tracing/net/ipv4.rs
index c9c889524..239236b64 100644
--- a/src/tracing/net/ipv4.rs
+++ b/src/tracing/net/ipv4.rs
@@ -15,8 +15,8 @@ use crate::tracing::packet::tcp::TcpPacket;
 use crate::tracing::packet::udp::UdpPacket;
 use crate::tracing::packet::IpProtocol;
 use crate::tracing::probe::{
-    Extensions, Probe, ProbeResponse, ProbeResponseData, ProbeResponseSeq, ProbeResponseSeqIcmp,
-    ProbeResponseSeqTcp, ProbeResponseSeqUdp,
+    Extensions, IcmpPacketCode, Probe, ProbeResponse, ProbeResponseData, ProbeResponseSeq,
+    ProbeResponseSeqIcmp, ProbeResponseSeqTcp, ProbeResponseSeqUdp,
 };
 use crate::tracing::types::{PacketSize, PayloadPattern, Sequence, TraceId, TypeOfService};
 use crate::tracing::{Flags, Port, PrivilegeMode, Protocol};
@@ -258,6 +258,7 @@ pub fn recv_tcp_socket<S: Socket>(
                 let error_addr = tcp_socket.icmp_error_info()?;
                 return Ok(Some(ProbeResponse::TimeExceeded(
                     ProbeResponseData::new(SystemTime::now(), error_addr, resp_seq),
+                    IcmpPacketCode(1),
                     None,
                 )));
             }
@@ -376,6 +377,7 @@ fn extract_probe_resp(
                 extract_probe_resp_seq(&nested_ipv4, protocol)?.map(|resp_seq| {
                     ProbeResponse::TimeExceeded(
                         ProbeResponseData::new(recv, src, resp_seq),
+                        IcmpPacketCode(icmp_code.0),
                         extension,
                     )
                 })
@@ -395,6 +397,7 @@ fn extract_probe_resp(
             extract_probe_resp_seq(&nested_ipv4, protocol)?.map(|resp_seq| {
                 ProbeResponse::DestinationUnreachable(
                     ProbeResponseData::new(recv, src, resp_seq),
+                    IcmpPacketCode(icmp_code.0),
                     extension,
                 )
             })
@@ -405,9 +408,10 @@ fn extract_probe_resp(
                 let id = packet.get_identifier();
                 let seq = packet.get_sequence();
                 let resp_seq = ProbeResponseSeq::Icmp(ProbeResponseSeqIcmp::new(id, seq));
-                Some(ProbeResponse::EchoReply(ProbeResponseData::new(
-                    recv, src, resp_seq,
-                )))
+                Some(ProbeResponse::EchoReply(
+                    ProbeResponseData::new(recv, src, resp_seq),
+                    IcmpPacketCode(icmp_code.0),
+                ))
             }
             Protocol::Udp | Protocol::Tcp => None,
         },
@@ -1039,15 +1043,18 @@ mod tests {
         )?
         .unwrap();
 
-        let ProbeResponse::EchoReply(ProbeResponseData {
-            addr,
-            resp_seq:
-                ProbeResponseSeq::Icmp(ProbeResponseSeqIcmp {
-                    identifier,
-                    sequence,
-                }),
-            ..
-        }) = resp
+        let ProbeResponse::EchoReply(
+            ProbeResponseData {
+                addr,
+                resp_seq:
+                    ProbeResponseSeq::Icmp(ProbeResponseSeqIcmp {
+                        identifier,
+                        sequence,
+                    }),
+                ..
+            },
+            icmp_code,
+        ) = resp
         else {
             panic!("expected EchoReply")
         };
@@ -1057,6 +1064,7 @@ mod tests {
         );
         assert_eq!(30167, identifier);
         assert_eq!(33049, sequence);
+        assert_eq!(IcmpPacketCode(0), icmp_code);
         Ok(())
     }
 
@@ -1095,6 +1103,7 @@ mod tests {
                     }),
                 ..
             },
+            icmp_code,
             extensions,
         ) = resp
         else {
@@ -1106,6 +1115,7 @@ mod tests {
         );
         assert_eq!(30167, identifier);
         assert_eq!(33047, sequence);
+        assert_eq!(IcmpPacketCode(0), icmp_code);
         assert_eq!(None, extensions);
         Ok(())
     }
@@ -1142,6 +1152,7 @@ mod tests {
                     }),
                 ..
             },
+            icmp_code,
             extensions,
         ) = resp
         else {
@@ -1150,6 +1161,7 @@ mod tests {
         assert_eq!(IpAddr::V4(Ipv4Addr::from_str("20.0.0.254").unwrap()), addr);
         assert_eq!(31489, identifier);
         assert_eq!(33060, sequence);
+        assert_eq!(IcmpPacketCode(1), icmp_code);
         assert_eq!(None, extensions);
         Ok(())
     }
@@ -1190,6 +1202,7 @@ mod tests {
                     }),
                 ..
             },
+            icmp_code,
             extensions,
         ) = resp
         else {
@@ -1206,6 +1219,7 @@ mod tests {
         assert_eq!(58571, checksum);
         assert_eq!(56, payload_len);
         assert!(!has_magic);
+        assert_eq!(IcmpPacketCode(0), icmp_code);
         assert_eq!(None, extensions);
         Ok(())
     }
@@ -1246,6 +1260,7 @@ mod tests {
                     }),
                 ..
             },
+            icmp_code,
             extensions,
         ) = resp
         else {
@@ -1262,6 +1277,7 @@ mod tests {
         assert_eq!(10913, checksum);
         assert_eq!(56, payload_len);
         assert!(!has_magic);
+        assert_eq!(IcmpPacketCode(10), icmp_code);
         assert_eq!(None, extensions);
         Ok(())
     }
@@ -1297,6 +1313,7 @@ mod tests {
                     }),
                 ..
             },
+            icmp_code,
             extensions,
         ) = resp
         else {
@@ -1312,6 +1329,7 @@ mod tests {
         );
         assert_eq!(33021, src_port);
         assert_eq!(80, dest_port);
+        assert_eq!(IcmpPacketCode(0), icmp_code);
         assert_eq!(None, extensions);
         Ok(())
     }
@@ -1347,6 +1365,7 @@ mod tests {
                     }),
                 ..
             },
+            icmp_code,
             extensions,
         ) = resp
         else {
@@ -1359,6 +1378,7 @@ mod tests {
         );
         assert_eq!(33010, src_port);
         assert_eq!(10011, dest_port);
+        assert_eq!(IcmpPacketCode(10), icmp_code);
         assert_eq!(None, extensions);
         Ok(())
     }
@@ -1535,6 +1555,7 @@ mod tests {
                     }),
                 ..
             },
+            icmp_code,
             extensions,
         ) = resp
         else {
@@ -1543,6 +1564,7 @@ mod tests {
         assert_eq!(dest_addr, addr);
         assert_eq!(33000, src_port);
         assert_eq!(80, dest_port);
+        assert_eq!(IcmpPacketCode(1), icmp_code);
         assert_eq!(None, extensions);
         Ok(())
     }
diff --git a/src/tracing/net/ipv6.rs b/src/tracing/net/ipv6.rs
index 31af3d427..d411dffef 100644
--- a/src/tracing/net/ipv6.rs
+++ b/src/tracing/net/ipv6.rs
@@ -14,8 +14,8 @@ use crate::tracing::packet::tcp::TcpPacket;
 use crate::tracing::packet::udp::UdpPacket;
 use crate::tracing::packet::IpProtocol;
 use crate::tracing::probe::{
-    Extensions, Probe, ProbeResponse, ProbeResponseData, ProbeResponseSeq, ProbeResponseSeqIcmp,
-    ProbeResponseSeqTcp, ProbeResponseSeqUdp,
+    Extensions, IcmpPacketCode, Probe, ProbeResponse, ProbeResponseData, ProbeResponseSeq,
+    ProbeResponseSeqIcmp, ProbeResponseSeqTcp, ProbeResponseSeqUdp,
 };
 use crate::tracing::types::{PacketSize, PayloadPattern, Sequence, TraceId};
 use crate::tracing::{Flags, Port, PrivilegeMode, Protocol};
@@ -248,6 +248,7 @@ pub fn recv_tcp_socket<S: Socket>(
                 let error_addr = tcp_socket.icmp_error_info()?;
                 return Ok(Some(ProbeResponse::TimeExceeded(
                     ProbeResponseData::new(SystemTime::now(), error_addr, resp_seq),
+                    IcmpPacketCode(1),
                     None,
                 )));
             }
@@ -338,6 +339,7 @@ fn extract_probe_resp(
                 extract_probe_resp_seq(&nested_ipv6, protocol)?.map(|resp_seq| {
                     ProbeResponse::TimeExceeded(
                         ProbeResponseData::new(recv, ip, resp_seq),
+                        IcmpPacketCode(icmp_code.0),
                         extension,
                     )
                 })
@@ -357,6 +359,7 @@ fn extract_probe_resp(
             extract_probe_resp_seq(&nested_ipv6, protocol)?.map(|resp_seq| {
                 ProbeResponse::DestinationUnreachable(
                     ProbeResponseData::new(recv, ip, resp_seq),
+                    IcmpPacketCode(icmp_code.0),
                     extension,
                 )
             })
@@ -367,9 +370,10 @@ fn extract_probe_resp(
                 let id = packet.get_identifier();
                 let seq = packet.get_sequence();
                 let resp_seq = ProbeResponseSeq::Icmp(ProbeResponseSeqIcmp::new(id, seq));
-                Some(ProbeResponse::EchoReply(ProbeResponseData::new(
-                    recv, ip, resp_seq,
-                )))
+                Some(ProbeResponse::EchoReply(
+                    ProbeResponseData::new(recv, ip, resp_seq),
+                    IcmpPacketCode(icmp_code.0),
+                ))
             }
             Protocol::Udp | Protocol::Tcp => None,
         },
@@ -1014,21 +1018,25 @@ mod tests {
         )?
         .unwrap();
 
-        let ProbeResponse::EchoReply(ProbeResponseData {
-            addr,
-            resp_seq:
-                ProbeResponseSeq::Icmp(ProbeResponseSeqIcmp {
-                    identifier,
-                    sequence,
-                }),
-            ..
-        }) = resp
+        let ProbeResponse::EchoReply(
+            ProbeResponseData {
+                addr,
+                resp_seq:
+                    ProbeResponseSeq::Icmp(ProbeResponseSeqIcmp {
+                        identifier,
+                        sequence,
+                    }),
+                ..
+            },
+            icmp_code,
+        ) = resp
         else {
             panic!("expected EchoReply")
         };
         assert_eq!(recv_from_addr, addr);
         assert_eq!(21945, identifier);
         assert_eq!(33062, sequence);
+        assert_eq!(IcmpPacketCode(0), icmp_code);
         Ok(())
     }
 
@@ -1071,6 +1079,7 @@ mod tests {
                     }),
                 ..
             },
+            icmp_code,
             extensions,
         ) = resp
         else {
@@ -1079,6 +1088,7 @@ mod tests {
         assert_eq!(recv_from_addr, addr);
         assert_eq!(21945, identifier);
         assert_eq!(33056, sequence);
+        assert_eq!(IcmpPacketCode(0), icmp_code);
         assert_eq!(None, extensions);
         Ok(())
     }
@@ -1122,6 +1132,7 @@ mod tests {
                     }),
                 ..
             },
+            icmp_code,
             extensions,
         ) = resp
         else {
@@ -1130,6 +1141,7 @@ mod tests {
         assert_eq!(recv_from_addr, addr);
         assert_eq!(22437, identifier);
         assert_eq!(33005, sequence);
+        assert_eq!(IcmpPacketCode(0), icmp_code);
         assert_eq!(None, extensions);
         Ok(())
     }
@@ -1174,6 +1186,7 @@ mod tests {
                     }),
                 ..
             },
+            icmp_code,
             extensions,
         ) = resp
         else {
@@ -1190,6 +1203,7 @@ mod tests {
         assert_eq!(53489, checksum);
         assert_eq!(36, payload_len);
         assert!(!has_magic);
+        assert_eq!(IcmpPacketCode(0), icmp_code);
         assert_eq!(None, extensions);
         Ok(())
     }
@@ -1234,6 +1248,7 @@ mod tests {
                     }),
                 ..
             },
+            icmp_code,
             extensions,
         ) = resp
         else {
@@ -1250,6 +1265,7 @@ mod tests {
         assert_eq!(37906, checksum);
         assert_eq!(36, payload_len);
         assert!(!has_magic);
+        assert_eq!(IcmpPacketCode(0), icmp_code);
         assert_eq!(None, extensions);
         Ok(())
     }
@@ -1300,6 +1316,7 @@ mod tests {
                     }),
                 ..
             },
+            icmp_code,
             extensions,
         ) = resp
         else {
@@ -1316,6 +1333,7 @@ mod tests {
         assert_eq!(39490, checksum);
         assert_eq!(5, payload_len);
         assert!(has_magic);
+        assert_eq!(IcmpPacketCode(0), icmp_code);
         assert_eq!(None, extensions);
         Ok(())
     }
@@ -1356,6 +1374,7 @@ mod tests {
                     }),
                 ..
             },
+            icmp_code,
             extensions,
         ) = resp
         else {
@@ -1368,6 +1387,7 @@ mod tests {
         );
         assert_eq!(33038, src_port);
         assert_eq!(80, dest_port);
+        assert_eq!(IcmpPacketCode(0), icmp_code);
         assert_eq!(None, extensions);
         Ok(())
     }
@@ -1408,6 +1428,7 @@ mod tests {
                     }),
                 ..
             },
+            icmp_code,
             extensions,
         ) = resp
         else {
@@ -1420,6 +1441,7 @@ mod tests {
         );
         assert_eq!(33060, src_port);
         assert_eq!(123, dest_port);
+        assert_eq!(IcmpPacketCode(0), icmp_code);
         assert_eq!(None, extensions);
         Ok(())
     }
@@ -1609,6 +1631,7 @@ mod tests {
                     }),
                 ..
             },
+            icmp_code,
             extensions,
         ) = resp
         else {
@@ -1617,6 +1640,7 @@ mod tests {
         assert_eq!(dest_addr, addr);
         assert_eq!(33000, src_port);
         assert_eq!(80, dest_port);
+        assert_eq!(IcmpPacketCode(1), icmp_code);
         assert_eq!(None, extensions);
         Ok(())
     }
diff --git a/src/tracing/probe.rs b/src/tracing/probe.rs
index 2234017e8..0c2ddf83e 100644
--- a/src/tracing/probe.rs
+++ b/src/tracing/probe.rs
@@ -120,21 +120,25 @@ pub struct ProbeComplete {
 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
 pub enum IcmpPacketType {
     /// TimeExceeded packet.
-    TimeExceeded,
+    TimeExceeded(IcmpPacketCode),
     /// EchoReply packet.
-    EchoReply,
+    EchoReply(IcmpPacketCode),
     /// Unreachable packet.
-    Unreachable,
+    Unreachable(IcmpPacketCode),
     /// Non-ICMP response (i.e. for some `UDP` & `TCP` probes).
     NotApplicable,
 }
 
+/// The code of `TimeExceeded`, `EchoReply` and `Unreachable` ICMP packets.
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub struct IcmpPacketCode(pub u8);
+
 /// The response to a probe.
 #[derive(Debug, Clone)]
 pub enum ProbeResponse {
-    TimeExceeded(ProbeResponseData, Option<Extensions>),
-    DestinationUnreachable(ProbeResponseData, Option<Extensions>),
-    EchoReply(ProbeResponseData),
+    TimeExceeded(ProbeResponseData, IcmpPacketCode, Option<Extensions>),
+    DestinationUnreachable(ProbeResponseData, IcmpPacketCode, Option<Extensions>),
+    EchoReply(ProbeResponseData, IcmpPacketCode),
     TcpReply(ProbeResponseData),
     TcpRefused(ProbeResponseData),
 }
diff --git a/src/tracing/tracer.rs b/src/tracing/tracer.rs
index a87901fbc..2ee688eb2 100644
--- a/src/tracing/tracer.rs
+++ b/src/tracing/tracer.rs
@@ -149,25 +149,25 @@ impl<F: Fn(&TracerRound<'_>)> Tracer<F> {
     fn recv_response<N: Network>(&self, network: &mut N, st: &mut TracerState) -> TraceResult<()> {
         let next = network.recv_probe()?;
         match next {
-            Some(ProbeResponse::TimeExceeded(data, extensions)) => {
+            Some(ProbeResponse::TimeExceeded(data, icmp_code, extensions)) => {
                 let (trace_id, sequence, received, host) = self.extract(&data);
                 let is_target = host == self.config.target_addr;
                 if self.check_trace_id(trace_id) && st.in_round(sequence) && self.validate(&data) {
                     st.complete_probe_time_exceeded(
-                        sequence, host, received, is_target, extensions,
+                        sequence, host, received, is_target, icmp_code, extensions,
                     );
                 }
             }
-            Some(ProbeResponse::DestinationUnreachable(data, extensions)) => {
+            Some(ProbeResponse::DestinationUnreachable(data, icmp_code, extensions)) => {
                 let (trace_id, sequence, received, host) = self.extract(&data);
                 if self.check_trace_id(trace_id) && st.in_round(sequence) && self.validate(&data) {
-                    st.complete_probe_unreachable(sequence, host, received, extensions);
+                    st.complete_probe_unreachable(sequence, host, received, icmp_code, extensions);
                 }
             }
-            Some(ProbeResponse::EchoReply(data)) => {
+            Some(ProbeResponse::EchoReply(data, icmp_code)) => {
                 let (trace_id, sequence, received, host) = self.extract(&data);
                 if self.check_trace_id(trace_id) && st.in_round(sequence) && self.validate(&data) {
-                    st.complete_probe_echo_reply(sequence, host, received);
+                    st.complete_probe_echo_reply(sequence, host, received, icmp_code);
                 }
             }
             Some(ProbeResponse::TcpReply(data) | ProbeResponse::TcpRefused(data)) => {
@@ -346,6 +346,7 @@ impl<F: Fn(&TracerRound<'_>)> Tracer<F> {
 mod tests {
     use super::*;
     use crate::tracing::net::MockNetwork;
+    use crate::tracing::probe::IcmpPacketCode;
     use crate::tracing::{MaxRounds, Port};
     use std::net::Ipv4Addr;
     use std::num::NonZeroUsize;
@@ -377,6 +378,7 @@ mod tests {
                         target_addr,
                         ProbeResponseSeq::Tcp(ProbeResponseSeqTcp::new(target_addr, sequence, 80)),
                     ),
+                    IcmpPacketCode(1),
                     None,
                 )))
             });
@@ -415,7 +417,7 @@ mod tests {
 /// the `TracerState` struct.
 mod state {
     use crate::tracing::constants::MAX_SEQUENCE_PER_ROUND;
-    use crate::tracing::probe::{Extensions, IcmpPacketType, Probe, ProbeState};
+    use crate::tracing::probe::{Extensions, IcmpPacketCode, IcmpPacketType, Probe, ProbeState};
     use crate::tracing::types::{MaxRounds, Port, Round, Sequence, TimeToLive, TraceId};
     use crate::tracing::{Config, Flags, MultipathStrategy, PortDirection, Protocol};
     use std::array::from_fn;
@@ -718,11 +720,12 @@ mod state {
             host: IpAddr,
             received: SystemTime,
             is_target: bool,
+            icmp_code: IcmpPacketCode,
             extensions: Option<Extensions>,
         ) {
             self.complete_probe(
                 sequence,
-                IcmpPacketType::TimeExceeded,
+                IcmpPacketType::TimeExceeded(icmp_code),
                 host,
                 received,
                 is_target,
@@ -737,11 +740,12 @@ mod state {
             sequence: Sequence,
             host: IpAddr,
             received: SystemTime,
+            icmp_code: IcmpPacketCode,
             extensions: Option<Extensions>,
         ) {
             self.complete_probe(
                 sequence,
-                IcmpPacketType::Unreachable,
+                IcmpPacketType::Unreachable(icmp_code),
                 host,
                 received,
                 true,
@@ -756,10 +760,11 @@ mod state {
             sequence: Sequence,
             host: IpAddr,
             received: SystemTime,
+            icmp_code: IcmpPacketCode,
         ) {
             self.complete_probe(
                 sequence,
-                IcmpPacketType::EchoReply,
+                IcmpPacketType::EchoReply(icmp_code),
                 host,
                 received,
                 true,
@@ -942,7 +947,14 @@ mod state {
             // Update the state of the probe 1 after receiving a TimeExceeded
             let received_1 = SystemTime::now();
             let host = IpAddr::V4(Ipv4Addr::LOCALHOST);
-            state.complete_probe_time_exceeded(Sequence(33000), host, received_1, false, None);
+            state.complete_probe_time_exceeded(
+                Sequence(33000),
+                host,
+                received_1,
+                false,
+                IcmpPacketCode(1),
+                None,
+            );
 
             // Validate the state of the probe 1 after the update
             let probe_1_fetch = state.probe_at(Sequence(33000)).try_into_complete().unwrap();
@@ -952,7 +964,10 @@ mod state {
             assert_eq!(probe_1_fetch.received, received_1);
             assert_eq!(probe_1_fetch.host, host);
             assert_eq!(probe_1_fetch.sent, sent_1);
-            assert_eq!(probe_1_fetch.icmp_packet_type, IcmpPacketType::TimeExceeded);
+            assert_eq!(
+                probe_1_fetch.icmp_packet_type,
+                IcmpPacketType::TimeExceeded(IcmpPacketCode(1))
+            );
 
             // Validate the TracerState after the update
             assert_eq!(state.round, Round(0));
@@ -1004,7 +1019,14 @@ mod state {
             // Update the state of probe 2 after receiving a TimeExceeded
             let received_2 = SystemTime::now();
             let host = IpAddr::V4(Ipv4Addr::LOCALHOST);
-            state.complete_probe_time_exceeded(Sequence(33001), host, received_2, false, None);
+            state.complete_probe_time_exceeded(
+                Sequence(33001),
+                host,
+                received_2,
+                false,
+                IcmpPacketCode(1),
+                None,
+            );
             let probe_2_recv = state.probe_at(Sequence(33001));
 
             // Validate the TracerState after the update to probe 2
@@ -1029,7 +1051,7 @@ mod state {
             // Update the state of probe 3 after receiving a EchoReply
             let received_3 = SystemTime::now();
             let host = IpAddr::V4(Ipv4Addr::LOCALHOST);
-            state.complete_probe_echo_reply(Sequence(33002), host, received_3);
+            state.complete_probe_echo_reply(Sequence(33002), host, received_3, IcmpPacketCode(0));
             let probe_3_recv = state.probe_at(Sequence(33002));
 
             // Validate the TracerState after the update to probe 3
diff --git a/trippy-config-sample.toml b/trippy-config-sample.toml
index be1795b90..3beeaa37a 100644
--- a/trippy-config-sample.toml
+++ b/trippy-config-sample.toml
@@ -271,6 +271,7 @@ tui-as-mode = "asn"
 #   S - Last probe source port
 #   P - Last probe destination port
 #   T - Last icmp packet type
+#   C - Last icmp packet code
 #
 # The columns will be shown in the order specified.
 tui-custom-columns = "holsravbwdt"


Test patch: