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
*
@@ -330,7 +393,17 @@ icmp_print(netdissect_options *ndo, const u_char *bp, u_int plen, const u_char *
330
393
GET_BE_U_2 (dp -> icmp_id ),
331
394
GET_BE_U_2 (dp -> icmp_seq ));
332
395
break ;
333
-
396
+
397
+ case ICMP_EXT_ECHO :
398
+ case ICMP_EXT_ECHOREPLY :
399
+ ND_TCHECK_1 (dp -> icmp_seq_ext );
400
+ (void )snprintf (buf , sizeof (buf ), "IPv4 extended echo %s, id %u, seq %u" ,
401
+ icmp_type == ICMP_EXT_ECHO ?
402
+ "request" : "reply" ,
403
+ GET_BE_U_2 (dp -> icmp_id ),
404
+ GET_U_1 (dp -> icmp_seq_ext ));
405
+ break ;
406
+
334
407
case ICMP_UNREACH :
335
408
switch (icmp_code ) {
336
409
@@ -662,6 +735,161 @@ icmp_print(netdissect_options *ndo, const u_char *bp, u_int plen, const u_char *
662
735
/* ndo_protocol reassignment after ip_print() call */
663
736
ndo -> ndo_protocol = "icmp" ;
664
737
738
+ /* print out icmp extended echo request from RFC 8335 */
739
+ if (icmp_type == ICMP_EXT_ECHO ) {
740
+ const struct icmp_ext_header * ext_hdr ;
741
+ ext_hdr = (const struct icmp_ext_header * )& dp -> icmp_data ;
742
+ const struct icmp_ext_obj_hdr * ext_obj_hdr ;
743
+ ext_obj_hdr = (const struct icmp_ext_obj_hdr * )(ext_hdr + 1 );
744
+ const char * payload = (const char * )(ext_obj_hdr + 1 );
745
+ uint8_t ctype = GET_U_1 (ext_obj_hdr -> icmp_ext_ctype );
746
+ uint8_t local = GET_U_1 (dp -> icmp_ext_lbit );
747
+ ND_PRINT (", local %u" , local );
748
+
749
+ if (GET_U_1 (ext_hdr -> icmp_ext_version ) != 0x20 ) { /* error */
750
+ ND_PRINT (", Packet version not supported" );
751
+ return ;
752
+ }
753
+ if (GET_U_1 (ext_hdr -> icmp_ext_reserved ) != 0 ) { /* error */
754
+ ND_PRINT (", Error: Reserved bits of extension header != 0" );
755
+ return ;
756
+
757
+ }
758
+ /* Checking packet length */
759
+ ND_TCHECK_SIZE (ext_obj_hdr );
760
+ uint16_t payloadLen ;
761
+ payloadLen = GET_BE_U_2 (ext_obj_hdr -> icmp_ext_length ) - sizeof (* ext_obj_hdr );
762
+ ND_TCHECK_LEN (ext_obj_hdr , payloadLen );
763
+
764
+ /* validate checksum in extended object header */
765
+ if (ndo -> ndo_vflag ) {
766
+ if (ND_TTEST_LEN (bp , plen )) {
767
+ uint16_t sum ;
768
+
769
+ vec [0 ].ptr = (const uint8_t * )(const void * )ext_hdr ;
770
+ vec [0 ].len = ((const uint8_t * )dp + plen ) - (const uint8_t * )ext_hdr ;
771
+ sum = in_cksum (vec , 1 );
772
+ if (sum != 0 ) {
773
+ uint16_t icmp_sum = GET_BE_U_2 (ext_hdr -> icmp_ext_checksum );
774
+ ND_PRINT (" (wrong icmp ext cksum %x (->%x)!)" ,
775
+ icmp_sum ,
776
+ in_cksum_shouldbe (icmp_sum , sum ));
777
+ }
778
+ }
779
+ }
780
+ switch (ctype ) {
781
+ case INTERFACE_NAME : /* identifies interface by name */
782
+ if (local ) {
783
+ ND_PRINT (", Type 1: Address Name %.*s" , payloadLen , payload );
784
+ } else {
785
+ ND_PRINT (", Error: Must identify interface by address if local unset" );
786
+ }
787
+ break ;
788
+
789
+ case INTERFACE_INDEX : /* identifies interface by index */
790
+ {
791
+ uint32_t ifIndex = GET_BE_U_4 ((const uint32_t * )payload );
792
+ if (local ) {
793
+ ND_PRINT (", Type 2: Address Index %u" , ifIndex );
794
+ } else {
795
+ ND_PRINT (", Error: Must identify interface by address if local unset" );
796
+ }
797
+ break ;
798
+ }
799
+ case INTERFACE_ADDRESS : /* identifies interface by address */
800
+ {
801
+ const struct icmp_ext_obj_ctype3 * ext_obj_ctype3 ;
802
+ ext_obj_ctype3 = (const struct icmp_ext_obj_ctype3 * )(ext_obj_hdr + 1 );
803
+ uint16_t afi = GET_BE_U_2 ((const uint16_t * )payload );
804
+ const char * name = tok2str (af_values , "Unknown" , afi );
805
+ const int * addr = (const int * )(ext_obj_ctype3 + 1 );
806
+
807
+ switch (afi ) {
808
+ case AFNUM_INET :
809
+ {
810
+ ND_PRINT (", Type 3: Address %s %s" , name , GET_IPADDR_STRING (addr ));
811
+ break ;
812
+ }
813
+ case AFNUM_INET6 :
814
+ ND_PRINT (", Type 3: Address %s %s" , name , GET_IP6ADDR_STRING (addr ));
815
+ break ;
816
+ default :
817
+ ND_PRINT (", Unknown name: %s" , name );
818
+ break ;
819
+ }
820
+ break ;
821
+ default :
822
+ printf ("Unrecognized ctype value" );
823
+ break ;
824
+ }
825
+ }
826
+ }
827
+
828
+ /* decode icmp ext echo reply */
829
+ if (icmp_type == ICMP_EXT_ECHOREPLY ) {
830
+ uint8_t reply_state = GET_U_1 (dp -> icmp_ext_state );
831
+ if (icmp_code != 0 ) {
832
+ switch (icmp_code ) {
833
+ case ICMP_CODE_MALQUERY :
834
+ ND_PRINT (", Error: Malformed Query" );
835
+ break ;
836
+ case ICMP_CODE_NOINTERFACE :
837
+ ND_PRINT (", Error: No such interface" );
838
+ break ;
839
+ case ICMP_CODE_NOTABLEENTRY :
840
+ ND_PRINT (", Error: No such table entry" );
841
+ break ;
842
+ case ICMP_CODE_MULTIPLEINTERFACES :
843
+ ND_PRINT (", Error: Multiple interfaces satisfy query" );
844
+ break ;
845
+ default :
846
+ ND_PRINT (", Error: Code value not recognized" );
847
+ break ;
848
+ }
849
+ if ((reply_state & STATE_MASK ) == 0 ) {
850
+ ND_PRINT (", Error: State not zero while code was zero" );
851
+ }
852
+ } else {
853
+ ND_PRINT (", Reply recognized" );
854
+ switch (reply_state & STATE_MASK ) {
855
+ case STATE_RESERVED :
856
+ ND_PRINT (", State 0: Disregarded" );
857
+ break ;
858
+ case STATE_INCOMPLETE :
859
+ ND_PRINT (", State: Incomplete" );
860
+ break ;
861
+ case STATE_REACHABLE :
862
+ ND_PRINT (", State: Reachable" );
863
+ break ;
864
+ case STATE_STALE :
865
+ ND_PRINT (", State: Stale" );
866
+ break ;
867
+ case STATE_DELAY :
868
+ ND_PRINT (", State: delay" );
869
+ break ;
870
+ case STATE_PROBE :
871
+ ND_PRINT (", State: probe" );
872
+ break ;
873
+ case STATE_FAILED :
874
+ ND_PRINT (", State: Failed" );
875
+ break ;
876
+ default :
877
+ ND_PRINT (", State: Unknown" );
878
+ break ;
879
+ }
880
+
881
+ if ((reply_state & (1 << 2 )) != 0 ) {
882
+ ND_PRINT (", A-bit: %d" , 1 );
883
+ if ((reply_state & (1 << 1 )) != 0 ) {
884
+ ND_PRINT (", 4-bit: %d" , 1 );
885
+ }
886
+ if ((reply_state & 1 ) != 0 ) {
887
+ ND_PRINT (", 6-bit: %d" , 1 );
888
+ }
889
+ }
890
+ }
891
+ }
892
+
665
893
/*
666
894
* Attempt to decode the MPLS extensions only for some ICMP types.
667
895
*/
@@ -768,3 +996,4 @@ icmp_print(netdissect_options *ndo, const u_char *bp, u_int plen, const u_char *
768
996
trunc :
769
997
nd_print_trunc (ndo );
770
998
}
999
+
0 commit comments