print-icmp6.c (127668) | print-icmp6.c (146773) |
---|---|
1/* 2 * Copyright (c) 1988, 1989, 1990, 1991, 1993, 1994 3 * The Regents of the University of California. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that: (1) source code distributions 7 * retain the above copyright notice and this paragraph in its entirety, (2) 8 * distributions including binary code include the above copyright notice and --- 7 unchanged lines hidden (view full) --- 16 * written permission. 17 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED 18 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF 19 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 20 */ 21 22#ifndef lint 23static const char rcsid[] _U_ = | 1/* 2 * Copyright (c) 1988, 1989, 1990, 1991, 1993, 1994 3 * The Regents of the University of California. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that: (1) source code distributions 7 * retain the above copyright notice and this paragraph in its entirety, (2) 8 * distributions including binary code include the above copyright notice and --- 7 unchanged lines hidden (view full) --- 16 * written permission. 17 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED 18 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF 19 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 20 */ 21 22#ifndef lint 23static const char rcsid[] _U_ = |
24 "@(#) $Header: /tcpdump/master/tcpdump/print-icmp6.c,v 1.72.2.4 2004/03/24 00:14:09 guy Exp $"; | 24 "@(#) $Header: /tcpdump/master/tcpdump/print-icmp6.c,v 1.79 2005/01/14 10:41:50 hannes Exp $"; |
25#endif 26 27#ifdef HAVE_CONFIG_H 28#include "config.h" 29#endif 30 31#ifdef INET6 32 --- 13 unchanged lines hidden (view full) --- 46#include "udp.h" 47#include "ah.h" 48 49static const char *get_rtpref(u_int); 50static const char *get_lifetime(u_int32_t); 51static void print_lladdr(const u_char *, size_t); 52static void icmp6_opt_print(const u_char *, int); 53static void mld6_print(const u_char *); | 25#endif 26 27#ifdef HAVE_CONFIG_H 28#include "config.h" 29#endif 30 31#ifdef INET6 32 --- 13 unchanged lines hidden (view full) --- 46#include "udp.h" 47#include "ah.h" 48 49static const char *get_rtpref(u_int); 50static const char *get_lifetime(u_int32_t); 51static void print_lladdr(const u_char *, size_t); 52static void icmp6_opt_print(const u_char *, int); 53static void mld6_print(const u_char *); |
54static void mldv2_report_print(const u_char *, u_int); 55static void mldv2_query_print(const u_char *, u_int); |
|
54static struct udphdr *get_upperlayer(u_char *, u_int *); 55static void dnsname_print(const u_char *, const u_char *); 56static void icmp6_nodeinfo_print(u_int, const u_char *, const u_char *); 57static void icmp6_rrenum_print(const u_char *, const u_char *); 58 59#ifndef abs 60#define abs(a) ((0 < (a)) ? (a) : -(a)) 61#endif 62 | 56static struct udphdr *get_upperlayer(u_char *, u_int *); 57static void dnsname_print(const u_char *, const u_char *); 58static void icmp6_nodeinfo_print(u_int, const u_char *, const u_char *); 59static void icmp6_rrenum_print(const u_char *, const u_char *); 60 61#ifndef abs 62#define abs(a) ((0 < (a)) ? (a) : -(a)) 63#endif 64 |
65static struct tok icmp6_type_values[] = { 66 { ICMP6_DST_UNREACH, "destination unreachable"}, 67 { ICMP6_PACKET_TOO_BIG, "packet too big"}, 68 { ICMP6_TIME_EXCEEDED, "time exceeded in-transit"}, 69 { ICMP6_PARAM_PROB, "parameter problem"}, 70 { ICMP6_ECHO_REQUEST, "echo request"}, 71 { ICMP6_ECHO_REPLY, "echo reply"}, 72 { MLD6_LISTENER_QUERY, "multicast listener query "}, 73 { MLD6_LISTENER_REPORT, "multicast listener report "}, 74 { MLD6_LISTENER_DONE, "multicast listener done "}, 75 { ND_ROUTER_SOLICIT, "router solicitation "}, 76 { ND_ROUTER_ADVERT, "router advertisement"}, 77 { ND_NEIGHBOR_SOLICIT, "neighbor solicitation"}, 78 { ND_NEIGHBOR_ADVERT, "neighbor advertisment"}, 79 { ND_REDIRECT, "redirect"}, 80 { ICMP6_ROUTER_RENUMBERING, "router renumbering"}, 81 { IND_SOLICIT, "inverse neighbor solicitation"}, 82 { IND_ADVERT, "inverse neighbor advertisement"}, 83 { MLDV2_LISTENER_REPORT, "multicast listener report v2 "}, 84 { ICMP6_HADISCOV_REQUEST, "ha discovery request"}, 85 { ICMP6_HADISCOV_REPLY, "ha discovery reply"}, 86 { ICMP6_MOBILEPREFIX_SOLICIT, "mobile router solicitation"}, 87 { ICMP6_MOBILEPREFIX_ADVERT, "mobile router advertisement"}, 88 { ICMP6_WRUREQUEST, "who-are-you request"}, 89 { ICMP6_WRUREPLY, "who-are-you reply"}, 90 { ICMP6_NI_QUERY, "node information query"}, 91 { ICMP6_NI_REPLY, "node information reply"}, 92 { MLD6_MTRACE, "mtrace message"}, 93 { MLD6_MTRACE_RESP, "mtrace response"}, 94 { 0, NULL } 95}; 96 97static struct tok icmp6_dst_unreach_code_values[] = { 98 { ICMP6_DST_UNREACH_NOROUTE, "unreachable route" }, 99 { ICMP6_DST_UNREACH_ADMIN, " unreachable prohibited"}, 100 { ICMP6_DST_UNREACH_BEYONDSCOPE, "beyond scope"}, 101 { ICMP6_DST_UNREACH_ADDR, "unreachable address"}, 102 { ICMP6_DST_UNREACH_NOPORT, "unreachable port"}, 103 { 0, NULL } 104}; 105 106static struct tok icmp6_opt_pi_flag_values[] = { 107 { ND_OPT_PI_FLAG_ONLINK, "onlink" }, 108 { ND_OPT_PI_FLAG_AUTO, "auto" }, 109 { ND_OPT_PI_FLAG_ROUTER, "router" }, 110 { 0, NULL } 111}; 112 113static struct tok icmp6_opt_ra_flag_values[] = { 114 { ND_RA_FLAG_MANAGED, "managed" }, 115 { ND_RA_FLAG_OTHER, "other stateful"}, 116 { ND_RA_FLAG_HOME_AGENT, "home agent"}, 117 { 0, NULL } 118}; 119 120static struct tok icmp6_nd_na_flag_values[] = { 121 { ND_NA_FLAG_ROUTER, "router" }, 122 { ND_NA_FLAG_SOLICITED, "solicited" }, 123 { ND_NA_FLAG_OVERRIDE, "override" }, 124 { 0, NULL } 125}; 126 127 128static struct tok icmp6_opt_values[] = { 129 { ND_OPT_SOURCE_LINKADDR, "source link-address"}, 130 { ND_OPT_TARGET_LINKADDR, "destination link-address"}, 131 { ND_OPT_PREFIX_INFORMATION, "prefix info"}, 132 { ND_OPT_REDIRECTED_HEADER, "redirected header"}, 133 { ND_OPT_MTU, "mtu"}, 134 { ND_OPT_ADVINTERVAL, "advertisment interval"}, 135 { ND_OPT_HOMEAGENT_INFO, "homeagent information"}, 136 { ND_OPT_ROUTE_INFO, "route info"}, 137 { 0, NULL } 138}; 139 140/* mldv2 report types */ 141static struct tok mldv2report2str[] = { 142 { 1, "is_in" }, 143 { 2, "is_ex" }, 144 { 3, "to_in" }, 145 { 4, "to_ex" }, 146 { 5, "allow" }, 147 { 6, "block" }, 148 { 0, NULL } 149}; 150 |
|
63static const char * 64get_rtpref(u_int v) 65{ 66 static const char *rtpref_str[] = { 67 "medium", /* 00 */ 68 "high", /* 01 */ 69 "rsv", /* 10 */ 70 "low" /* 11 */ --- 102 unchanged lines hidden (view full) --- 173 sum = icmp6_cksum(ip, dp, length); 174 if (sum != 0) 175 (void)printf("[bad icmp6 cksum %x!] ", sum); 176 else 177 (void)printf("[icmp6 sum ok] "); 178 } 179 } 180 | 151static const char * 152get_rtpref(u_int v) 153{ 154 static const char *rtpref_str[] = { 155 "medium", /* 00 */ 156 "high", /* 01 */ 157 "rsv", /* 10 */ 158 "low" /* 11 */ --- 102 unchanged lines hidden (view full) --- 261 sum = icmp6_cksum(ip, dp, length); 262 if (sum != 0) 263 (void)printf("[bad icmp6 cksum %x!] ", sum); 264 else 265 (void)printf("[icmp6 sum ok] "); 266 } 267 } 268 |
269 printf("ICMP6, %s", tok2str(icmp6_type_values,"unknown icmp6 type (%u)",dp->icmp6_type)); 270 271 /* display cosmetics: print the packet length for printer that use the vflag now */ 272 if (vflag && (dp->icmp6_type == 273 ND_ROUTER_SOLICIT || 274 ND_ROUTER_ADVERT || 275 ND_NEIGHBOR_ADVERT || 276 ND_NEIGHBOR_SOLICIT || 277 ND_REDIRECT || 278 ICMP6_HADISCOV_REPLY || 279 ICMP6_MOBILEPREFIX_ADVERT )) 280 printf(", length %u", length); 281 |
|
181 switch (dp->icmp6_type) { 182 case ICMP6_DST_UNREACH: 183 TCHECK(oip->ip6_dst); | 282 switch (dp->icmp6_type) { 283 case ICMP6_DST_UNREACH: 284 TCHECK(oip->ip6_dst); |
285 printf(", %s", tok2str(icmp6_dst_unreach_code_values,"unknown unreach code (%u)",dp->icmp6_code)); |
|
184 switch (dp->icmp6_code) { | 286 switch (dp->icmp6_code) { |
185 case ICMP6_DST_UNREACH_NOROUTE: 186 printf("icmp6: %s unreachable route", 187 ip6addr_string(&oip->ip6_dst)); 188 break; | 287 288 case ICMP6_DST_UNREACH_NOROUTE: /* fall through */ |
189 case ICMP6_DST_UNREACH_ADMIN: | 289 case ICMP6_DST_UNREACH_ADMIN: |
190 printf("icmp6: %s unreachable prohibited", 191 ip6addr_string(&oip->ip6_dst)); 192 break; | 290 case ICMP6_DST_UNREACH_ADDR: 291 printf(" %s",ip6addr_string(&oip->ip6_dst)); 292 break; |
193 case ICMP6_DST_UNREACH_BEYONDSCOPE: | 293 case ICMP6_DST_UNREACH_BEYONDSCOPE: |
194 printf("icmp6: %s beyond scope of source address %s", | 294 printf(" %s, source address %s", |
195 ip6addr_string(&oip->ip6_dst), 196 ip6addr_string(&oip->ip6_src)); 197 break; | 295 ip6addr_string(&oip->ip6_dst), 296 ip6addr_string(&oip->ip6_src)); 297 break; |
198 case ICMP6_DST_UNREACH_ADDR: 199 printf("icmp6: %s unreachable address", 200 ip6addr_string(&oip->ip6_dst)); 201 break; | |
202 case ICMP6_DST_UNREACH_NOPORT: 203 if ((ouh = get_upperlayer((u_char *)oip, &prot)) 204 == NULL) 205 goto trunc; 206 207 dport = EXTRACT_16BITS(&ouh->uh_dport); 208 switch (prot) { 209 case IPPROTO_TCP: | 298 case ICMP6_DST_UNREACH_NOPORT: 299 if ((ouh = get_upperlayer((u_char *)oip, &prot)) 300 == NULL) 301 goto trunc; 302 303 dport = EXTRACT_16BITS(&ouh->uh_dport); 304 switch (prot) { 305 case IPPROTO_TCP: |
210 printf("icmp6: %s tcp port %s unreachable", | 306 printf(", %s tcp port %s", |
211 ip6addr_string(&oip->ip6_dst), 212 tcpport_string(dport)); 213 break; 214 case IPPROTO_UDP: | 307 ip6addr_string(&oip->ip6_dst), 308 tcpport_string(dport)); 309 break; 310 case IPPROTO_UDP: |
215 printf("icmp6: %s udp port %s unreachable", | 311 printf(", %s udp port %s", |
216 ip6addr_string(&oip->ip6_dst), 217 udpport_string(dport)); 218 break; 219 default: | 312 ip6addr_string(&oip->ip6_dst), 313 udpport_string(dport)); 314 break; 315 default: |
220 printf("icmp6: %s protocol %d port %d unreachable", | 316 printf(", %s protocol %d port %d unreachable", |
221 ip6addr_string(&oip->ip6_dst), 222 oip->ip6_nxt, dport); 223 break; 224 } 225 break; 226 default: | 317 ip6addr_string(&oip->ip6_dst), 318 oip->ip6_nxt, dport); 319 break; 320 } 321 break; 322 default: |
227 printf("icmp6: %s unreachable code-#%d", 228 ip6addr_string(&oip->ip6_dst), 229 dp->icmp6_code); 230 break; | 323 if (vflag <= 1) { 324 print_unknown_data(bp,"\n\t",length); 325 return; 326 } 327 break; |
231 } 232 break; 233 case ICMP6_PACKET_TOO_BIG: 234 TCHECK(dp->icmp6_mtu); | 328 } 329 break; 330 case ICMP6_PACKET_TOO_BIG: 331 TCHECK(dp->icmp6_mtu); |
235 printf("icmp6: too big %u", EXTRACT_32BITS(&dp->icmp6_mtu)); | 332 printf(", mtu %u", EXTRACT_32BITS(&dp->icmp6_mtu)); |
236 break; 237 case ICMP6_TIME_EXCEEDED: 238 TCHECK(oip->ip6_dst); 239 switch (dp->icmp6_code) { 240 case ICMP6_TIME_EXCEED_TRANSIT: | 333 break; 334 case ICMP6_TIME_EXCEEDED: 335 TCHECK(oip->ip6_dst); 336 switch (dp->icmp6_code) { 337 case ICMP6_TIME_EXCEED_TRANSIT: |
241 printf("icmp6: time exceeded in-transit for %s", | 338 printf(" for %s", |
242 ip6addr_string(&oip->ip6_dst)); 243 break; 244 case ICMP6_TIME_EXCEED_REASSEMBLY: | 339 ip6addr_string(&oip->ip6_dst)); 340 break; 341 case ICMP6_TIME_EXCEED_REASSEMBLY: |
245 printf("icmp6: ip6 reassembly time exceeded"); | 342 printf(" (reassembly)"); |
246 break; 247 default: | 343 break; 344 default: |
248 printf("icmp6: time exceeded code-#%d", 249 dp->icmp6_code); | 345 printf(", unknown code (%u)", dp->icmp6_code); |
250 break; 251 } 252 break; 253 case ICMP6_PARAM_PROB: 254 TCHECK(oip->ip6_dst); 255 switch (dp->icmp6_code) { 256 case ICMP6_PARAMPROB_HEADER: | 346 break; 347 } 348 break; 349 case ICMP6_PARAM_PROB: 350 TCHECK(oip->ip6_dst); 351 switch (dp->icmp6_code) { 352 case ICMP6_PARAMPROB_HEADER: |
257 printf("icmp6: parameter problem errorneous - octet %u", 258 EXTRACT_32BITS(&dp->icmp6_pptr)); | 353 printf(", errorneous - octet %u", EXTRACT_32BITS(&dp->icmp6_pptr)); |
259 break; 260 case ICMP6_PARAMPROB_NEXTHEADER: | 354 break; 355 case ICMP6_PARAMPROB_NEXTHEADER: |
261 printf("icmp6: parameter problem next header - octet %u", 262 EXTRACT_32BITS(&dp->icmp6_pptr)); | 356 printf(", next header - octet %u", EXTRACT_32BITS(&dp->icmp6_pptr)); |
263 break; 264 case ICMP6_PARAMPROB_OPTION: | 357 break; 358 case ICMP6_PARAMPROB_OPTION: |
265 printf("icmp6: parameter problem option - octet %u", 266 EXTRACT_32BITS(&dp->icmp6_pptr)); | 359 printf(", option - octet %u", EXTRACT_32BITS(&dp->icmp6_pptr)); |
267 break; 268 default: | 360 break; 361 default: |
269 printf("icmp6: parameter problem code-#%d", | 362 printf(", code-#%d", |
270 dp->icmp6_code); 271 break; 272 } 273 break; 274 case ICMP6_ECHO_REQUEST: 275 case ICMP6_ECHO_REPLY: 276 TCHECK(dp->icmp6_seq); | 363 dp->icmp6_code); 364 break; 365 } 366 break; 367 case ICMP6_ECHO_REQUEST: 368 case ICMP6_ECHO_REPLY: 369 TCHECK(dp->icmp6_seq); |
277 printf("icmp6: echo %s seq %u", 278 dp->icmp6_type == ICMP6_ECHO_REQUEST ? 279 "request" : "reply", 280 EXTRACT_16BITS(&dp->icmp6_seq)); | 370 printf(", seq %u", EXTRACT_16BITS(&dp->icmp6_seq)); |
281 break; 282 case ICMP6_MEMBERSHIP_QUERY: | 371 break; 372 case ICMP6_MEMBERSHIP_QUERY: |
283 printf("icmp6: multicast listener query "); 284 mld6_print((const u_char *)dp); | 373 if (length == MLD_MINLEN) { 374 mld6_print((const u_char *)dp); 375 } else if (length >= MLDV2_MINLEN) { 376 printf("v2 "); 377 mldv2_query_print((const u_char *)dp, length); 378 } else { 379 printf(" unknown-version (len %u) ", length); 380 } |
285 break; 286 case ICMP6_MEMBERSHIP_REPORT: | 381 break; 382 case ICMP6_MEMBERSHIP_REPORT: |
287 printf("icmp6: multicast listener report "); | |
288 mld6_print((const u_char *)dp); 289 break; 290 case ICMP6_MEMBERSHIP_REDUCTION: | 383 mld6_print((const u_char *)dp); 384 break; 385 case ICMP6_MEMBERSHIP_REDUCTION: |
291 printf("icmp6: multicast listener done "); | |
292 mld6_print((const u_char *)dp); 293 break; 294 case ND_ROUTER_SOLICIT: | 386 mld6_print((const u_char *)dp); 387 break; 388 case ND_ROUTER_SOLICIT: |
295 printf("icmp6: router solicitation "); 296 if (vflag) { | |
297#define RTSOLLEN 8 | 389#define RTSOLLEN 8 |
390 if (vflag) { |
|
298 icmp6_opt_print((const u_char *)dp + RTSOLLEN, 299 length - RTSOLLEN); 300 } 301 break; 302 case ND_ROUTER_ADVERT: | 391 icmp6_opt_print((const u_char *)dp + RTSOLLEN, 392 length - RTSOLLEN); 393 } 394 break; 395 case ND_ROUTER_ADVERT: |
303 printf("icmp6: router advertisement"); | 396#define RTADVLEN 16 |
304 if (vflag) { 305 struct nd_router_advert *p; 306 307 p = (struct nd_router_advert *)dp; 308 TCHECK(p->nd_ra_retransmit); | 397 if (vflag) { 398 struct nd_router_advert *p; 399 400 p = (struct nd_router_advert *)dp; 401 TCHECK(p->nd_ra_retransmit); |
309 printf("(chlim=%d, ", (int)p->nd_ra_curhoplimit); 310 if (p->nd_ra_flags_reserved & ND_RA_FLAG_MANAGED) 311 printf("M"); 312 if (p->nd_ra_flags_reserved & ND_RA_FLAG_OTHER) 313 printf("O"); 314 if (p->nd_ra_flags_reserved & ND_RA_FLAG_HOME_AGENT) 315 printf("H"); | 402 printf("\n\thop limit %u, Flags [%s]" \ 403 ", pref %s, router lifetime %us, reachable time %us, retrans time %us", 404 (u_int)p->nd_ra_curhoplimit, 405 bittok2str(icmp6_opt_ra_flag_values,"none",(p->nd_ra_flags_reserved)), 406 get_rtpref(p->nd_ra_flags_reserved), 407 EXTRACT_16BITS(&p->nd_ra_router_lifetime), 408 EXTRACT_32BITS(&p->nd_ra_reachable), 409 EXTRACT_32BITS(&p->nd_ra_retransmit)); |
316 | 410 |
317 if ((p->nd_ra_flags_reserved & ~ND_RA_FLAG_RTPREF_MASK) 318 != 0) 319 printf(" "); 320 321 printf("pref=%s, ", 322 get_rtpref(p->nd_ra_flags_reserved)); 323 324 printf("router_ltime=%d, ", EXTRACT_16BITS(&p->nd_ra_router_lifetime)); 325 printf("reachable_time=%u, ", 326 EXTRACT_32BITS(&p->nd_ra_reachable)); 327 printf("retrans_time=%u)", 328 EXTRACT_32BITS(&p->nd_ra_retransmit)); 329#define RTADVLEN 16 | |
330 icmp6_opt_print((const u_char *)dp + RTADVLEN, 331 length - RTADVLEN); 332 } 333 break; 334 case ND_NEIGHBOR_SOLICIT: 335 { 336 struct nd_neighbor_solicit *p; 337 p = (struct nd_neighbor_solicit *)dp; 338 TCHECK(p->nd_ns_target); | 411 icmp6_opt_print((const u_char *)dp + RTADVLEN, 412 length - RTADVLEN); 413 } 414 break; 415 case ND_NEIGHBOR_SOLICIT: 416 { 417 struct nd_neighbor_solicit *p; 418 p = (struct nd_neighbor_solicit *)dp; 419 TCHECK(p->nd_ns_target); |
339 printf("icmp6: neighbor sol: who has %s", 340 ip6addr_string(&p->nd_ns_target)); | 420 printf(", who has %s", ip6addr_string(&p->nd_ns_target)); |
341 if (vflag) { 342#define NDSOLLEN 24 343 icmp6_opt_print((const u_char *)dp + NDSOLLEN, 344 length - NDSOLLEN); 345 } 346 } 347 break; 348 case ND_NEIGHBOR_ADVERT: 349 { 350 struct nd_neighbor_advert *p; 351 352 p = (struct nd_neighbor_advert *)dp; 353 TCHECK(p->nd_na_target); | 421 if (vflag) { 422#define NDSOLLEN 24 423 icmp6_opt_print((const u_char *)dp + NDSOLLEN, 424 length - NDSOLLEN); 425 } 426 } 427 break; 428 case ND_NEIGHBOR_ADVERT: 429 { 430 struct nd_neighbor_advert *p; 431 432 p = (struct nd_neighbor_advert *)dp; 433 TCHECK(p->nd_na_target); |
354 printf("icmp6: neighbor adv: tgt is %s", | 434 printf(", tgt is %s", |
355 ip6addr_string(&p->nd_na_target)); 356 if (vflag) { | 435 ip6addr_string(&p->nd_na_target)); 436 if (vflag) { |
357#define ND_NA_FLAG_ALL \ 358 (ND_NA_FLAG_ROUTER|ND_NA_FLAG_SOLICITED|ND_NA_FLAG_OVERRIDE) 359 /* we don't need ntohl() here. see advanced-api-04. */ 360 if (p->nd_na_flags_reserved & ND_NA_FLAG_ALL) { 361#undef ND_NA_FLAG_ALL 362 u_int32_t flags; 363 364 flags = p->nd_na_flags_reserved; 365 printf("("); 366 if (flags & ND_NA_FLAG_ROUTER) 367 printf("R"); 368 if (flags & ND_NA_FLAG_SOLICITED) 369 printf("S"); 370 if (flags & ND_NA_FLAG_OVERRIDE) 371 printf("O"); 372 printf(")"); 373 } | 437 printf(", Flags [%s]", 438 bittok2str(icmp6_nd_na_flag_values, 439 "none", 440 EXTRACT_32BITS(&p->nd_na_flags_reserved))); |
374#define NDADVLEN 24 375 icmp6_opt_print((const u_char *)dp + NDADVLEN, 376 length - NDADVLEN); 377#undef NDADVLEN 378 } 379 } 380 break; 381 case ND_REDIRECT: 382#define RDR(i) ((struct nd_redirect *)(i)) 383 TCHECK(RDR(dp)->nd_rd_dst); | 441#define NDADVLEN 24 442 icmp6_opt_print((const u_char *)dp + NDADVLEN, 443 length - NDADVLEN); 444#undef NDADVLEN 445 } 446 } 447 break; 448 case ND_REDIRECT: 449#define RDR(i) ((struct nd_redirect *)(i)) 450 TCHECK(RDR(dp)->nd_rd_dst); |
384 printf("icmp6: redirect %s", 385 getname6((const u_char *)&RDR(dp)->nd_rd_dst)); | 451 printf(", %s", getname6((const u_char *)&RDR(dp)->nd_rd_dst)); |
386 TCHECK(RDR(dp)->nd_rd_target); 387 printf(" to %s", 388 getname6((const u_char*)&RDR(dp)->nd_rd_target)); 389#define REDIRECTLEN 40 390 if (vflag) { 391 icmp6_opt_print((const u_char *)dp + REDIRECTLEN, 392 length - REDIRECTLEN); 393 } 394 break; 395#undef REDIRECTLEN 396#undef RDR 397 case ICMP6_ROUTER_RENUMBERING: 398 icmp6_rrenum_print(bp, ep); 399 break; 400 case ICMP6_NI_QUERY: 401 case ICMP6_NI_REPLY: 402 icmp6_nodeinfo_print(length, bp, ep); 403 break; | 452 TCHECK(RDR(dp)->nd_rd_target); 453 printf(" to %s", 454 getname6((const u_char*)&RDR(dp)->nd_rd_target)); 455#define REDIRECTLEN 40 456 if (vflag) { 457 icmp6_opt_print((const u_char *)dp + REDIRECTLEN, 458 length - REDIRECTLEN); 459 } 460 break; 461#undef REDIRECTLEN 462#undef RDR 463 case ICMP6_ROUTER_RENUMBERING: 464 icmp6_rrenum_print(bp, ep); 465 break; 466 case ICMP6_NI_QUERY: 467 case ICMP6_NI_REPLY: 468 icmp6_nodeinfo_print(length, bp, ep); 469 break; |
404 case ICMP6_HADISCOV_REQUEST: 405 printf("icmp6: ha discovery request"); 406 if (vflag) { 407 TCHECK(dp->icmp6_data16[0]); 408 printf("(id=%d)", EXTRACT_16BITS(&dp->icmp6_data16[0])); 409 } | 470 case IND_SOLICIT: 471 case IND_ADVERT: |
410 break; | 472 break; |
473 case ICMP6_V2_MEMBERSHIP_REPORT: 474 mldv2_report_print((const u_char *) dp, length); 475 break; 476 case ICMP6_MOBILEPREFIX_SOLICIT: /* fall through */ 477 case ICMP6_HADISCOV_REQUEST: 478 TCHECK(dp->icmp6_data16[0]); 479 printf(", id 0x%04x", EXTRACT_16BITS(&dp->icmp6_data16[0])); 480 break; |
|
411 case ICMP6_HADISCOV_REPLY: | 481 case ICMP6_HADISCOV_REPLY: |
412 printf("icmp6: ha discovery reply"); | |
413 if (vflag) { 414 struct in6_addr *in6; 415 u_char *cp; 416 417 TCHECK(dp->icmp6_data16[0]); | 482 if (vflag) { 483 struct in6_addr *in6; 484 u_char *cp; 485 486 TCHECK(dp->icmp6_data16[0]); |
418 printf("(id=%d", EXTRACT_16BITS(&dp->icmp6_data16[0])); | 487 printf(", id 0x%04x", EXTRACT_16BITS(&dp->icmp6_data16[0])); |
419 cp = (u_char *)dp + length; 420 in6 = (struct in6_addr *)(dp + 1); 421 for (; (u_char *)in6 < cp; in6++) { 422 TCHECK(*in6); 423 printf(", %s", ip6addr_string(in6)); 424 } | 488 cp = (u_char *)dp + length; 489 in6 = (struct in6_addr *)(dp + 1); 490 for (; (u_char *)in6 < cp; in6++) { 491 TCHECK(*in6); 492 printf(", %s", ip6addr_string(in6)); 493 } |
425 printf(")"); | |
426 } 427 break; | 494 } 495 break; |
428 case ICMP6_MOBILEPREFIX_SOLICIT: 429 printf("icmp6: mobile router solicitation"); 430 if (vflag) { 431 TCHECK(dp->icmp6_data16[0]); 432 printf("(id=%d)", EXTRACT_16BITS(&dp->icmp6_data16[0])); 433 } 434 break; | |
435 case ICMP6_MOBILEPREFIX_ADVERT: | 496 case ICMP6_MOBILEPREFIX_ADVERT: |
436 printf("icmp6: mobile router advertisement"); | |
437 if (vflag) { 438 TCHECK(dp->icmp6_data16[0]); | 497 if (vflag) { 498 TCHECK(dp->icmp6_data16[0]); |
439 printf("(id=%d", EXTRACT_16BITS(&dp->icmp6_data16[0])); | 499 printf(", id 0x%04x", EXTRACT_16BITS(&dp->icmp6_data16[0])); |
440 if (dp->icmp6_data16[1] & 0xc0) 441 printf(" "); 442 if (dp->icmp6_data16[1] & 0x80) 443 printf("M"); 444 if (dp->icmp6_data16[1] & 0x40) 445 printf("O"); | 500 if (dp->icmp6_data16[1] & 0xc0) 501 printf(" "); 502 if (dp->icmp6_data16[1] & 0x80) 503 printf("M"); 504 if (dp->icmp6_data16[1] & 0x40) 505 printf("O"); |
446 printf(")"); | |
447#define MPADVLEN 8 448 icmp6_opt_print((const u_char *)dp + MPADVLEN, 449 length - MPADVLEN); 450 } 451 break; 452 default: | 506#define MPADVLEN 8 507 icmp6_opt_print((const u_char *)dp + MPADVLEN, 508 length - MPADVLEN); 509 } 510 break; 511 default: |
453 printf("icmp6: type-#%d", dp->icmp6_type); 454 break; 455 } | 512 printf(", length %u", length); 513 if (vflag <= 1) 514 print_unknown_data(bp,"\n\t", length); 515 return; 516 } 517 if (!vflag) 518 printf(", length %u", length); |
456 return; 457trunc: 458 fputs("[|icmp6]", stdout); 459} 460 461static struct udphdr * 462get_upperlayer(u_char *bp, u_int *prot) 463{ --- 95 unchanged lines hidden (view full) --- 559 ECHECK(op->nd_opt_len); 560 if (resid <= 0) 561 return; 562 if (op->nd_opt_len == 0) 563 goto trunc; 564 if (cp + (op->nd_opt_len << 3) > ep) 565 goto trunc; 566 | 519 return; 520trunc: 521 fputs("[|icmp6]", stdout); 522} 523 524static struct udphdr * 525get_upperlayer(u_char *bp, u_int *prot) 526{ --- 95 unchanged lines hidden (view full) --- 622 ECHECK(op->nd_opt_len); 623 if (resid <= 0) 624 return; 625 if (op->nd_opt_len == 0) 626 goto trunc; 627 if (cp + (op->nd_opt_len << 3) > ep) 628 goto trunc; 629 |
630 printf("\n\t %s option (%u), length %u (%u): ", 631 tok2str(icmp6_opt_values, "unknown", op->nd_opt_type), 632 op->nd_opt_type, 633 op->nd_opt_len << 3, 634 op->nd_opt_len); 635 |
|
567 switch (op->nd_opt_type) { 568 case ND_OPT_SOURCE_LINKADDR: 569 opl = (struct nd_opt_hdr *)op; | 636 switch (op->nd_opt_type) { 637 case ND_OPT_SOURCE_LINKADDR: 638 opl = (struct nd_opt_hdr *)op; |
570 printf("(src lladdr: "); | |
571 l = (op->nd_opt_len << 3) - 2; 572 print_lladdr(cp + 2, l); | 639 l = (op->nd_opt_len << 3) - 2; 640 print_lladdr(cp + 2, l); |
573 /*(*/ 574 printf(")"); | |
575 break; 576 case ND_OPT_TARGET_LINKADDR: 577 opl = (struct nd_opt_hdr *)op; | 641 break; 642 case ND_OPT_TARGET_LINKADDR: 643 opl = (struct nd_opt_hdr *)op; |
578 printf("(tgt lladdr: "); | |
579 l = (op->nd_opt_len << 3) - 2; 580 print_lladdr(cp + 2, l); | 644 l = (op->nd_opt_len << 3) - 2; 645 print_lladdr(cp + 2, l); |
581 /*(*/ 582 printf(")"); | |
583 break; 584 case ND_OPT_PREFIX_INFORMATION: 585 opp = (struct nd_opt_prefix_info *)op; 586 TCHECK(opp->nd_opt_pi_prefix); | 646 break; 647 case ND_OPT_PREFIX_INFORMATION: 648 opp = (struct nd_opt_prefix_info *)op; 649 TCHECK(opp->nd_opt_pi_prefix); |
587 printf("(prefix info: "); /*)*/ 588 if (op->nd_opt_len != 4) { 589 printf("badlen"); 590 /*(*/ 591 printf(")"); 592 break; 593 } 594 if (opp->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_ONLINK) 595 printf("L"); 596 if (opp->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_AUTO) 597 printf("A"); 598 if (opp->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_ROUTER) 599 printf("R"); 600 if (opp->nd_opt_pi_flags_reserved) 601 printf(" "); 602 printf("valid_ltime=%s,", 603 get_lifetime(EXTRACT_32BITS(&opp->nd_opt_pi_valid_time))); 604 printf("preferred_ltime=%s,", 605 get_lifetime(EXTRACT_32BITS(&opp->nd_opt_pi_preferred_time))); 606 printf("prefix=%s/%d", 607 ip6addr_string(&opp->nd_opt_pi_prefix), 608 opp->nd_opt_pi_prefix_len); 609 if (opp->nd_opt_pi_len != 4) 610 printf("!"); 611 /*(*/ 612 printf(")"); | 650 printf("%s/%u%s, Flags [%s], valid time %ss", 651 ip6addr_string(&opp->nd_opt_pi_prefix), 652 opp->nd_opt_pi_prefix_len, 653 (op->nd_opt_len != 4) ? "badlen" : "", 654 bittok2str(icmp6_opt_pi_flag_values, "none", opp->nd_opt_pi_flags_reserved), 655 get_lifetime(EXTRACT_32BITS(&opp->nd_opt_pi_valid_time))); 656 printf(", pref. time %ss", get_lifetime(EXTRACT_32BITS(&opp->nd_opt_pi_preferred_time))); |
613 break; 614 case ND_OPT_REDIRECTED_HEADER: 615 opr = (struct icmp6_opts_redirect *)op; | 657 break; 658 case ND_OPT_REDIRECTED_HEADER: 659 opr = (struct icmp6_opts_redirect *)op; |
616 printf("(redirect)"); | 660 print_unknown_data(bp,"\n\t ",op->nd_opt_len<<3); |
617 /* xxx */ 618 break; 619 case ND_OPT_MTU: 620 opm = (struct nd_opt_mtu *)op; 621 TCHECK(opm->nd_opt_mtu_mtu); | 661 /* xxx */ 662 break; 663 case ND_OPT_MTU: 664 opm = (struct nd_opt_mtu *)op; 665 TCHECK(opm->nd_opt_mtu_mtu); |
622 printf("(mtu:"); /*)*/ 623 if (op->nd_opt_len != 1) { 624 printf("badlen"); 625 /*(*/ 626 printf(")"); 627 break; 628 } 629 printf(" mtu=%u", EXTRACT_32BITS(&opm->nd_opt_mtu_mtu)); 630 if (opm->nd_opt_mtu_len != 1) 631 printf("!"); 632 printf(")"); 633 break; | 666 printf(" %u%s", 667 EXTRACT_32BITS(&opm->nd_opt_mtu_mtu), 668 (op->nd_opt_len != 1) ? "bad option length" : "" ); 669 break; |
634 case ND_OPT_ADVINTERVAL: 635 opa = (struct nd_opt_advinterval *)op; 636 TCHECK(opa->nd_opt_adv_interval); | 670 case ND_OPT_ADVINTERVAL: 671 opa = (struct nd_opt_advinterval *)op; 672 TCHECK(opa->nd_opt_adv_interval); |
637 printf("(advint:"); /*)*/ 638 printf(" advint=%u", 639 EXTRACT_32BITS(&opa->nd_opt_adv_interval)); 640 /*(*/ 641 printf(")"); | 673 printf(" %us", EXTRACT_32BITS(&opa->nd_opt_adv_interval)); |
642 break; 643 case ND_OPT_HOMEAGENT_INFO: 644 oph = (struct nd_opt_homeagent_info *)op; 645 TCHECK(oph->nd_opt_hai_lifetime); | 674 break; 675 case ND_OPT_HOMEAGENT_INFO: 676 oph = (struct nd_opt_homeagent_info *)op; 677 TCHECK(oph->nd_opt_hai_lifetime); |
646 printf("(ha info:"); /*)*/ 647 printf(" pref=%d", EXTRACT_16BITS(&oph->nd_opt_hai_preference)); 648 printf(", lifetime=%u", EXTRACT_16BITS(&oph->nd_opt_hai_lifetime)); 649 printf(")"); | 678 printf(" preference %u, lifetime %u", 679 EXTRACT_16BITS(&oph->nd_opt_hai_preference), 680 EXTRACT_16BITS(&oph->nd_opt_hai_lifetime)); |
650 break; 651 case ND_OPT_ROUTE_INFO: 652 opri = (struct nd_opt_route_info *)op; 653 TCHECK(opri->nd_opt_rti_lifetime); 654 memset(&in6, 0, sizeof(in6)); 655 in6p = (struct in6_addr *)(opri + 1); 656 switch (op->nd_opt_len) { 657 case 1: --- 4 unchanged lines hidden (view full) --- 662 break; 663 case 3: 664 TCHECK(*in6p); 665 memcpy(&in6, opri + 1, sizeof(in6)); 666 break; 667 default: 668 goto trunc; 669 } | 681 break; 682 case ND_OPT_ROUTE_INFO: 683 opri = (struct nd_opt_route_info *)op; 684 TCHECK(opri->nd_opt_rti_lifetime); 685 memset(&in6, 0, sizeof(in6)); 686 in6p = (struct in6_addr *)(opri + 1); 687 switch (op->nd_opt_len) { 688 case 1: --- 4 unchanged lines hidden (view full) --- 693 break; 694 case 3: 695 TCHECK(*in6p); 696 memcpy(&in6, opri + 1, sizeof(in6)); 697 break; 698 default: 699 goto trunc; 700 } |
670 printf("(rtinfo:"); /*)*/ | |
671 printf(" %s/%u", ip6addr_string(&in6), 672 opri->nd_opt_rti_prefixlen); 673 printf(", pref=%s", get_rtpref(opri->nd_opt_rti_flags)); 674 printf(", lifetime=%s", 675 get_lifetime(EXTRACT_32BITS(&opri->nd_opt_rti_lifetime))); | 701 printf(" %s/%u", ip6addr_string(&in6), 702 opri->nd_opt_rti_prefixlen); 703 printf(", pref=%s", get_rtpref(opri->nd_opt_rti_flags)); 704 printf(", lifetime=%s", 705 get_lifetime(EXTRACT_32BITS(&opri->nd_opt_rti_lifetime))); |
676 /*(*/ 677 printf(")"); | |
678 break; 679 default: | 706 break; 707 default: |
680 printf("(unknown opt_type=%d, opt_len=%d)", 681 op->nd_opt_type, op->nd_opt_len); 682 break; | 708 if (vflag <= 1) { 709 print_unknown_data(cp+2,"\n\t ", (op->nd_opt_len << 3) - 2); /* skip option header */ 710 return; 711 } 712 break; |
683 } | 713 } |
714 /* do we want to see an additional hexdump ? */ 715 if (vflag> 1) 716 print_unknown_data(cp+2,"\n\t ", (op->nd_opt_len << 3) - 2); /* skip option header */ |
|
684 685 cp += op->nd_opt_len << 3; 686 resid -= op->nd_opt_len << 3; 687 } 688 return; 689 690 trunc: 691 fputs("[ndp opt]", stdout); --- 13 unchanged lines hidden (view full) --- 705 if ((u_char *)mp + sizeof(*mp) > ep) 706 return; 707 708 printf("max resp delay: %d ", EXTRACT_16BITS(&mp->mld6_maxdelay)); 709 printf("addr: %s", ip6addr_string(&mp->mld6_addr)); 710} 711 712static void | 717 718 cp += op->nd_opt_len << 3; 719 resid -= op->nd_opt_len << 3; 720 } 721 return; 722 723 trunc: 724 fputs("[ndp opt]", stdout); --- 13 unchanged lines hidden (view full) --- 738 if ((u_char *)mp + sizeof(*mp) > ep) 739 return; 740 741 printf("max resp delay: %d ", EXTRACT_16BITS(&mp->mld6_maxdelay)); 742 printf("addr: %s", ip6addr_string(&mp->mld6_addr)); 743} 744 745static void |
746mldv2_report_print(const u_char *bp, u_int len) 747{ 748 struct icmp6_hdr *icp = (struct icmp6_hdr *) bp; 749 u_int group, nsrcs, ngroups; 750 u_int i, j; 751 752 /* Minimum len is 8 */ 753 if (len < 8) { 754 printf(" [invalid len %d]", len); 755 return; 756 } 757 758 TCHECK(icp->icmp6_data16[1]); 759 ngroups = ntohs(icp->icmp6_data16[1]); 760 printf(", %d group record(s)", ngroups); 761 if (vflag > 0) { 762 /* Print the group records */ 763 group = 8; 764 for (i = 0; i < ngroups; i++) { 765 /* type(1) + auxlen(1) + numsrc(2) + grp(16) */ 766 if (len < group + 20) { 767 printf(" [invalid number of groups]"); 768 return; 769 } 770 TCHECK2(bp[group + 4], 16); 771 printf(" [gaddr %s", ip6addr_string(&bp[group + 4])); 772 printf(" %s", tok2str(mldv2report2str, " [v2-report-#%d]", 773 bp[group])); 774 nsrcs = (bp[group + 2] << 8) + bp[group + 3]; 775 /* Check the number of sources and print them */ 776 if (len < group + 20 + (nsrcs * 16)) { 777 printf(" [invalid number of sources %d]", nsrcs); 778 return; 779 } 780 if (vflag == 1) 781 printf(", %d source(s)", nsrcs); 782 else { 783 /* Print the sources */ 784 (void)printf(" {"); 785 for (j = 0; j < nsrcs; j++) { 786 TCHECK2(bp[group + 20 + j * 16], 16); 787 printf(" %s", ip6addr_string(&bp[group + 20 + j * 16])); 788 } 789 (void)printf(" }"); 790 } 791 /* Next group record */ 792 group += 20 + nsrcs * 16; 793 printf("]"); 794 } 795 } 796 return; 797trunc: 798 (void)printf("[|icmp6]"); 799 return; 800} 801 802static void 803mldv2_query_print(const u_char *bp, u_int len) 804{ 805 struct icmp6_hdr *icp = (struct icmp6_hdr *) bp; 806 u_int mrc; 807 int mrt, qqi; 808 u_int nsrcs; 809 register u_int i; 810 811 /* Minimum len is 28 */ 812 if (len < 28) { 813 printf(" [invalid len %d]", len); 814 return; 815 } 816 TCHECK(icp->icmp6_data16[0]); 817 mrc = ntohs(icp->icmp6_data16[0]); 818 if (mrc < 32768) { 819 mrt = mrc; 820 } else { 821 mrt = ((mrc & 0x0fff) | 0x1000) << (((mrc & 0x7000) >> 12) + 3); 822 } 823 if (vflag) { 824 (void)printf(" [max resp delay=%d]", mrt); 825 } 826 TCHECK2(bp[8], 16); 827 printf(" [gaddr %s", ip6addr_string(&bp[8])); 828 829 if (vflag) { 830 TCHECK(bp[25]); 831 if (bp[24] & 0x08) { 832 printf(" sflag"); 833 } 834 if (bp[24] & 0x07) { 835 printf(" robustness=%d", bp[24] & 0x07); 836 } 837 if (bp[25] < 128) { 838 qqi = bp[25]; 839 } else { 840 qqi = ((bp[25] & 0x0f) | 0x10) << (((bp[25] & 0x70) >> 4) + 3); 841 } 842 printf(" qqi=%d", qqi); 843 } 844 845 TCHECK2(bp[26], 2); 846 nsrcs = ntohs(*(u_short *)&bp[26]); 847 if (nsrcs > 0) { 848 if (len < 28 + nsrcs * 16) 849 printf(" [invalid number of sources]"); 850 else if (vflag > 1) { 851 printf(" {"); 852 for (i = 0; i < nsrcs; i++) { 853 TCHECK2(bp[28 + i * 16], 16); 854 printf(" %s", ip6addr_string(&bp[28 + i * 16])); 855 } 856 printf(" }"); 857 } else 858 printf(", %d source(s)", nsrcs); 859 } 860 printf("]"); 861 return; 862trunc: 863 (void)printf("[|icmp6]"); 864 return; 865} 866 867void |
|
713dnsname_print(const u_char *cp, const u_char *ep) 714{ 715 int i; 716 717 /* DNS name decoding - no decompression */ 718 printf(", \""); 719 while (cp < ep) { 720 i = *cp++; --- 38 unchanged lines hidden (view full) --- 759 dp = (struct icmp6_hdr *)bp; 760 ni6 = (struct icmp6_nodeinfo *)bp; 761 siz = ep - bp; 762 763 switch (ni6->ni_type) { 764 case ICMP6_NI_QUERY: 765 if (siz == sizeof(*dp) + 4) { 766 /* KAME who-are-you */ | 868dnsname_print(const u_char *cp, const u_char *ep) 869{ 870 int i; 871 872 /* DNS name decoding - no decompression */ 873 printf(", \""); 874 while (cp < ep) { 875 i = *cp++; --- 38 unchanged lines hidden (view full) --- 914 dp = (struct icmp6_hdr *)bp; 915 ni6 = (struct icmp6_nodeinfo *)bp; 916 siz = ep - bp; 917 918 switch (ni6->ni_type) { 919 case ICMP6_NI_QUERY: 920 if (siz == sizeof(*dp) + 4) { 921 /* KAME who-are-you */ |
767 printf("icmp6: who-are-you request"); | 922 printf(" who-are-you request"); |
768 break; 769 } | 923 break; 924 } |
770 printf("icmp6: node information query"); | 925 printf(" node information query"); |
771 772 TCHECK2(*dp, sizeof(*ni6)); 773 ni6 = (struct icmp6_nodeinfo *)dp; 774 printf(" ("); /*)*/ 775 switch (EXTRACT_16BITS(&ni6->ni_qtype)) { 776 case NI_QTYPE_NOOP: 777 printf("noop"); 778 break; --- 99 unchanged lines hidden (view full) --- 878 if (icmp6len > siz) { 879 printf("[|icmp6: node information reply]"); 880 break; 881 } 882 883 needcomma = 0; 884 885 ni6 = (struct icmp6_nodeinfo *)dp; | 926 927 TCHECK2(*dp, sizeof(*ni6)); 928 ni6 = (struct icmp6_nodeinfo *)dp; 929 printf(" ("); /*)*/ 930 switch (EXTRACT_16BITS(&ni6->ni_qtype)) { 931 case NI_QTYPE_NOOP: 932 printf("noop"); 933 break; --- 99 unchanged lines hidden (view full) --- 1033 if (icmp6len > siz) { 1034 printf("[|icmp6: node information reply]"); 1035 break; 1036 } 1037 1038 needcomma = 0; 1039 1040 ni6 = (struct icmp6_nodeinfo *)dp; |
886 printf("icmp6: node information reply"); | 1041 printf(" node information reply"); |
887 printf(" ("); /*)*/ 888 switch (ni6->ni_code) { 889 case ICMP6_NI_SUCCESS: 890 if (vflag) { 891 printf("success"); 892 needcomma++; 893 } 894 break; --- 243 unchanged lines hidden --- | 1042 printf(" ("); /*)*/ 1043 switch (ni6->ni_code) { 1044 case ICMP6_NI_SUCCESS: 1045 if (vflag) { 1046 printf("success"); 1047 needcomma++; 1048 } 1049 break; --- 243 unchanged lines hidden --- |