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,8 @@ 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 */
146
-
147
- #define ICMP_MAXTYPE 18
161
+ #define ICMP_EXT_ECHO 42 /* IPv4 extended echo request */
162
+ #define ICMP_EXT_ECHOREPLY 43 /* IPv4 extended echo reply */
148
163
149
164
#define ICMP_ERRTYPE (type ) \
150
165
((type) == ICMP_UNREACH || (type) == ICMP_SOURCEQUENCH || \
@@ -220,6 +235,51 @@ struct id_rdiscovery {
220
235
nd_uint32_t ird_pref ;
221
236
};
222
237
238
+ struct icmp_ext_header {
239
+ nd_uint8_t icmp_ext_version ;
240
+ nd_uint8_t icmp_ext_reserved ;
241
+ nd_uint16_t icmp_ext_checksum ;
242
+ };
243
+
244
+ #define INTERFACE_NAME 1 /* identifies interface by name */
245
+ #define INTERFACE_INDEX 2 /* identifies interface by index */
246
+ #define INTERFACE_ADDRESS 3 /* identifies interface by address */
247
+
248
+ struct icmp_ext_obj_hdr {
249
+ nd_uint16_t icmp_ext_length ;
250
+ nd_uint8_t icmp_ext_classnum ;
251
+ nd_uint8_t icmp_ext_ctype ;
252
+ };
253
+
254
+ struct icmp_ext_obj_ctype3 { /* When ctype value in ext echo obj header is 3 */
255
+ nd_uint16_t icmp_ext_obj_afi ; /* Address family identifier */
256
+ nd_uint8_t icmp_ext_obj_addrlen ; /* Length of probed address */
257
+ nd_uint8_t icmp_ext_obj_reserved ; /* reserved bits */
258
+ };
259
+
260
+ /* cases for code value of ICMP EXT ECHO Reply */
261
+ #define ICMP_CODE_NOERROR 0 /* no error in response */
262
+ #define ICMP_CODE_MALQUERY 1 /* malformed query */
263
+ #define ICMP_CODE_NOINTERFACE 2 /* no such interface */
264
+ #define ICMP_CODE_NOTABLEENTRY 3 /* no such table entry */
265
+ #define ICMP_CODE_MULTIPLEINTERFACES 4 /* multiple interfaces satisfy query */
266
+
267
+ /* RFC 8335 describes the state field of the ICMP Ext Echo reply as reflecting
268
+ * the state of ARP table or neighbor cache entry associated with the probed
269
+ * interface
270
+ */
271
+ #define STATE_MASK 0xe0 /* masks first 3 bits of last byte in reply */
272
+ #define STATE_RESERVED (0 << 5) /* ignored upon receipt */
273
+ #define STATE_INCOMPLETE (1 << 5)
274
+ #define STATE_REACHABLE (2 << 5)
275
+ #define STATE_STALE (3 << 5)
276
+ #define STATE_DELAY (4 << 5)
277
+ #define STATE_PROBE (5 << 5)
278
+ #define STATE_FAILED (6 << 5)
279
+ #define ABIT_MASK 0x01
280
+ #define ABIT_SET (1 << 7)
281
+
282
+
223
283
/*
224
284
* draft-bonica-internet-icmp-08
225
285
*
@@ -330,7 +390,17 @@ icmp_print(netdissect_options *ndo, const u_char *bp, u_int plen, const u_char *
330
390
GET_BE_U_2 (dp -> icmp_id ),
331
391
GET_BE_U_2 (dp -> icmp_seq ));
332
392
break ;
333
-
393
+
394
+ case ICMP_EXT_ECHO :
395
+ case ICMP_EXT_ECHOREPLY :
396
+ ND_TCHECK_1 (dp -> icmp_seq_ext );
397
+ (void )snprintf (buf , sizeof (buf ), "IPv4 extended echo %s, id %u, seq %u" ,
398
+ icmp_type == ICMP_EXT_ECHO ?
399
+ "request" : "reply" ,
400
+ GET_BE_U_2 (dp -> icmp_id ),
401
+ GET_U_1 (dp -> icmp_seq_ext ));
402
+ break ;
403
+
334
404
case ICMP_UNREACH :
335
405
switch (icmp_code ) {
336
406
@@ -662,6 +732,161 @@ icmp_print(netdissect_options *ndo, const u_char *bp, u_int plen, const u_char *
662
732
/* ndo_protocol reassignment after ip_print() call */
663
733
ndo -> ndo_protocol = "icmp" ;
664
734
735
+ /* print out icmp extended echo request from RFC 8335 */
736
+ if (icmp_type == ICMP_EXT_ECHO ) {
737
+ const struct icmp_ext_header * ext_hdr ;
738
+ ext_hdr = (const struct icmp_ext_header * )& dp -> icmp_data ;
739
+ const struct icmp_ext_obj_hdr * ext_obj_hdr ;
740
+ ext_obj_hdr = (const struct icmp_ext_obj_hdr * )(ext_hdr + 1 );
741
+ const char * payload = (const char * )(ext_obj_hdr + 1 );
742
+ uint8_t ctype = GET_U_1 (ext_obj_hdr -> icmp_ext_ctype );
743
+ uint8_t local = GET_U_1 (dp -> icmp_ext_lbit );
744
+ ND_PRINT (", local %u" , local );
745
+
746
+ if (GET_U_1 (ext_hdr -> icmp_ext_version ) != 0x20 ) { /* error */
747
+ ND_PRINT (", Packet version not supported" );
748
+ return ;
749
+ }
750
+ if (GET_U_1 (ext_hdr -> icmp_ext_reserved ) != 0 ) { /* error */
751
+ ND_PRINT (", Error: Reserved bits of extension header != 0" );
752
+ return ;
753
+
754
+ }
755
+ /* Checking packet length */
756
+ ND_TCHECK_SIZE (ext_obj_hdr );
757
+ uint16_t payloadLen ;
758
+ payloadLen = GET_BE_U_2 (ext_obj_hdr -> icmp_ext_length ) - sizeof (* ext_obj_hdr );
759
+ ND_TCHECK_LEN (ext_obj_hdr , payloadLen );
760
+
761
+ /* validate checksum in extended object header */
762
+ if (ndo -> ndo_vflag ) {
763
+ if (ND_TTEST_LEN (bp , plen )) {
764
+ uint16_t sum ;
765
+
766
+ vec [0 ].ptr = (const uint8_t * )(const void * )ext_hdr ;
767
+ vec [0 ].len = ((const uint8_t * )dp + plen ) - (const uint8_t * )ext_hdr ;
768
+ sum = in_cksum (vec , 1 );
769
+ if (sum != 0 ) {
770
+ uint16_t icmp_sum = GET_BE_U_2 (ext_hdr -> icmp_ext_checksum );
771
+ ND_PRINT (" (wrong icmp ext cksum %x (->%x)!)" ,
772
+ icmp_sum ,
773
+ in_cksum_shouldbe (icmp_sum , sum ));
774
+ }
775
+ }
776
+ }
777
+ switch (ctype ) {
778
+ case INTERFACE_NAME : /* identifies interface by name */
779
+ if (local ) {
780
+ ND_PRINT (", Type 1: Address Name %.*s" , payloadLen , payload );
781
+ } else {
782
+ ND_PRINT (", Error: Must identify interface by address if local unset" );
783
+ }
784
+ break ;
785
+
786
+ case INTERFACE_INDEX : /* identifies interface by index */
787
+ {
788
+ uint32_t ifIndex = GET_BE_U_4 ((const uint32_t * )payload );
789
+ if (local ) {
790
+ ND_PRINT (", Type 2: Address Index %u" , ifIndex );
791
+ } else {
792
+ ND_PRINT (", Error: Must identify interface by address if local unset" );
793
+ }
794
+ break ;
795
+ }
796
+ case INTERFACE_ADDRESS : /* identifies interface by address */
797
+ {
798
+ const struct icmp_ext_obj_ctype3 * ext_obj_ctype3 ;
799
+ ext_obj_ctype3 = (const struct icmp_ext_obj_ctype3 * )(ext_obj_hdr + 1 );
800
+ uint16_t afi = GET_BE_U_2 ((const uint16_t * )payload );
801
+ const char * name = tok2str (af_values , "Unknown" , afi );
802
+ const int * addr = (const int * )(ext_obj_ctype3 + 1 );
803
+
804
+ switch (afi ) {
805
+ case AFNUM_INET :
806
+ {
807
+ ND_PRINT (", Type 3: Address %s %s" , name , GET_IPADDR_STRING (addr ));
808
+ break ;
809
+ }
810
+ case AFNUM_INET6 :
811
+ ND_PRINT (", Type 3: Address %s %s" , name , GET_IP6ADDR_STRING (addr ));
812
+ break ;
813
+ default :
814
+ ND_PRINT (", Unknown name: %s" , name );
815
+ break ;
816
+ }
817
+ break ;
818
+ default :
819
+ printf ("Unrecognized ctype value" );
820
+ break ;
821
+ }
822
+ }
823
+ }
824
+
825
+ /* decode icmp ext echo reply */
826
+ if (icmp_type == ICMP_EXT_ECHOREPLY ) {
827
+ uint8_t reply_state = GET_U_1 (dp -> icmp_ext_state );
828
+ if (icmp_code != 0 ) {
829
+ switch (icmp_code ) {
830
+ case ICMP_CODE_MALQUERY :
831
+ ND_PRINT (", Error: Malformed Query" );
832
+ break ;
833
+ case ICMP_CODE_NOINTERFACE :
834
+ ND_PRINT (", Error: No such interface" );
835
+ break ;
836
+ case ICMP_CODE_NOTABLEENTRY :
837
+ ND_PRINT (", Error: No such table entry" );
838
+ break ;
839
+ case ICMP_CODE_MULTIPLEINTERFACES :
840
+ ND_PRINT (", Error: Multiple interfaces satisfy query" );
841
+ break ;
842
+ default :
843
+ ND_PRINT (", Error: Code value not recognized" );
844
+ break ;
845
+ }
846
+ if ((reply_state & STATE_MASK ) == 0 ) {
847
+ ND_PRINT (", Error: State not zero while code was zero" );
848
+ }
849
+ } else {
850
+ ND_PRINT (", Reply recognized" );
851
+ switch (reply_state & STATE_MASK ) {
852
+ case STATE_RESERVED :
853
+ ND_PRINT (", State 0: Disregarded" );
854
+ break ;
855
+ case STATE_INCOMPLETE :
856
+ ND_PRINT (", State: Incomplete" );
857
+ break ;
858
+ case STATE_REACHABLE :
859
+ ND_PRINT (", State: Reachable" );
860
+ break ;
861
+ case STATE_STALE :
862
+ ND_PRINT (", State: Stale" );
863
+ break ;
864
+ case STATE_DELAY :
865
+ ND_PRINT (", State: delay" );
866
+ break ;
867
+ case STATE_PROBE :
868
+ ND_PRINT (", State: probe" );
869
+ break ;
870
+ case STATE_FAILED :
871
+ ND_PRINT (", State: Failed" );
872
+ break ;
873
+ default :
874
+ ND_PRINT (", State: Unknown" );
875
+ break ;
876
+ }
877
+
878
+ if ((reply_state & (1 << 2 )) != 0 ) {
879
+ ND_PRINT (", A-bit: %d" , 1 );
880
+ if ((reply_state & (1 << 1 )) != 0 ) {
881
+ ND_PRINT (", 4-bit: %d" , 1 );
882
+ }
883
+ if ((reply_state & 1 ) != 0 ) {
884
+ ND_PRINT (", 6-bit: %d" , 1 );
885
+ }
886
+ }
887
+ }
888
+ }
889
+
665
890
/*
666
891
* Attempt to decode the MPLS extensions only for some ICMP types.
667
892
*/
@@ -768,3 +993,4 @@ icmp_print(netdissect_options *ndo, const u_char *bp, u_int plen, const u_char *
768
993
trunc :
769
994
nd_print_trunc (ndo );
770
995
}
996
+
0 commit comments