icmp6.c 18 KB

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