icmp6.c 18 KB

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