icmp6.c (7718B)
1 #include <u.h> 2 #include <libc.h> 3 #include <ip.h> 4 #include "dat.h" 5 #include "protos.h" 6 7 typedef struct Hdr Hdr; 8 struct Hdr 9 { uchar type; 10 uchar code; 11 uchar cksum[2]; /* Checksum */ 12 uchar data[1]; 13 }; 14 15 enum 16 { 17 ICMP6LEN= 4 18 }; 19 20 enum 21 { 22 Ot, /* type */ 23 Op, /* next protocol */}; 24 25 static Field p_fields[] = 26 { 27 {"t", Fnum, Ot, "type", } , 28 {0} 29 }; 30 31 enum 32 { 33 /* ICMPv6 types */ 34 EchoReply = 0, 35 UnreachableV6 = 1, 36 PacketTooBigV6 = 2, 37 TimeExceedV6 = 3, 38 ParamProblemV6 = 4, 39 Redirect = 5, 40 EchoRequest = 8, 41 TimeExceed = 11, 42 InParmProblem = 12, 43 Timestamp = 13, 44 TimestampReply = 14, 45 InfoRequest = 15, 46 InfoReply = 16, 47 AddrMaskRequest = 17, 48 AddrMaskReply = 18, 49 EchoRequestV6 = 128, 50 EchoReplyV6 = 129, 51 RouterSolicit = 133, 52 RouterAdvert = 134, 53 NbrSolicit = 135, 54 NbrAdvert = 136, 55 RedirectV6 = 137, 56 57 Maxtype6 = 137 58 }; 59 60 static Mux p_mux[] = 61 { 62 {"ip6", UnreachableV6, }, 63 {"ip6", RedirectV6, }, 64 {"ip6", TimeExceedV6, }, 65 {0} 66 }; 67 68 char *icmpmsg6[256] = 69 { 70 [EchoReply] "EchoReply", 71 [UnreachableV6] "UnreachableV6", 72 [PacketTooBigV6] "PacketTooBigV6", 73 [TimeExceedV6] "TimeExceedV6", 74 [Redirect] "Redirect", 75 [EchoRequest] "EchoRequest", 76 [TimeExceed] "TimeExceed", 77 [InParmProblem] "InParmProblem", 78 [Timestamp] "Timestamp", 79 [TimestampReply] "TimestampReply", 80 [InfoRequest] "InfoRequest", 81 [InfoReply] "InfoReply", 82 [AddrMaskRequest] "AddrMaskRequest", 83 [AddrMaskReply] "AddrMaskReply", 84 [EchoRequestV6] "EchoRequestV6", 85 [EchoReplyV6] "EchoReplyV6", 86 [RouterSolicit] "RouterSolicit", 87 [RouterAdvert] "RouterAdvert", 88 [NbrSolicit] "NbrSolicit", 89 [NbrAdvert] "NbrAdvert", 90 [RedirectV6] "RedirectV6" 91 }; 92 93 static char *unreachcode[] = 94 { 95 [0] "no route to destination", 96 [1] "comm with destination administratively prohibited", 97 [2] "icmp unreachable: unassigned error code (2)", 98 [3] "address unreachable", 99 [4] "port unreachable", 100 [5] "icmp unreachable: unknown code" 101 }; 102 103 static char *timexcode[] = 104 { 105 [0] "hop limit exc", 106 [1] "reassmbl time exc", 107 [2] "icmp time exc: unknown code" 108 }; 109 110 static char *parpcode[] = 111 { 112 [0] "erroneous header field encountered", 113 [1] "unrecognized Next Header type encountered", 114 [2] "unrecognized IPv6 option encountered", 115 [3] "icmp par prob: unknown code" 116 }; 117 enum 118 { 119 sll = 1, 120 tll = 2, 121 pref = 3, 122 redir = 4, 123 mtu = 5 124 }; 125 126 static char *icmp6opts[256] = 127 { 128 [0] "unknown opt", 129 [1] "sll_addr", 130 [2] "tll_addr", 131 [3] "pref_opt", 132 [4] "redirect", 133 [5] "mtu_opt" 134 }; 135 136 static void 137 p_compile(Filter *f) 138 { 139 if(f->op == '='){ 140 compile_cmp(icmp6.name, f, p_fields); 141 return; 142 } 143 if(strcmp(f->s, "ip6") == 0){ 144 f->pr = p_mux->pr; 145 f->subop = Op; 146 return; 147 } 148 sysfatal("unknown icmp field or protocol: %s", f->s); 149 } 150 151 static int 152 p_filter(Filter *f, Msg *m) 153 { 154 Hdr *h; 155 156 if(m->pe - m->ps < ICMP6LEN) 157 return 0; 158 159 h = (Hdr*)m->ps; 160 m->ps += ICMP6LEN; 161 162 switch(f->subop){ 163 164 case Ot: 165 if(h->type == f->ulv) 166 return 1; 167 break; 168 case Op: 169 switch(h->type){ 170 case UnreachableV6: 171 case RedirectV6: 172 case TimeExceedV6: 173 m->ps += 4; 174 return 1; 175 } 176 } 177 return 0; 178 } 179 180 static char* 181 opt_seprint(Msg *m) 182 { 183 int otype, osz, pktsz; 184 uchar *a; 185 char *p = m->p; 186 char *e = m->e; 187 char *opt; 188 char optbuf[12]; 189 190 pktsz = m->pe - m->ps; 191 a = m->ps; 192 while (pktsz > 0) { 193 otype = *a; 194 opt = icmp6opts[otype]; 195 if(opt == nil){ 196 sprint(optbuf, "0x%ux", otype); 197 opt = optbuf; 198 } 199 osz = (*(a+1)) * 8; 200 201 switch (otype) { 202 default: 203 p = seprint(p, e, "\n option=%s ", opt); 204 m->pr = &dump; 205 return p; 206 207 case sll: 208 case tll: 209 if ((pktsz < osz) || (osz != 8)) { 210 p = seprint(p, e, "\n option=%s bad size=%d", opt, osz); 211 m->pr = &dump; 212 return p; 213 } 214 p = seprint(p, e, "\n option=%s maddr=%E", opt, a+2); 215 pktsz -= osz; 216 a += osz; 217 break; 218 219 case pref: 220 if ((pktsz < osz) || (osz != 32)) { 221 p = seprint(p, e, "\n option=%s: bad size=%d", opt, osz); 222 m->pr = &dump; 223 return p; 224 } 225 226 p = seprint(p, e, "\n option=%s pref=%I preflen=%3.3d lflag=%1.1d aflag=%1.1d unused1=%1.1d validlt=%d preflt=%d unused2=%1.1d", 227 opt, 228 a+16, 229 (int) (*(a+2)), 230 (*(a+3) & (1 << 7))!=0, 231 (*(a+3) & (1 << 6))!=0, 232 (*(a+3) & 63) != 0, 233 NetL(a+4), 234 NetL(a+8), 235 NetL(a+12)!=0); 236 237 pktsz -= osz; 238 a += osz; 239 break; 240 241 case redir: 242 if (pktsz < osz) { 243 p = seprint(p, e, "\n option=%s: bad size=%d", opt, osz); 244 m->pr = &dump; 245 return p; 246 } 247 248 p = seprint(p, e, "\n option=%s len %d", opt, osz); 249 a += osz; 250 m->ps = a; 251 return p; 252 break; 253 254 case mtu: 255 if ((pktsz < osz) || (osz != 8)) { 256 p = seprint(p, e, "\n option=%s: bad size=%d", opt, osz); 257 m->pr = &dump; 258 return p; 259 } 260 261 p = seprint(p, e, "\n option=%s unused=%1.1d mtu=%d", opt, NetL(a+2)!=0, NetL(a+4)); 262 pktsz -= osz; 263 a += osz; 264 break; 265 } 266 } 267 268 m->ps = a; 269 return p; 270 } 271 272 static int 273 p_seprint(Msg *m) 274 { 275 Hdr *h; 276 char *tn; 277 char *p = m->p; 278 char *e = m->e; 279 int i; 280 uchar *a; 281 /* ushort cksum2, cksum; */ 282 283 h = (Hdr*)m->ps; 284 m->ps += ICMP6LEN; 285 m->pr = &dump; 286 a = m->ps; 287 288 if(m->pe - m->ps < ICMP6LEN) 289 return -1; 290 291 tn = icmpmsg6[h->type]; 292 if(tn == nil) 293 p = seprint(p, e, "t=%ud c=%d ck=%4.4ux", h->type, 294 h->code, (ushort)NetS(h->cksum)); 295 else 296 p = seprint(p, e, "t=%s c=%d ck=%4.4ux", tn, 297 h->code, (ushort)NetS(h->cksum)); 298 299 /* 300 if(Cflag){ 301 cksum = NetS(h->cksum); 302 h->cksum[0] = 0; 303 h->cksum[1] = 0; 304 cksum2 = ~ptclbsum((uchar*)h, m->pe - m->ps + ICMP6LEN) & 0xffff; 305 if(cksum != cksum2) 306 p = seprint(p,e, " !ck=%4.4ux", cksum2); 307 } 308 */ 309 310 switch(h->type){ 311 312 case UnreachableV6: 313 m->ps += 4; 314 m->pr = &ip6; 315 if (h->code >= nelem(unreachcode)) 316 i = nelem(unreachcode)-1; 317 else 318 i = h->code; 319 p = seprint(p, e, " code=%s unused=%1.1d ", unreachcode[i], NetL(a)!=0); 320 break; 321 322 case PacketTooBigV6: 323 m->ps += 4; 324 m->pr = &ip6; 325 p = seprint(p, e, " mtu=%4.4d ", NetL(a)); 326 break; 327 328 case TimeExceedV6: 329 m->ps += 4; 330 m->pr = &ip6; 331 if (h->code >= nelem(timexcode)) 332 i = nelem(timexcode)-1; 333 else 334 i = h->code; 335 p = seprint(p, e, " code=%s unused=%1.1d ", timexcode[i], NetL(a)!=0); 336 break; 337 338 case ParamProblemV6: 339 m->ps += 4; 340 m->pr = &ip6; 341 if (h->code > nelem(parpcode)) 342 i = nelem(parpcode)-1; 343 else 344 i = h->code; 345 p = seprint(p, e, " code=%s ptr=%2.2ux", parpcode[i], h->data[0]); 346 break; 347 348 case EchoReplyV6: 349 case EchoRequestV6: 350 m->ps += 4; 351 p = seprint(p, e, " id=%ux seq=%ux", 352 NetS(h->data), NetS(h->data+2)); 353 break; 354 355 case RouterSolicit: 356 m->ps += 4; 357 m->pr = nil; 358 m->p = seprint(p, e, " unused=%1.1d ", NetL(a)!=0); 359 p = opt_seprint(m); 360 break; 361 362 case RouterAdvert: 363 m->ps += 12; 364 m->pr = nil; 365 m->p = seprint(p, e, " hoplim=%3.3d mflag=%1.1d oflag=%1.1d unused=%1.1d routerlt=%8.8d reachtime=%d rxmtimer=%d", 366 (int) *a, 367 (*(a+1) & (1 << 7)) != 0, 368 (*(a+1) & (1 << 6)) != 0, 369 (*(a+1) & 63) != 0, 370 NetS(a+2), 371 NetL(a+4), 372 NetL(a+8)); 373 p = opt_seprint(m); 374 break; 375 376 case NbrSolicit: 377 m->ps += 20; 378 m->pr = nil; 379 m->p = seprint(p, e, " unused=%1.1d targ %I", NetL(a)!=0, a+4); 380 p = opt_seprint(m); 381 break; 382 383 case NbrAdvert: 384 m->ps += 20; 385 m->pr = nil; 386 m->p = seprint(p, e, " rflag=%1.1d sflag=%1.1d oflag=%1.1d targ=%I", 387 (*a & (1 << 7)) != 0, 388 (*a & (1 << 6)) != 0, 389 (*a & (1 << 5)) != 0, 390 a+4); 391 p = opt_seprint(m); 392 break; 393 394 case RedirectV6: 395 m->ps += 36; 396 m->pr = &ip6; 397 m->p = seprint(p, e, " unused=%1.1d targ=%I dest=%I", NetL(a)!=0, a+4, a+20); 398 p = opt_seprint(m); 399 break; 400 401 case Timestamp: 402 case TimestampReply: 403 m->ps += 12; 404 p = seprint(p, e, " orig=%ud rcv=%ux xmt=%ux", 405 NetL(h->data), NetL(h->data+4), 406 NetL(h->data+8)); 407 m->pr = nil; 408 break; 409 410 case InfoRequest: 411 case InfoReply: 412 break; 413 414 } 415 m->p = p; 416 return 0; 417 } 418 419 Proto icmp6 = 420 { 421 "icmp6", 422 p_compile, 423 p_filter, 424 p_seprint, 425 p_mux, 426 "%lud", 427 p_fields, 428 defaultframer 429 };