38
38
#include "udp.h"
39
39
#include "ipproto.h"
40
40
#include "mpls.h"
41
+ #include "af.h"
41
42
42
43
/*
43
44
* Interface Control Message Protocol Definitions.
@@ -56,14 +57,28 @@ struct icmp {
56
57
nd_ipv4 ih_gwaddr ; /* ICMP_REDIRECT */
57
58
struct ih_idseq {
58
59
nd_uint16_t icd_id ;
59
- nd_uint16_t icd_seq ;
60
+ union {
61
+ nd_uint16_t icd_seq ;
62
+ struct {
63
+ nd_uint8_t icd_seq_ext ;
64
+ union {
65
+ nd_uint8_t icd_local_ext ;
66
+ struct {
67
+ nd_uint8_t icd_state_ext ;
68
+ } ih_ext_reply_state ;
69
+ } ih_ext_rest ;
70
+ } ih_seq_ext ;
71
+ } ih_seq ;
60
72
} ih_idseq ;
61
73
nd_uint32_t ih_void ;
62
74
} icmp_hun ;
63
75
#define icmp_pptr icmp_hun.ih_pptr
64
76
#define icmp_gwaddr icmp_hun.ih_gwaddr
65
77
#define icmp_id icmp_hun.ih_idseq.icd_id
66
- #define icmp_seq icmp_hun.ih_idseq.icd_seq
78
+ #define icmp_seq icmp_hun.ih_idseq.ih_seq.icd_seq
79
+ #define icmp_seq_ext icmp_hun.ih_idseq.ih_seq.ih_seq_ext.icd_seq_ext
80
+ #define icmp_ext_lbit icmp_hun.ih_idseq.ih_seq.ih_seq_ext.ih_ext_rest.icd_local_ext
81
+ #define icmp_ext_state icmp_hun.ih_idseq.ih_seq.ih_seq_ext.ih_ext_rest.ih_ext_reply_state.icd_state_ext
67
82
#define icmp_void icmp_hun.ih_void
68
83
union {
69
84
struct id_ts {
@@ -143,8 +158,11 @@ struct icmp {
143
158
#define ICMP_IREQREPLY 16 /* information reply */
144
159
#define ICMP_MASKREQ 17 /* address mask request */
145
160
#define ICMP_MASKREPLY 18 /* address mask reply */
161
+ #define ICMP_EXT_ECHO 42 /* IPv4 extended echo request */
162
+ #define ICMP_EXT_ECHOREPLY 43 /* IPv4 extended echo reply */
163
+ #define ICMP_EXT_ECHO_IPV6 160 /* IPv6 extended echo requesti */
164
+ #define ICMP_EXT_ECHOREPLY_IPV6 161 /* IPv6 extended echo reply */
146
165
147
- #define ICMP_MAXTYPE 18
148
166
149
167
#define ICMP_ERRTYPE (type ) \
150
168
((type) == ICMP_UNREACH || (type) == ICMP_SOURCEQUENCH || \
@@ -220,6 +238,51 @@ struct id_rdiscovery {
220
238
nd_uint32_t ird_pref ;
221
239
};
222
240
241
+ struct icmp_ext_header {
242
+ nd_uint8_t icmp_ext_version ;
243
+ nd_uint8_t icmp_ext_reserved ;
244
+ nd_uint16_t icmp_ext_checksum ;
245
+ };
246
+
247
+ #define INTERFACE_NAME 1 /* identifies interface by name */
248
+ #define INTERFACE_INDEX 2 /* identifies interface by index */
249
+ #define INTERFACE_ADDRESS 3 /* identifies interface by address */
250
+
251
+ struct icmp_ext_obj_hdr {
252
+ nd_uint16_t icmp_ext_length ;
253
+ nd_uint8_t icmp_ext_classnum ;
254
+ nd_uint8_t icmp_ext_ctype ;
255
+ };
256
+
257
+ struct icmp_ext_obj_ctype3 { /* When ctype value in ext echo obj header is 3 */
258
+ nd_uint16_t icmp_ext_obj_afi ; /* Address family identifier */
259
+ nd_uint8_t icmp_ext_obj_addrlen ; /* Length of probed address */
260
+ nd_uint8_t icmp_ext_obj_reserved ; /* reserved bits */
261
+ };
262
+
263
+ /* cases for code value of ICMP EXT ECHO Reply */
264
+ #define ICMP_CODE_NOERROR 0 /* no error in response */
265
+ #define ICMP_CODE_MALQUERY 1 /* malformed query */
266
+ #define ICMP_CODE_NOINTERFACE 2 /* no such interface */
267
+ #define ICMP_CODE_NOTABLEENTRY 3 /* no such table entry */
268
+ #define ICMP_CODE_MULTIPLEINTERFACES 4 /* multiple interfaces satisfy query */
269
+
270
+ /* RFC 8335 describes the state field of the ICMP Ext Echo reply as reflecting
271
+ * the state of ARP table or neighbor cache entry associated with the probed
272
+ * interface
273
+ */
274
+ #define STATE_MASK 0xe0 /* masks first 3 bits of last byte in reply */
275
+ #define STATE_RESERVED (0 << 5) /* ignored upon receipt */
276
+ #define STATE_INCOMPLETE (1 << 5)
277
+ #define STATE_REACHABLE (2 << 5)
278
+ #define STATE_STALE (3 << 5)
279
+ #define STATE_DELAY (4 << 5)
280
+ #define STATE_PROBE (5 << 5)
281
+ #define STATE_FAILED (6 << 5)
282
+ #define ABIT_MASK 0x01
283
+ #define ABIT_SET (1 << 7)
284
+
285
+
223
286
/*
224
287
* draft-bonica-internet-icmp-08
225
288
*
@@ -331,7 +394,17 @@ icmp_print(netdissect_options *ndo, const u_char *bp, u_int plen, const u_char *
331
394
GET_BE_U_2 (dp -> icmp_id ),
332
395
GET_BE_U_2 (dp -> icmp_seq ));
333
396
break ;
334
-
397
+
398
+ case ICMP_EXT_ECHO :
399
+ case ICMP_EXT_ECHOREPLY :
400
+ ND_TCHECK_1 (dp -> icmp_seq_ext );
401
+ (void )snprintf (buf , sizeof (buf ), "IPv4 extended echo %s, id %u, seq %u" ,
402
+ icmp_type == ICMP_EXT_ECHO ?
403
+ "request" : "reply" ,
404
+ GET_BE_U_2 (dp -> icmp_id ),
405
+ GET_U_1 (dp -> icmp_seq_ext ));
406
+ break ;
407
+
335
408
case ICMP_UNREACH :
336
409
switch (icmp_code ) {
337
410
@@ -666,6 +739,161 @@ icmp_print(netdissect_options *ndo, const u_char *bp, u_int plen, const u_char *
666
739
/* ndo_protocol reassignment after ip_print() call */
667
740
ndo -> ndo_protocol = "icmp" ;
668
741
742
+ /* print out icmp extended echo request from RFC 8335 */
743
+ if (icmp_type == ICMP_EXT_ECHO ) {
744
+ const struct icmp_ext_header * ext_hdr ;
745
+ ext_hdr = (const struct icmp_ext_header * )& dp -> icmp_data ;
746
+ const struct icmp_ext_obj_hdr * ext_obj_hdr ;
747
+ ext_obj_hdr = (const struct icmp_ext_obj_hdr * )(ext_hdr + 1 );
748
+ const char * payload = (const char * )(ext_obj_hdr + 1 );
749
+ uint8_t ctype = GET_U_1 (ext_obj_hdr -> icmp_ext_ctype );
750
+ uint8_t local = GET_U_1 (dp -> icmp_ext_lbit );
751
+ ND_PRINT (", local %u" , local );
752
+
753
+ if (GET_U_1 (ext_hdr -> icmp_ext_version ) != 0x20 ) { /* error */
754
+ ND_PRINT (", Packet version not supported" );
755
+ return ;
756
+ }
757
+ if (GET_U_1 (ext_hdr -> icmp_ext_reserved ) != 0 ) { /* error */
758
+ ND_PRINT (", Error: Reserved bits of extension header != 0" );
759
+ return ;
760
+
761
+ }
762
+ /* Checking packet length */
763
+ ND_TCHECK_SIZE (ext_obj_hdr );
764
+ uint16_t payloadLen ;
765
+ payloadLen = GET_BE_U_2 (ext_obj_hdr -> icmp_ext_length ) - sizeof (* ext_obj_hdr );
766
+ ND_TCHECK_LEN (ext_obj_hdr , payloadLen );
767
+
768
+ /* validate checksum in extended object header */
769
+ if (ndo -> ndo_vflag ) {
770
+ if (ND_TTEST_LEN (bp , plen )) {
771
+ uint16_t sum ;
772
+
773
+ vec [0 ].ptr = (const uint8_t * )(const void * )ext_hdr ;
774
+ vec [0 ].len = ((const uint8_t * )dp + plen ) - (const uint8_t * )ext_hdr ;
775
+ sum = in_cksum (vec , 1 );
776
+ if (sum != 0 ) {
777
+ uint16_t icmp_sum = GET_BE_U_2 (ext_hdr -> icmp_ext_checksum );
778
+ ND_PRINT (" (wrong icmp ext cksum %x (->%x)!)" ,
779
+ icmp_sum ,
780
+ in_cksum_shouldbe (icmp_sum , sum ));
781
+ }
782
+ }
783
+ }
784
+ switch (ctype ) {
785
+ case INTERFACE_NAME : /* identifies interface by name */
786
+ if (local ) {
787
+ ND_PRINT (", Type 1: Address Name %.*s" , payloadLen , payload );
788
+ } else {
789
+ ND_PRINT (", Error: Must identify interface by address if local unset" );
790
+ }
791
+ break ;
792
+
793
+ case INTERFACE_INDEX : /* identifies interface by index */
794
+ {
795
+ uint32_t ifIndex = GET_BE_U_4 ((const uint32_t * )payload );
796
+ if (local ) {
797
+ ND_PRINT (", Type 2: Address Index %u" , ifIndex );
798
+ } else {
799
+ ND_PRINT (", Error: Must identify interface by address if local unset" );
800
+ }
801
+ break ;
802
+ }
803
+ case INTERFACE_ADDRESS : /* identifies interface by address */
804
+ {
805
+ const struct icmp_ext_obj_ctype3 * ext_obj_ctype3 ;
806
+ ext_obj_ctype3 = (const struct icmp_ext_obj_ctype3 * )(ext_obj_hdr + 1 );
807
+ uint16_t afi = GET_BE_U_2 ((const uint16_t * )payload );
808
+ const char * name = tok2str (af_values , "Unknown" , afi );
809
+ const int * addr = (const int * )(ext_obj_ctype3 + 1 );
810
+
811
+ switch (afi ) {
812
+ case AFNUM_INET :
813
+ {
814
+ ND_PRINT (", Type 3: Address %s %s" , name , GET_IPADDR_STRING (addr ));
815
+ break ;
816
+ }
817
+ case AFNUM_INET6 :
818
+ ND_PRINT (", Type 3: Address %s %s" , name , GET_IP6ADDR_STRING (addr ));
819
+ break ;
820
+ default :
821
+ ND_PRINT (", Unknown name: %s" , name );
822
+ break ;
823
+ }
824
+ break ;
825
+ default :
826
+ printf ("Unrecognized ctype value" );
827
+ break ;
828
+ }
829
+ }
830
+ }
831
+
832
+ /* decode icmp ext echo reply */
833
+ if (icmp_type == ICMP_EXT_ECHOREPLY ) {
834
+ uint8_t reply_state = GET_U_1 (dp -> icmp_ext_state );
835
+ if (icmp_code != 0 ) {
836
+ switch (icmp_code ) {
837
+ case ICMP_CODE_MALQUERY :
838
+ ND_PRINT (", Error: Malformed Query" );
839
+ break ;
840
+ case ICMP_CODE_NOINTERFACE :
841
+ ND_PRINT (", Error: No such interface" );
842
+ break ;
843
+ case ICMP_CODE_NOTABLEENTRY :
844
+ ND_PRINT (", Error: No such table entry" );
845
+ break ;
846
+ case ICMP_CODE_MULTIPLEINTERFACES :
847
+ ND_PRINT (", Error: Multiple interfaces satisfy query" );
848
+ break ;
849
+ default :
850
+ ND_PRINT (", Error: Code value not recognized" );
851
+ break ;
852
+ }
853
+ if ((reply_state & STATE_MASK ) == 0 ) {
854
+ ND_PRINT (", Error: State not zero while code was zero" );
855
+ }
856
+ } else {
857
+ ND_PRINT (", Reply recognized" );
858
+ switch (reply_state & STATE_MASK ) {
859
+ case STATE_RESERVED :
860
+ ND_PRINT (", State 0: Disregarded" );
861
+ break ;
862
+ case STATE_INCOMPLETE :
863
+ ND_PRINT (", State: Incomplete" );
864
+ break ;
865
+ case STATE_REACHABLE :
866
+ ND_PRINT (", State: Reachable" );
867
+ break ;
868
+ case STATE_STALE :
869
+ ND_PRINT (", State: Stale" );
870
+ break ;
871
+ case STATE_DELAY :
872
+ ND_PRINT (", State: delay" );
873
+ break ;
874
+ case STATE_PROBE :
875
+ ND_PRINT (", State: probe" );
876
+ break ;
877
+ case STATE_FAILED :
878
+ ND_PRINT (", State: Failed" );
879
+ break ;
880
+ default :
881
+ ND_PRINT (", State: Unknown" );
882
+ break ;
883
+ }
884
+
885
+ if ((reply_state & (1 << 2 )) != 0 ) {
886
+ ND_PRINT (", A-bit: %d" , 1 );
887
+ if ((reply_state & (1 << 1 )) != 0 ) {
888
+ ND_PRINT (", 4-bit: %d" , 1 );
889
+ }
890
+ if ((reply_state & 1 ) != 0 ) {
891
+ ND_PRINT (", 6-bit: %d" , 1 );
892
+ }
893
+ }
894
+ }
895
+ }
896
+
669
897
/*
670
898
* Attempt to decode the MPLS extensions only for some ICMP types.
671
899
*/
@@ -772,3 +1000,4 @@ icmp_print(netdissect_options *ndo, const u_char *bp, u_int plen, const u_char *
772
1000
trunc :
773
1001
nd_print_trunc (ndo );
774
1002
}
1003
+
0 commit comments