icmp6.c 7.5 KB

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