Skip to content

Commit 6ef7209

Browse files
committed
ICMP: Implemented RFC 8337, Extended Echo Request/Reply
1 parent 2bfa05b commit 6ef7209

File tree

3 files changed

+246
-5
lines changed

3 files changed

+246
-5
lines changed

configure

+13-1
Original file line numberDiff line numberDiff line change
@@ -676,6 +676,7 @@ infodir
676676
docdir
677677
oldincludedir
678678
includedir
679+
runstatedir
679680
localstatedir
680681
sharedstatedir
681682
sysconfdir
@@ -756,6 +757,7 @@ datadir='${datarootdir}'
756757
sysconfdir='${prefix}/etc'
757758
sharedstatedir='${prefix}/com'
758759
localstatedir='${prefix}/var'
760+
runstatedir='${localstatedir}/run'
759761
includedir='${prefix}/include'
760762
oldincludedir='/usr/include'
761763
docdir='${datarootdir}/doc/${PACKAGE_TARNAME}'
@@ -1008,6 +1010,15 @@ do
10081010
| -silent | --silent | --silen | --sile | --sil)
10091011
silent=yes ;;
10101012

1013+
-runstatedir | --runstatedir | --runstatedi | --runstated \
1014+
| --runstate | --runstat | --runsta | --runst | --runs \
1015+
| --run | --ru | --r)
1016+
ac_prev=runstatedir ;;
1017+
-runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \
1018+
| --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \
1019+
| --run=* | --ru=* | --r=*)
1020+
runstatedir=$ac_optarg ;;
1021+
10111022
-sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
10121023
ac_prev=sbindir ;;
10131024
-sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
@@ -1145,7 +1156,7 @@ fi
11451156
for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \
11461157
datadir sysconfdir sharedstatedir localstatedir includedir \
11471158
oldincludedir docdir infodir htmldir dvidir pdfdir psdir \
1148-
libdir localedir mandir
1159+
libdir localedir mandir runstatedir
11491160
do
11501161
eval ac_val=\$$ac_var
11511162
# Remove trailing slashes.
@@ -1298,6 +1309,7 @@ Fine tuning of the installation directories:
12981309
--sysconfdir=DIR read-only single-machine data [PREFIX/etc]
12991310
--sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com]
13001311
--localstatedir=DIR modifiable single-machine data [PREFIX/var]
1312+
--runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run]
13011313
--libdir=DIR object code libraries [EPREFIX/lib]
13021314
--includedir=DIR C header files [PREFIX/include]
13031315
--oldincludedir=DIR C header files for non-gcc [/usr/include]

print-icmp.c

+233-4
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
#include "udp.h"
3939
#include "ipproto.h"
4040
#include "mpls.h"
41+
#include "af.h"
4142

4243
/*
4344
* Interface Control Message Protocol Definitions.
@@ -56,14 +57,28 @@ struct icmp {
5657
nd_ipv4 ih_gwaddr; /* ICMP_REDIRECT */
5758
struct ih_idseq {
5859
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;
6072
} ih_idseq;
6173
nd_uint32_t ih_void;
6274
} icmp_hun;
6375
#define icmp_pptr icmp_hun.ih_pptr
6476
#define icmp_gwaddr icmp_hun.ih_gwaddr
6577
#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
6782
#define icmp_void icmp_hun.ih_void
6883
union {
6984
struct id_ts {
@@ -143,8 +158,11 @@ struct icmp {
143158
#define ICMP_IREQREPLY 16 /* information reply */
144159
#define ICMP_MASKREQ 17 /* address mask request */
145160
#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 */
146165

147-
#define ICMP_MAXTYPE 18
148166

149167
#define ICMP_ERRTYPE(type) \
150168
((type) == ICMP_UNREACH || (type) == ICMP_SOURCEQUENCH || \
@@ -220,6 +238,51 @@ struct id_rdiscovery {
220238
nd_uint32_t ird_pref;
221239
};
222240

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+
223286
/*
224287
* draft-bonica-internet-icmp-08
225288
*
@@ -331,7 +394,17 @@ icmp_print(netdissect_options *ndo, const u_char *bp, u_int plen, const u_char *
331394
GET_BE_U_2(dp->icmp_id),
332395
GET_BE_U_2(dp->icmp_seq));
333396
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+
335408
case ICMP_UNREACH:
336409
switch (icmp_code) {
337410

@@ -666,6 +739,161 @@ icmp_print(netdissect_options *ndo, const u_char *bp, u_int plen, const u_char *
666739
/* ndo_protocol reassignment after ip_print() call */
667740
ndo->ndo_protocol = "icmp";
668741

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+
669897
/*
670898
* Attempt to decode the MPLS extensions only for some ICMP types.
671899
*/
@@ -772,3 +1000,4 @@ icmp_print(netdissect_options *ndo, const u_char *bp, u_int plen, const u_char *
7721000
trunc:
7731001
nd_print_trunc(ndo);
7741002
}
1003+

tests/icmp-ext-ipv4.pcap

300 Bytes
Binary file not shown.

0 commit comments

Comments
 (0)