icmp6.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901
  1. /*
  2. * Internet Control Message Protocol for IPv6
  3. */
  4. #include "u.h"
  5. #include "../port/lib.h"
  6. #include "mem.h"
  7. #include "dat.h"
  8. #include "fns.h"
  9. #include "../port/error.h"
  10. #include "ip.h"
  11. #include "ipv6.h"
  12. enum
  13. {
  14. InMsgs6,
  15. InErrors6,
  16. OutMsgs6,
  17. CsumErrs6,
  18. LenErrs6,
  19. HlenErrs6,
  20. HoplimErrs6,
  21. IcmpCodeErrs6,
  22. TargetErrs6,
  23. OptlenErrs6,
  24. AddrmxpErrs6,
  25. RouterAddrErrs6,
  26. Nstats6,
  27. };
  28. enum {
  29. ICMP_USEAD6 = 40,
  30. };
  31. enum {
  32. Oflag = 1<<5,
  33. Sflag = 1<<6,
  34. Rflag = 1<<7,
  35. };
  36. enum {
  37. /* ICMPv6 types */
  38. EchoReply = 0,
  39. UnreachableV6 = 1,
  40. PacketTooBigV6 = 2,
  41. TimeExceedV6 = 3,
  42. SrcQuench = 4,
  43. ParamProblemV6 = 4,
  44. Redirect = 5,
  45. EchoRequest = 8,
  46. TimeExceed = 11,
  47. InParmProblem = 12,
  48. Timestamp = 13,
  49. TimestampReply = 14,
  50. InfoRequest = 15,
  51. InfoReply = 16,
  52. AddrMaskRequest = 17,
  53. AddrMaskReply = 18,
  54. EchoRequestV6 = 128,
  55. EchoReplyV6 = 129,
  56. RouterSolicit = 133,
  57. RouterAdvert = 134,
  58. NbrSolicit = 135,
  59. NbrAdvert = 136,
  60. RedirectV6 = 137,
  61. Maxtype6 = 137,
  62. };
  63. typedef struct ICMPpkt ICMPpkt;
  64. typedef struct IPICMP IPICMP;
  65. typedef struct Ndpkt Ndpkt;
  66. typedef struct NdiscC NdiscC;
  67. struct ICMPpkt {
  68. uchar type;
  69. uchar code;
  70. uchar cksum[2];
  71. uchar icmpid[2];
  72. uchar seq[2];
  73. };
  74. struct IPICMP {
  75. Ip6hdr;
  76. ICMPpkt;
  77. };
  78. struct NdiscC
  79. {
  80. IPICMP;
  81. uchar target[IPaddrlen];
  82. };
  83. struct Ndpkt
  84. {
  85. NdiscC;
  86. uchar otype;
  87. uchar olen; /* length in units of 8 octets(incl type, code),
  88. * 1 for IEEE 802 addresses */
  89. uchar lnaddr[6]; /* link-layer address */
  90. };
  91. typedef struct Icmppriv6
  92. {
  93. ulong stats[Nstats6];
  94. /* message counts */
  95. ulong in[Maxtype6+1];
  96. ulong out[Maxtype6+1];
  97. } Icmppriv6;
  98. typedef struct Icmpcb6
  99. {
  100. QLock;
  101. uchar headers;
  102. } Icmpcb6;
  103. char *icmpnames6[Maxtype6+1] =
  104. {
  105. [EchoReply] "EchoReply",
  106. [UnreachableV6] "UnreachableV6",
  107. [PacketTooBigV6] "PacketTooBigV6",
  108. [TimeExceedV6] "TimeExceedV6",
  109. [SrcQuench] "SrcQuench",
  110. [Redirect] "Redirect",
  111. [EchoRequest] "EchoRequest",
  112. [TimeExceed] "TimeExceed",
  113. [InParmProblem] "InParmProblem",
  114. [Timestamp] "Timestamp",
  115. [TimestampReply] "TimestampReply",
  116. [InfoRequest] "InfoRequest",
  117. [InfoReply] "InfoReply",
  118. [AddrMaskRequest] "AddrMaskRequest",
  119. [AddrMaskReply] "AddrMaskReply",
  120. [EchoRequestV6] "EchoRequestV6",
  121. [EchoReplyV6] "EchoReplyV6",
  122. [RouterSolicit] "RouterSolicit",
  123. [RouterAdvert] "RouterAdvert",
  124. [NbrSolicit] "NbrSolicit",
  125. [NbrAdvert] "NbrAdvert",
  126. [RedirectV6] "RedirectV6",
  127. };
  128. static char *statnames6[Nstats6] =
  129. {
  130. [InMsgs6] "InMsgs",
  131. [InErrors6] "InErrors",
  132. [OutMsgs6] "OutMsgs",
  133. [CsumErrs6] "CsumErrs",
  134. [LenErrs6] "LenErrs",
  135. [HlenErrs6] "HlenErrs",
  136. [HoplimErrs6] "HoplimErrs",
  137. [IcmpCodeErrs6] "IcmpCodeErrs",
  138. [TargetErrs6] "TargetErrs",
  139. [OptlenErrs6] "OptlenErrs",
  140. [AddrmxpErrs6] "AddrmxpErrs",
  141. [RouterAddrErrs6] "RouterAddrErrs",
  142. };
  143. static char *unreachcode[] =
  144. {
  145. [Icmp6_no_route] "no route to destination",
  146. [Icmp6_ad_prohib] "comm with destination administratively prohibited",
  147. [Icmp6_out_src_scope] "beyond scope of source address",
  148. [Icmp6_adr_unreach] "address unreachable",
  149. [Icmp6_port_unreach] "port unreachable",
  150. [Icmp6_gress_src_fail] "source address failed ingress/egress policy",
  151. [Icmp6_rej_route] "reject route to destination",
  152. [Icmp6_unknown] "icmp unreachable: unknown code",
  153. };
  154. static void icmpkick6(void *x, Block *bp);
  155. static void
  156. icmpcreate6(Conv *c)
  157. {
  158. c->rq = qopen(64*1024, Qmsg, 0, c);
  159. c->wq = qbypass(icmpkick6, c);
  160. }
  161. static void
  162. set_cksum(Block *bp)
  163. {
  164. IPICMP *p = (IPICMP *)(bp->rp);
  165. hnputl(p->vcf, 0); /* borrow IP header as pseudoheader */
  166. hnputs(p->ploadlen, blocklen(bp)-IPV6HDR_LEN);
  167. p->proto = 0;
  168. p->ttl = ICMPv6; /* ttl gets set later */
  169. hnputs(p->cksum, 0);
  170. hnputs(p->cksum, ptclcsum(bp, 0, blocklen(bp)));
  171. p->proto = ICMPv6;
  172. }
  173. static Block *
  174. newIPICMP(int packetlen)
  175. {
  176. Block *nbp;
  177. nbp = allocb(packetlen);
  178. nbp->wp += packetlen;
  179. memset(nbp->rp, 0, packetlen);
  180. return nbp;
  181. }
  182. void
  183. icmpadvise6(Proto *icmp, Block *bp, char *msg)
  184. {
  185. ushort recid;
  186. Conv **c, *s;
  187. IPICMP *p;
  188. p = (IPICMP *)bp->rp;
  189. recid = nhgets(p->icmpid);
  190. for(c = icmp->conv; *c; c++) {
  191. s = *c;
  192. if(s->lport == recid && ipcmp(s->raddr, p->dst) == 0){
  193. qhangup(s->rq, msg);
  194. qhangup(s->wq, msg);
  195. break;
  196. }
  197. }
  198. freeblist(bp);
  199. }
  200. static void
  201. icmpkick6(void *x, Block *bp)
  202. {
  203. uchar laddr[IPaddrlen], raddr[IPaddrlen];
  204. Conv *c = x;
  205. IPICMP *p;
  206. Icmppriv6 *ipriv = c->p->priv;
  207. Icmpcb6 *icb = (Icmpcb6*)c->ptcl;
  208. if(bp == nil)
  209. return;
  210. if(icb->headers==6) {
  211. /* get user specified addresses */
  212. bp = pullupblock(bp, ICMP_USEAD6);
  213. if(bp == nil)
  214. return;
  215. bp->rp += 8;
  216. ipmove(laddr, bp->rp);
  217. bp->rp += IPaddrlen;
  218. ipmove(raddr, bp->rp);
  219. bp->rp += IPaddrlen;
  220. bp = padblock(bp, sizeof(Ip6hdr));
  221. }
  222. if(blocklen(bp) < sizeof(IPICMP)){
  223. freeblist(bp);
  224. return;
  225. }
  226. p = (IPICMP *)(bp->rp);
  227. if(icb->headers == 6) {
  228. ipmove(p->dst, raddr);
  229. ipmove(p->src, laddr);
  230. } else {
  231. ipmove(p->dst, c->raddr);
  232. ipmove(p->src, c->laddr);
  233. hnputs(p->icmpid, c->lport);
  234. }
  235. set_cksum(bp);
  236. p->vcf[0] = 0x06 << 4;
  237. if(p->type <= Maxtype6)
  238. ipriv->out[p->type]++;
  239. ipoput6(c->p->f, bp, 0, c->ttl, c->tos, nil);
  240. }
  241. char*
  242. icmpctl6(Conv *c, char **argv, int argc)
  243. {
  244. Icmpcb6 *icb;
  245. icb = (Icmpcb6*) c->ptcl;
  246. if(argc==1 && strcmp(argv[0], "headers")==0) {
  247. icb->headers = 6;
  248. return nil;
  249. }
  250. return "unknown control request";
  251. }
  252. static void
  253. goticmpkt6(Proto *icmp, Block *bp, int muxkey)
  254. {
  255. ushort recid;
  256. uchar *addr;
  257. Conv **c, *s;
  258. IPICMP *p = (IPICMP *)bp->rp;
  259. if(muxkey == 0) {
  260. recid = nhgets(p->icmpid);
  261. addr = p->src;
  262. } else {
  263. recid = muxkey;
  264. addr = p->dst;
  265. }
  266. for(c = icmp->conv; *c; c++){
  267. s = *c;
  268. if(s->lport == recid && ipcmp(s->raddr, addr) == 0){
  269. bp = concatblock(bp);
  270. if(bp != nil)
  271. qpass(s->rq, bp);
  272. return;
  273. }
  274. }
  275. freeblist(bp);
  276. }
  277. static Block *
  278. mkechoreply6(Block *bp, Ipifc *ifc)
  279. {
  280. uchar addr[IPaddrlen];
  281. IPICMP *p = (IPICMP *)(bp->rp);
  282. ipmove(addr, p->src);
  283. if(!isv6mcast(p->dst))
  284. ipmove(p->src, p->dst);
  285. else if (!ipv6anylocal(ifc, p->src))
  286. return nil;
  287. ipmove(p->dst, addr);
  288. p->type = EchoReplyV6;
  289. set_cksum(bp);
  290. return bp;
  291. }
  292. /*
  293. * sends out an ICMPv6 neighbor solicitation
  294. * suni == SRC_UNSPEC or SRC_UNI,
  295. * tuni == TARG_MULTI => multicast for address resolution,
  296. * and tuni == TARG_UNI => neighbor reachability.
  297. */
  298. extern void
  299. icmpns(Fs *f, uchar* src, int suni, uchar* targ, int tuni, uchar* mac)
  300. {
  301. Block *nbp;
  302. Ndpkt *np;
  303. Proto *icmp = f->t2p[ICMPv6];
  304. Icmppriv6 *ipriv = icmp->priv;
  305. nbp = newIPICMP(sizeof(Ndpkt));
  306. np = (Ndpkt*) nbp->rp;
  307. if(suni == SRC_UNSPEC)
  308. memmove(np->src, v6Unspecified, IPaddrlen);
  309. else
  310. memmove(np->src, src, IPaddrlen);
  311. if(tuni == TARG_UNI)
  312. memmove(np->dst, targ, IPaddrlen);
  313. else
  314. ipv62smcast(np->dst, targ);
  315. np->type = NbrSolicit;
  316. np->code = 0;
  317. memmove(np->target, targ, IPaddrlen);
  318. if(suni != SRC_UNSPEC) {
  319. np->otype = SRC_LLADDR;
  320. np->olen = 1; /* 1+1+6 = 8 = 1 8-octet */
  321. memmove(np->lnaddr, mac, sizeof(np->lnaddr));
  322. } else
  323. nbp->wp -= sizeof(Ndpkt) - sizeof(NdiscC);
  324. set_cksum(nbp);
  325. np = (Ndpkt*)nbp->rp;
  326. np->ttl = HOP_LIMIT;
  327. np->vcf[0] = 0x06 << 4;
  328. ipriv->out[NbrSolicit]++;
  329. netlog(f, Logicmp, "sending neighbor solicitation %I\n", targ);
  330. ipoput6(f, nbp, 0, MAXTTL, DFLTTOS, nil);
  331. }
  332. /*
  333. * sends out an ICMPv6 neighbor advertisement. pktflags == RSO flags.
  334. */
  335. extern void
  336. icmpna(Fs *f, uchar* src, uchar* dst, uchar* targ, uchar* mac, uchar flags)
  337. {
  338. Block *nbp;
  339. Ndpkt *np;
  340. Proto *icmp = f->t2p[ICMPv6];
  341. Icmppriv6 *ipriv = icmp->priv;
  342. nbp = newIPICMP(sizeof(Ndpkt));
  343. np = (Ndpkt*)nbp->rp;
  344. memmove(np->src, src, IPaddrlen);
  345. memmove(np->dst, dst, IPaddrlen);
  346. np->type = NbrAdvert;
  347. np->code = 0;
  348. np->icmpid[0] = flags;
  349. memmove(np->target, targ, IPaddrlen);
  350. np->otype = TARGET_LLADDR;
  351. np->olen = 1;
  352. memmove(np->lnaddr, mac, sizeof(np->lnaddr));
  353. set_cksum(nbp);
  354. np = (Ndpkt*) nbp->rp;
  355. np->ttl = HOP_LIMIT;
  356. np->vcf[0] = 0x06 << 4;
  357. ipriv->out[NbrAdvert]++;
  358. netlog(f, Logicmp, "sending neighbor advertisement %I\n", src);
  359. ipoput6(f, nbp, 0, MAXTTL, DFLTTOS, nil);
  360. }
  361. extern void
  362. icmphostunr(Fs *f, Ipifc *ifc, Block *bp, int code, int free)
  363. {
  364. int osz = BLEN(bp);
  365. int sz = MIN(sizeof(IPICMP) + osz, v6MINTU);
  366. Block *nbp;
  367. IPICMP *np;
  368. Ip6hdr *p;
  369. Proto *icmp = f->t2p[ICMPv6];
  370. Icmppriv6 *ipriv = icmp->priv;
  371. p = (Ip6hdr *)bp->rp;
  372. if(isv6mcast(p->src))
  373. goto clean;
  374. nbp = newIPICMP(sz);
  375. np = (IPICMP *)nbp->rp;
  376. rlock(ifc);
  377. if(ipv6anylocal(ifc, np->src))
  378. netlog(f, Logicmp, "send icmphostunr -> s%I d%I\n",
  379. p->src, p->dst);
  380. else {
  381. netlog(f, Logicmp, "icmphostunr fail -> s%I d%I\n",
  382. p->src, p->dst);
  383. freeblist(nbp);
  384. if(free)
  385. goto clean;
  386. else
  387. return;
  388. }
  389. memmove(np->dst, p->src, IPaddrlen);
  390. np->type = UnreachableV6;
  391. np->code = code;
  392. memmove(nbp->rp + sizeof(IPICMP), bp->rp, sz - sizeof(IPICMP));
  393. set_cksum(nbp);
  394. np->ttl = HOP_LIMIT;
  395. np->vcf[0] = 0x06 << 4;
  396. ipriv->out[UnreachableV6]++;
  397. if(free)
  398. ipiput6(f, ifc, nbp);
  399. else {
  400. ipoput6(f, nbp, 0, MAXTTL, DFLTTOS, nil);
  401. return;
  402. }
  403. clean:
  404. runlock(ifc);
  405. freeblist(bp);
  406. }
  407. extern void
  408. icmpttlexceeded6(Fs *f, Ipifc *ifc, Block *bp)
  409. {
  410. int osz = BLEN(bp);
  411. int sz = MIN(sizeof(IPICMP) + osz, v6MINTU);
  412. Block *nbp;
  413. IPICMP *np;
  414. Ip6hdr *p;
  415. Proto *icmp = f->t2p[ICMPv6];
  416. Icmppriv6 *ipriv = icmp->priv;
  417. p = (Ip6hdr *)bp->rp;
  418. if(isv6mcast(p->src))
  419. return;
  420. nbp = newIPICMP(sz);
  421. np = (IPICMP *) nbp->rp;
  422. if(ipv6anylocal(ifc, np->src))
  423. netlog(f, Logicmp, "send icmpttlexceeded6 -> s%I d%I\n",
  424. p->src, p->dst);
  425. else {
  426. netlog(f, Logicmp, "icmpttlexceeded6 fail -> s%I d%I\n",
  427. p->src, p->dst);
  428. return;
  429. }
  430. memmove(np->dst, p->src, IPaddrlen);
  431. np->type = TimeExceedV6;
  432. np->code = 0;
  433. memmove(nbp->rp + sizeof(IPICMP), bp->rp, sz - sizeof(IPICMP));
  434. set_cksum(nbp);
  435. np->ttl = HOP_LIMIT;
  436. np->vcf[0] = 0x06 << 4;
  437. ipriv->out[TimeExceedV6]++;
  438. ipoput6(f, nbp, 0, MAXTTL, DFLTTOS, nil);
  439. }
  440. extern void
  441. icmppkttoobig6(Fs *f, Ipifc *ifc, Block *bp)
  442. {
  443. int osz = BLEN(bp);
  444. int sz = MIN(sizeof(IPICMP) + osz, v6MINTU);
  445. Block *nbp;
  446. IPICMP *np;
  447. Ip6hdr *p;
  448. Proto *icmp = f->t2p[ICMPv6];
  449. Icmppriv6 *ipriv = icmp->priv;
  450. p = (Ip6hdr *)bp->rp;
  451. if(isv6mcast(p->src))
  452. return;
  453. nbp = newIPICMP(sz);
  454. np = (IPICMP *)nbp->rp;
  455. if(ipv6anylocal(ifc, np->src))
  456. netlog(f, Logicmp, "send icmppkttoobig6 -> s%I d%I\n",
  457. p->src, p->dst);
  458. else {
  459. netlog(f, Logicmp, "icmppkttoobig6 fail -> s%I d%I\n",
  460. p->src, p->dst);
  461. return;
  462. }
  463. memmove(np->dst, p->src, IPaddrlen);
  464. np->type = PacketTooBigV6;
  465. np->code = 0;
  466. hnputl(np->icmpid, ifc->maxtu - ifc->m->hsize);
  467. memmove(nbp->rp + sizeof(IPICMP), bp->rp, sz - sizeof(IPICMP));
  468. set_cksum(nbp);
  469. np->ttl = HOP_LIMIT;
  470. np->vcf[0] = 0x06 << 4;
  471. ipriv->out[PacketTooBigV6]++;
  472. ipoput6(f, nbp, 0, MAXTTL, DFLTTOS, nil);
  473. }
  474. /*
  475. * RFC 2461, pages 39-40, pages 57-58.
  476. */
  477. static int
  478. valid(Proto *icmp, Ipifc *ifc, Block *bp, Icmppriv6 *ipriv)
  479. {
  480. int sz, osz, unsp, n, ttl, iplen;
  481. int pktsz = BLEN(bp);
  482. uchar *packet = bp->rp;
  483. IPICMP *p = (IPICMP *) packet;
  484. Ndpkt *np;
  485. USED(ifc);
  486. n = blocklen(bp);
  487. if(n < sizeof(IPICMP)) {
  488. ipriv->stats[HlenErrs6]++;
  489. netlog(icmp->f, Logicmp, "icmp hlen %d\n", n);
  490. goto err;
  491. }
  492. iplen = nhgets(p->ploadlen);
  493. if(iplen > n-IPV6HDR_LEN || (iplen % 1)) {
  494. ipriv->stats[LenErrs6]++;
  495. netlog(icmp->f, Logicmp, "icmp length %d\n", iplen);
  496. goto err;
  497. }
  498. /* Rather than construct explicit pseudoheader, overwrite IPv6 header */
  499. if(p->proto != ICMPv6) {
  500. /* This code assumes no extension headers!!! */
  501. netlog(icmp->f, Logicmp, "icmp error: extension header\n");
  502. goto err;
  503. }
  504. memset(packet, 0, 4);
  505. ttl = p->ttl;
  506. p->ttl = p->proto;
  507. p->proto = 0;
  508. if(ptclcsum(bp, 0, iplen + IPV6HDR_LEN)) {
  509. ipriv->stats[CsumErrs6]++;
  510. netlog(icmp->f, Logicmp, "icmp checksum error\n");
  511. goto err;
  512. }
  513. p->proto = p->ttl;
  514. p->ttl = ttl;
  515. /* additional tests for some pkt types */
  516. if (p->type == NbrSolicit || p->type == NbrAdvert ||
  517. p->type == RouterAdvert || p->type == RouterSolicit ||
  518. p->type == RedirectV6) {
  519. if(p->ttl != HOP_LIMIT) {
  520. ipriv->stats[HoplimErrs6]++;
  521. goto err;
  522. }
  523. if(p->code != 0) {
  524. ipriv->stats[IcmpCodeErrs6]++;
  525. goto err;
  526. }
  527. switch (p->type) {
  528. case NbrSolicit:
  529. case NbrAdvert:
  530. np = (Ndpkt*) p;
  531. if(isv6mcast(np->target)) {
  532. ipriv->stats[TargetErrs6]++;
  533. goto err;
  534. }
  535. if(optexsts(np) && np->olen == 0) {
  536. ipriv->stats[OptlenErrs6]++;
  537. goto err;
  538. }
  539. if (p->type == NbrSolicit &&
  540. ipcmp(np->src, v6Unspecified) == 0)
  541. if(!issmcast(np->dst) || optexsts(np)) {
  542. ipriv->stats[AddrmxpErrs6]++;
  543. goto err;
  544. }
  545. if(p->type == NbrAdvert)
  546. if(isv6mcast(np->dst) &&
  547. (nhgets(np->icmpid) & Sflag)){
  548. ipriv->stats[AddrmxpErrs6]++;
  549. goto err;
  550. }
  551. break;
  552. case RouterAdvert:
  553. if(pktsz - sizeof(Ip6hdr) < 16) {
  554. ipriv->stats[HlenErrs6]++;
  555. goto err;
  556. }
  557. if(!islinklocal(p->src)) {
  558. ipriv->stats[RouterAddrErrs6]++;
  559. goto err;
  560. }
  561. sz = sizeof(IPICMP) + 8;
  562. while (sz+1 < pktsz) {
  563. osz = packet[sz+1];
  564. if(osz <= 0) {
  565. ipriv->stats[OptlenErrs6]++;
  566. goto err;
  567. }
  568. sz += 8*osz;
  569. }
  570. break;
  571. case RouterSolicit:
  572. if(pktsz - sizeof(Ip6hdr) < 8) {
  573. ipriv->stats[HlenErrs6]++;
  574. goto err;
  575. }
  576. unsp = (ipcmp(p->src, v6Unspecified) == 0);
  577. sz = sizeof(IPICMP) + 8;
  578. while (sz+1 < pktsz) {
  579. osz = packet[sz+1];
  580. if(osz <= 0 ||
  581. (unsp && packet[sz] == SRC_LLADDR)) {
  582. ipriv->stats[OptlenErrs6]++;
  583. goto err;
  584. }
  585. sz += 8*osz;
  586. }
  587. break;
  588. case RedirectV6:
  589. /* to be filled in */
  590. break;
  591. default:
  592. goto err;
  593. }
  594. }
  595. return 1;
  596. err:
  597. ipriv->stats[InErrors6]++;
  598. return 0;
  599. }
  600. static int
  601. targettype(Fs *f, Ipifc *ifc, uchar *target)
  602. {
  603. Iplifc *lifc;
  604. int t;
  605. rlock(ifc);
  606. if(ipproxyifc(f, ifc, target)) {
  607. runlock(ifc);
  608. return Tuniproxy;
  609. }
  610. for(lifc = ifc->lifc; lifc; lifc = lifc->next)
  611. if(ipcmp(lifc->local, target) == 0) {
  612. t = (lifc->tentative)? Tunitent: Tunirany;
  613. runlock(ifc);
  614. return t;
  615. }
  616. runlock(ifc);
  617. return 0;
  618. }
  619. static void
  620. icmpiput6(Proto *icmp, Ipifc *ipifc, Block *bp)
  621. {
  622. int refresh = 1;
  623. char *msg, m2[128];
  624. uchar pktflags;
  625. uchar *packet = bp->rp;
  626. uchar lsrc[IPaddrlen];
  627. Block *r;
  628. IPICMP *p = (IPICMP *)packet;
  629. Icmppriv6 *ipriv = icmp->priv;
  630. Iplifc *lifc;
  631. Ndpkt* np;
  632. Proto *pr;
  633. if(!valid(icmp, ipifc, bp, ipriv) || p->type > Maxtype6)
  634. goto raise;
  635. ipriv->in[p->type]++;
  636. switch(p->type) {
  637. case EchoRequestV6:
  638. r = mkechoreply6(bp, ipifc);
  639. if(r == nil)
  640. goto raise;
  641. ipriv->out[EchoReply]++;
  642. ipoput6(icmp->f, r, 0, MAXTTL, DFLTTOS, nil);
  643. break;
  644. case UnreachableV6:
  645. if(p->code >= nelem(unreachcode))
  646. msg = unreachcode[Icmp6_unknown];
  647. else
  648. msg = unreachcode[p->code];
  649. bp->rp += sizeof(IPICMP);
  650. if(blocklen(bp) < 8){
  651. ipriv->stats[LenErrs6]++;
  652. goto raise;
  653. }
  654. p = (IPICMP *)bp->rp;
  655. pr = Fsrcvpcolx(icmp->f, p->proto);
  656. if(pr != nil && pr->advise != nil) {
  657. (*pr->advise)(pr, bp, msg);
  658. return;
  659. }
  660. bp->rp -= sizeof(IPICMP);
  661. goticmpkt6(icmp, bp, 0);
  662. break;
  663. case TimeExceedV6:
  664. if(p->code == 0){
  665. sprint(m2, "ttl exceeded at %I", p->src);
  666. bp->rp += sizeof(IPICMP);
  667. if(blocklen(bp) < 8){
  668. ipriv->stats[LenErrs6]++;
  669. goto raise;
  670. }
  671. p = (IPICMP *)bp->rp;
  672. pr = Fsrcvpcolx(icmp->f, p->proto);
  673. if(pr && pr->advise) {
  674. (*pr->advise)(pr, bp, m2);
  675. return;
  676. }
  677. bp->rp -= sizeof(IPICMP);
  678. }
  679. goticmpkt6(icmp, bp, 0);
  680. break;
  681. case RouterAdvert:
  682. case RouterSolicit:
  683. /* using lsrc as a temp, munge hdr for goticmp6 */
  684. if (0) {
  685. memmove(lsrc, p->src, IPaddrlen);
  686. memmove(p->src, p->dst, IPaddrlen);
  687. memmove(p->dst, lsrc, IPaddrlen);
  688. }
  689. goticmpkt6(icmp, bp, p->type);
  690. break;
  691. case NbrSolicit:
  692. np = (Ndpkt*) p;
  693. pktflags = 0;
  694. switch (targettype(icmp->f, ipifc, np->target)) {
  695. case Tunirany:
  696. pktflags |= Oflag;
  697. /* fall through */
  698. case Tuniproxy:
  699. if(ipcmp(np->src, v6Unspecified) != 0) {
  700. arpenter(icmp->f, V6, np->src, np->lnaddr,
  701. 8*np->olen-2, 0);
  702. pktflags |= Sflag;
  703. }
  704. if(ipv6local(ipifc, lsrc))
  705. icmpna(icmp->f, lsrc,
  706. (ipcmp(np->src, v6Unspecified) == 0?
  707. v6allnodesL: np->src),
  708. np->target, ipifc->mac, pktflags);
  709. else
  710. freeblist(bp);
  711. break;
  712. case Tunitent:
  713. /* not clear what needs to be done. send up
  714. * an icmp mesg saying don't use this address? */
  715. default:
  716. freeblist(bp);
  717. }
  718. break;
  719. case NbrAdvert:
  720. np = (Ndpkt*) p;
  721. /*
  722. * if the target address matches one of the local interface
  723. * addresses and the local interface address has tentative bit
  724. * set, insert into ARP table. this is so the duplicate address
  725. * detection part of ipconfig can discover duplication through
  726. * the arp table.
  727. */
  728. lifc = iplocalonifc(ipifc, np->target);
  729. if(lifc && lifc->tentative)
  730. refresh = 0;
  731. arpenter(icmp->f, V6, np->target, np->lnaddr, 8*np->olen-2,
  732. refresh);
  733. freeblist(bp);
  734. break;
  735. case PacketTooBigV6:
  736. default:
  737. goticmpkt6(icmp, bp, 0);
  738. break;
  739. }
  740. return;
  741. raise:
  742. freeblist(bp);
  743. }
  744. int
  745. icmpstats6(Proto *icmp6, char *buf, int len)
  746. {
  747. Icmppriv6 *priv;
  748. char *p, *e;
  749. int i;
  750. priv = icmp6->priv;
  751. p = buf;
  752. e = p+len;
  753. for(i = 0; i < Nstats6; i++)
  754. p = seprint(p, e, "%s: %lud\n", statnames6[i], priv->stats[i]);
  755. for(i = 0; i <= Maxtype6; i++)
  756. if(icmpnames6[i])
  757. p = seprint(p, e, "%s: %lud %lud\n", icmpnames6[i],
  758. priv->in[i], priv->out[i]);
  759. /* else
  760. p = seprint(p, e, "%d: %lud %lud\n", i, priv->in[i],
  761. priv->out[i]);
  762. */
  763. return p - buf;
  764. }
  765. /* import from icmp.c */
  766. extern int icmpstate(Conv *c, char *state, int n);
  767. extern char* icmpannounce(Conv *c, char **argv, int argc);
  768. extern char* icmpconnect(Conv *c, char **argv, int argc);
  769. extern void icmpclose(Conv *c);
  770. void
  771. icmp6init(Fs *fs)
  772. {
  773. Proto *icmp6 = smalloc(sizeof(Proto));
  774. icmp6->priv = smalloc(sizeof(Icmppriv6));
  775. icmp6->name = "icmpv6";
  776. icmp6->connect = icmpconnect;
  777. icmp6->announce = icmpannounce;
  778. icmp6->state = icmpstate;
  779. icmp6->create = icmpcreate6;
  780. icmp6->close = icmpclose;
  781. icmp6->rcv = icmpiput6;
  782. icmp6->stats = icmpstats6;
  783. icmp6->ctl = icmpctl6;
  784. icmp6->advise = icmpadvise6;
  785. icmp6->gc = nil;
  786. icmp6->ipproto = ICMPv6;
  787. icmp6->nc = 16;
  788. icmp6->ptclsize = sizeof(Icmpcb6);
  789. Fsproto(fs, icmp6);
  790. }