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
10 /*
11 * well known IP addresses
12 */
13 uchar IPv4bcast[IPaddrlen] = {
14 0, 0, 0, 0,
15 0, 0, 0, 0,
16 0, 0, 0xff, 0xff,
17 0xff, 0xff, 0xff, 0xff
18 };
19 uchar IPv4allsys[IPaddrlen] = {
20 0, 0, 0, 0,
21 0, 0, 0, 0,
22 0, 0, 0xff, 0xff,
23 0xe0, 0, 0, 0x01
24 };
25 uchar IPv4allrouter[IPaddrlen] = {
26 0, 0, 0, 0,
27 0, 0, 0, 0,
28 0, 0, 0xff, 0xff,
29 0xe0, 0, 0, 0x02
30 };
31 uchar IPallbits[IPaddrlen] = {
32 0xff, 0xff, 0xff, 0xff,
33 0xff, 0xff, 0xff, 0xff,
34 0xff, 0xff, 0xff, 0xff,
35 0xff, 0xff, 0xff, 0xff
36 };
37
38 uchar IPnoaddr[IPaddrlen];
39
40 /*
41 * prefix of all v4 addresses
42 */
43 uchar v4prefix[IPaddrlen] = {
44 0, 0, 0, 0,
45 0, 0, 0, 0,
46 0, 0, 0xff, 0xff,
47 0, 0, 0, 0
48 };
49
50
51 char *v6hdrtypes[Maxhdrtype] =
52 {
53 [HBH] "HopbyHop",
54 [ICMP] "ICMP",
55 [IGMP] "IGMP",
56 [GGP] "GGP",
57 [IPINIP] "IP",
58 [ST] "ST",
59 [TCP] "TCP",
60 [UDP] "UDP",
61 [ISO_TP4] "ISO_TP4",
62 [RH] "Routinghdr",
63 [FH] "Fraghdr",
64 [IDRP] "IDRP",
65 [RSVP] "RSVP",
66 [AH] "Authhdr",
67 [ESP] "ESP",
68 [ICMPv6] "ICMPv6",
69 [NNH] "Nonexthdr",
70 [ISO_IP] "ISO_IP",
71 [IGRP] "IGRP",
72 [OSPF] "OSPF",
73 };
74
75 /*
76 * well known IPv6 addresses
77 */
78 uchar v6Unspecified[IPaddrlen] = {
79 0, 0, 0, 0,
80 0, 0, 0, 0,
81 0, 0, 0, 0,
82 0, 0, 0, 0
83 };
84 uchar v6loopback[IPaddrlen] = {
85 0, 0, 0, 0,
86 0, 0, 0, 0,
87 0, 0, 0, 0,
88 0, 0, 0, 0x01
89 };
90 uchar v6linklocal[IPaddrlen] = {
91 0xfe, 0x80, 0, 0,
92 0, 0, 0, 0,
93 0, 0, 0, 0,
94 0, 0, 0, 0
95 };
96 uchar v6linklocalmask[IPaddrlen] = {
97 0xff, 0xff, 0xff, 0xff,
98 0xff, 0xff, 0xff, 0xff,
99 0, 0, 0, 0,
100 0, 0, 0, 0
101 };
102 int v6llpreflen = 8; // link-local prefix length
103 uchar v6sitelocal[IPaddrlen] = {
104 0xfe, 0xc0, 0, 0,
105 0, 0, 0, 0,
106 0, 0, 0, 0,
107 0, 0, 0, 0
108 };
109 uchar v6sitelocalmask[IPaddrlen] = {
110 0xff, 0xff, 0xff, 0xff,
111 0xff, 0xff, 0xff, 0xff,
112 0, 0, 0, 0,
113 0, 0, 0, 0
114 };
115 int v6slpreflen = 6; // site-local prefix length
116 uchar v6glunicast[IPaddrlen] = {
117 0x08, 0, 0, 0,
118 0, 0, 0, 0,
119 0, 0, 0, 0,
120 0, 0, 0, 0
121 };
122 uchar v6multicast[IPaddrlen] = {
123 0xff, 0, 0, 0,
124 0, 0, 0, 0,
125 0, 0, 0, 0,
126 0, 0, 0, 0
127 };
128 uchar v6multicastmask[IPaddrlen] = {
129 0xff, 0, 0, 0,
130 0, 0, 0, 0,
131 0, 0, 0, 0,
132 0, 0, 0, 0
133 };
134 int v6mcpreflen = 1; // multicast prefix length
135 uchar v6allnodesN[IPaddrlen] = {
136 0xff, 0x01, 0, 0,
137 0, 0, 0, 0,
138 0, 0, 0, 0,
139 0, 0, 0, 0x01
140 };
141 uchar v6allnodesNmask[IPaddrlen] = {
142 0xff, 0xff, 0, 0,
143 0, 0, 0, 0,
144 0, 0, 0, 0,
145 0, 0, 0, 0
146 };
147 int v6aNpreflen = 2; // all nodes (N) prefix
148 uchar v6allnodesL[IPaddrlen] = {
149 0xff, 0x02, 0, 0,
150 0, 0, 0, 0,
151 0, 0, 0, 0,
152 0, 0, 0, 0x01
153 };
154 uchar v6allnodesLmask[IPaddrlen] = {
155 0xff, 0xff, 0, 0,
156 0, 0, 0, 0,
157 0, 0, 0, 0,
158 0, 0, 0, 0
159 };
160 int v6aLpreflen = 2; // all nodes (L) prefix
161 uchar v6allroutersN[IPaddrlen] = {
162 0xff, 0x01, 0, 0,
163 0, 0, 0, 0,
164 0, 0, 0, 0,
165 0, 0, 0, 0x02
166 };
167 uchar v6allroutersL[IPaddrlen] = {
168 0xff, 0x02, 0, 0,
169 0, 0, 0, 0,
170 0, 0, 0, 0,
171 0, 0, 0, 0x02
172 };
173 uchar v6allroutersS[IPaddrlen] = {
174 0xff, 0x05, 0, 0,
175 0, 0, 0, 0,
176 0, 0, 0, 0,
177 0, 0, 0, 0x02
178 };
179 uchar v6solicitednode[IPaddrlen] = {
180 0xff, 0x02, 0, 0,
181 0, 0, 0, 0,
182 0, 0, 0, 0x01,
183 0xff, 0, 0, 0
184 };
185 uchar v6solicitednodemask[IPaddrlen] = {
186 0xff, 0xff, 0xff, 0xff,
187 0xff, 0xff, 0xff, 0xff,
188 0xff, 0xff, 0xff, 0xff,
189 0xff, 0x0, 0x0, 0x0
190 };
191 int v6snpreflen = 13;
192
193
194
195
196 ushort
ptclcsum(Block * bp,int offset,int len)197 ptclcsum(Block *bp, int offset, int len)
198 {
199 uchar *addr;
200 ulong losum, hisum;
201 ushort csum;
202 int odd, blocklen, x;
203
204 /* Correct to front of data area */
205 while(bp != nil && offset && offset >= BLEN(bp)) {
206 offset -= BLEN(bp);
207 bp = bp->next;
208 }
209 if(bp == nil)
210 return 0;
211
212 addr = bp->rp + offset;
213 blocklen = BLEN(bp) - offset;
214
215 if(bp->next == nil) {
216 if(blocklen < len)
217 len = blocklen;
218 return ~ptclbsum(addr, len) & 0xffff;
219 }
220
221 losum = 0;
222 hisum = 0;
223
224 odd = 0;
225 while(len) {
226 x = blocklen;
227 if(len < x)
228 x = len;
229
230 csum = ptclbsum(addr, x);
231 if(odd)
232 hisum += csum;
233 else
234 losum += csum;
235 odd = (odd+x) & 1;
236 len -= x;
237
238 bp = bp->next;
239 if(bp == nil)
240 break;
241 blocklen = BLEN(bp);
242 addr = bp->rp;
243 }
244
245 losum += hisum>>8;
246 losum += (hisum&0xff)<<8;
247 while((csum = losum>>16) != 0)
248 losum = csum + (losum & 0xffff);
249
250 return ~losum & 0xffff;
251 }
252
253 enum
254 {
255 Isprefix= 16,
256 };
257
258 static uchar prefixvals[256] =
259 {
260 [0x00] 0 | Isprefix,
261 [0x80] 1 | Isprefix,
262 [0xC0] 2 | Isprefix,
263 [0xE0] 3 | Isprefix,
264 [0xF0] 4 | Isprefix,
265 [0xF8] 5 | Isprefix,
266 [0xFC] 6 | Isprefix,
267 [0xFE] 7 | Isprefix,
268 [0xFF] 8 | Isprefix,
269 };
270
271 int
eipfmt(Fmt * f)272 eipfmt(Fmt *f)
273 {
274 char buf[5*8];
275 static char *efmt = "%.2lux%.2lux%.2lux%.2lux%.2lux%.2lux";
276 static char *ifmt = "%d.%d.%d.%d";
277 uchar *p, ip[16];
278 ulong *lp;
279 ushort s;
280 int i, j, n, eln, eli;
281
282 switch(f->r) {
283 case 'E': /* Ethernet address */
284 p = va_arg(f->args, uchar*);
285 return fmtprint(f, efmt, p[0], p[1], p[2], p[3], p[4], p[5]);
286
287 case 'I': /* Ip address */
288 p = va_arg(f->args, uchar*);
289 common:
290 if(memcmp(p, v4prefix, 12) == 0)
291 return fmtprint(f, ifmt, p[12], p[13], p[14], p[15]);
292
293 /* find longest elision */
294 eln = eli = -1;
295 for(i = 0; i < 16; i += 2){
296 for(j = i; j < 16; j += 2)
297 if(p[j] != 0 || p[j+1] != 0)
298 break;
299 if(j > i && j - i > eln){
300 eli = i;
301 eln = j - i;
302 }
303 }
304
305 /* print with possible elision */
306 n = 0;
307 for(i = 0; i < 16; i += 2){
308 if(i == eli){
309 n += sprint(buf+n, "::");
310 i += eln;
311 if(i >= 16)
312 break;
313 } else if(i != 0)
314 n += sprint(buf+n, ":");
315 s = (p[i]<<8) + p[i+1];
316 n += sprint(buf+n, "%ux", s);
317 }
318 return fmtstrcpy(f, buf);
319
320 case 'i': /* v6 address as 4 longs */
321 lp = va_arg(f->args, ulong*);
322 for(i = 0; i < 4; i++)
323 hnputl(ip+4*i, *lp++);
324 p = ip;
325 goto common;
326
327 case 'V': /* v4 ip address */
328 p = va_arg(f->args, uchar*);
329 return fmtprint(f, ifmt, p[0], p[1], p[2], p[3]);
330
331 case 'M': /* ip mask */
332 p = va_arg(f->args, uchar*);
333
334 /* look for a prefix mask */
335 for(i = 0; i < 16; i++)
336 if(p[i] != 0xff)
337 break;
338 if(i < 16){
339 if((prefixvals[p[i]] & Isprefix) == 0)
340 goto common;
341 for(j = i+1; j < 16; j++)
342 if(p[j] != 0)
343 goto common;
344 n = 8*i + (prefixvals[p[i]] & ~Isprefix);
345 } else
346 n = 8*16;
347
348 /* got one, use /xx format */
349 return fmtprint(f, "/%d", n);
350 }
351 return fmtstrcpy(f, "(eipfmt)");
352 }
353
354 #define CLASS(p) ((*(uchar*)(p))>>6)
355
356 extern char*
v4parseip(uchar * to,char * from)357 v4parseip(uchar *to, char *from)
358 {
359 int i;
360 char *p;
361
362 p = from;
363 for(i = 0; i < 4 && *p; i++){
364 to[i] = strtoul(p, &p, 0);
365 if(*p == '.')
366 p++;
367 }
368 switch(CLASS(to)){
369 case 0: /* class A - 1 uchar net */
370 case 1:
371 if(i == 3){
372 to[3] = to[2];
373 to[2] = to[1];
374 to[1] = 0;
375 } else if(i == 2){
376 to[3] = to[1];
377 to[1] = 0;
378 }
379 break;
380 case 2: /* class B - 2 uchar net */
381 if(i == 3){
382 to[3] = to[2];
383 to[2] = 0;
384 }
385 break;
386 }
387 return p;
388 }
389
390 int
isv4(uchar * ip)391 isv4(uchar *ip)
392 {
393 return memcmp(ip, v4prefix, IPv4off) == 0;
394 }
395
396
397 /*
398 * the following routines are unrolled with no memset's to speed
399 * up the usual case
400 */
401 void
v4tov6(uchar * v6,uchar * v4)402 v4tov6(uchar *v6, uchar *v4)
403 {
404 v6[0] = 0;
405 v6[1] = 0;
406 v6[2] = 0;
407 v6[3] = 0;
408 v6[4] = 0;
409 v6[5] = 0;
410 v6[6] = 0;
411 v6[7] = 0;
412 v6[8] = 0;
413 v6[9] = 0;
414 v6[10] = 0xff;
415 v6[11] = 0xff;
416 v6[12] = v4[0];
417 v6[13] = v4[1];
418 v6[14] = v4[2];
419 v6[15] = v4[3];
420 }
421
422 int
v6tov4(uchar * v4,uchar * v6)423 v6tov4(uchar *v4, uchar *v6)
424 {
425 if(v6[0] == 0
426 && v6[1] == 0
427 && v6[2] == 0
428 && v6[3] == 0
429 && v6[4] == 0
430 && v6[5] == 0
431 && v6[6] == 0
432 && v6[7] == 0
433 && v6[8] == 0
434 && v6[9] == 0
435 && v6[10] == 0xff
436 && v6[11] == 0xff)
437 {
438 v4[0] = v6[12];
439 v4[1] = v6[13];
440 v4[2] = v6[14];
441 v4[3] = v6[15];
442 return 0;
443 } else {
444 memset(v4, 0, 4);
445 return -1;
446 }
447 }
448
449 ulong
parseip(uchar * to,char * from)450 parseip(uchar *to, char *from)
451 {
452 int i, elipsis = 0, v4 = 1;
453 ulong x;
454 char *p, *op;
455
456 memset(to, 0, IPaddrlen);
457 p = from;
458 for(i = 0; i < 16 && *p; i+=2){
459 op = p;
460 x = strtoul(p, &p, 16);
461 if(*p == '.' || (*p == 0 && i == 0)){
462 p = v4parseip(to+i, op);
463 i += 4;
464 break;
465 } else {
466 to[i] = x>>8;
467 to[i+1] = x;
468 }
469 if(*p == ':'){
470 v4 = 0;
471 if(*++p == ':'){
472 elipsis = i+2;
473 p++;
474 }
475 }
476 }
477 if(i < 16){
478 memmove(&to[elipsis+16-i], &to[elipsis], i-elipsis);
479 memset(&to[elipsis], 0, 16-i);
480 }
481 if(v4){
482 to[10] = to[11] = 0xff;
483 return nhgetl(to+12);
484 } else
485 return 6;
486 }
487
488 /*
489 * hack to allow ip v4 masks to be entered in the old
490 * style
491 */
492 ulong
parseipmask(uchar * to,char * from)493 parseipmask(uchar *to, char *from)
494 {
495 ulong x;
496 int i;
497 uchar *p;
498
499 if(*from == '/'){
500 /* as a number of prefix bits */
501 i = atoi(from+1);
502 if(i < 0)
503 i = 0;
504 if(i > 128)
505 i = 128;
506 memset(to, 0, IPaddrlen);
507 for(p = to; i >= 8; i -= 8)
508 *p++ = 0xff;
509 if(i > 0)
510 *p = ~((1<<(8-i))-1);
511 x = nhgetl(to+IPv4off);
512 } else {
513 /* as a straight bit mask */
514 x = parseip(to, from);
515 if(memcmp(to, v4prefix, IPv4off) == 0)
516 memset(to, 0xff, IPv4off);
517 }
518 return x;
519 }
520
521 void
maskip(uchar * from,uchar * mask,uchar * to)522 maskip(uchar *from, uchar *mask, uchar *to)
523 {
524 int i;
525
526 for(i = 0; i < IPaddrlen; i++)
527 to[i] = from[i] & mask[i];
528 }
529
530 uchar classmask[4][16] = {
531 0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff, 0xff,0x00,0x00,0x00,
532 0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff, 0xff,0x00,0x00,0x00,
533 0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff, 0xff,0xff,0x00,0x00,
534 0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0x00,
535 };
536
537 uchar*
defmask(uchar * ip)538 defmask(uchar *ip)
539 {
540 if(isv4(ip))
541 return classmask[ip[IPv4off]>>6];
542 else {
543 if(ipcmp(ip, v6loopback) == 0)
544 return IPallbits;
545 else if(memcmp(ip, v6linklocal, v6llpreflen) == 0)
546 return v6linklocalmask;
547 else if(memcmp(ip, v6sitelocal, v6slpreflen) == 0)
548 return v6sitelocalmask;
549 else if(memcmp(ip, v6solicitednode, v6snpreflen) == 0)
550 return v6solicitednodemask;
551 else if(memcmp(ip, v6multicast, v6mcpreflen) == 0)
552 return v6multicastmask;
553 return IPallbits;
554 }
555 }
556
557 void
ipv62smcast(uchar * smcast,uchar * a)558 ipv62smcast(uchar *smcast, uchar *a)
559 {
560 assert(IPaddrlen == 16);
561 memmove(smcast, v6solicitednode, IPaddrlen);
562 smcast[13] = a[13];
563 smcast[14] = a[14];
564 smcast[15] = a[15];
565 }
566
567
568 /*
569 * parse a hex mac address
570 */
571 int
parsemac(uchar * to,char * from,int len)572 parsemac(uchar *to, char *from, int len)
573 {
574 char nip[4];
575 char *p;
576 int i;
577
578 p = from;
579 memset(to, 0, len);
580 for(i = 0; i < len; i++){
581 if(p[0] == '\0' || p[1] == '\0')
582 break;
583
584 nip[0] = p[0];
585 nip[1] = p[1];
586 nip[2] = '\0';
587 p += 2;
588
589 to[i] = strtoul(nip, 0, 16);
590 if(*p == ':')
591 p++;
592 }
593 return i;
594 }
595
596 /*
597 * hashing tcp, udp, ... connections
598 */
599 ulong
iphash(uchar * sa,ushort sp,uchar * da,ushort dp)600 iphash(uchar *sa, ushort sp, uchar *da, ushort dp)
601 {
602 return ((sa[IPaddrlen-1]<<24) ^ (sp << 16) ^ (da[IPaddrlen-1]<<8) ^ dp ) % Nhash;
603 }
604
605 void
iphtadd(Ipht * ht,Conv * c)606 iphtadd(Ipht *ht, Conv *c)
607 {
608 ulong hv;
609 Iphash *h;
610
611 hv = iphash(c->raddr, c->rport, c->laddr, c->lport);
612 h = smalloc(sizeof(*h));
613 if(ipcmp(c->raddr, IPnoaddr) != 0)
614 h->match = IPmatchexact;
615 else {
616 if(ipcmp(c->laddr, IPnoaddr) != 0){
617 if(c->lport == 0)
618 h->match = IPmatchaddr;
619 else
620 h->match = IPmatchpa;
621 } else {
622 if(c->lport == 0)
623 h->match = IPmatchany;
624 else
625 h->match = IPmatchport;
626 }
627 }
628 h->c = c;
629
630 lock(ht);
631 h->next = ht->tab[hv];
632 ht->tab[hv] = h;
633 unlock(ht);
634 }
635
636 void
iphtrem(Ipht * ht,Conv * c)637 iphtrem(Ipht *ht, Conv *c)
638 {
639 ulong hv;
640 Iphash **l, *h;
641
642 hv = iphash(c->raddr, c->rport, c->laddr, c->lport);
643 lock(ht);
644 for(l = &ht->tab[hv]; (*l) != nil; l = &(*l)->next)
645 if((*l)->c == c){
646 h = *l;
647 (*l) = h->next;
648 free(h);
649 break;
650 }
651 unlock(ht);
652 }
653
654 /* look for a matching conversation with the following precedence
655 * connected && raddr,rport,laddr,lport
656 * announced && laddr,lport
657 * announced && *,lport
658 * announced && laddr,*
659 * announced && *,*
660 */
661 Conv*
iphtlook(Ipht * ht,uchar * sa,ushort sp,uchar * da,ushort dp)662 iphtlook(Ipht *ht, uchar *sa, ushort sp, uchar *da, ushort dp)
663 {
664 ulong hv;
665 Iphash *h;
666 Conv *c;
667
668 /* exact 4 pair match (connection) */
669 hv = iphash(sa, sp, da, dp);
670 lock(ht);
671 for(h = ht->tab[hv]; h != nil; h = h->next){
672 if(h->match != IPmatchexact)
673 continue;
674 c = h->c;
675 if(sp == c->rport && dp == c->lport
676 && ipcmp(sa, c->raddr) == 0 && ipcmp(da, c->laddr) == 0){
677 unlock(ht);
678 return c;
679 }
680 }
681
682 /* match local address and port */
683 hv = iphash(IPnoaddr, 0, da, dp);
684 for(h = ht->tab[hv]; h != nil; h = h->next){
685 if(h->match != IPmatchpa)
686 continue;
687 c = h->c;
688 if(dp == c->lport && ipcmp(da, c->laddr) == 0){
689 unlock(ht);
690 return c;
691 }
692 }
693
694 /* match just port */
695 hv = iphash(IPnoaddr, 0, IPnoaddr, dp);
696 for(h = ht->tab[hv]; h != nil; h = h->next){
697 if(h->match != IPmatchport)
698 continue;
699 c = h->c;
700 if(dp == c->lport){
701 unlock(ht);
702 return c;
703 }
704 }
705
706 /* match local address */
707 hv = iphash(IPnoaddr, 0, da, 0);
708 for(h = ht->tab[hv]; h != nil; h = h->next){
709 if(h->match != IPmatchaddr)
710 continue;
711 c = h->c;
712 if(ipcmp(da, c->laddr) == 0){
713 unlock(ht);
714 return c;
715 }
716 }
717
718 /* look for something that matches anything */
719 hv = iphash(IPnoaddr, 0, IPnoaddr, 0);
720 for(h = ht->tab[hv]; h != nil; h = h->next){
721 if(h->match != IPmatchany)
722 continue;
723 c = h->c;
724 unlock(ht);
725 return c;
726 }
727 unlock(ht);
728 return nil;
729 }
730