icmp6.c 7.6 KB

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