123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734 |
- #include "u.h"
- #include "../port/lib.h"
- #include "mem.h"
- #include "dat.h"
- #include "fns.h"
- #include "../port/error.h"
- #include "ip.h"
- #include "ipv6.h"
- /*
- * well known IP addresses
- */
- uchar IPv4bcast[IPaddrlen] = {
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff
- };
- uchar IPv4allsys[IPaddrlen] = {
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0xff, 0xff,
- 0xe0, 0, 0, 0x01
- };
- uchar IPv4allrouter[IPaddrlen] = {
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0xff, 0xff,
- 0xe0, 0, 0, 0x02
- };
- uchar IPallbits[IPaddrlen] = {
- 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff
- };
- uchar IPnoaddr[IPaddrlen];
- /*
- * prefix of all v4 addresses
- */
- uchar v4prefix[IPaddrlen] = {
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0xff, 0xff,
- 0, 0, 0, 0
- };
- char *v6hdrtypes[Maxhdrtype] =
- {
- [HBH] "HopbyHop",
- [ICMP] "ICMP",
- [IGMP] "IGMP",
- [GGP] "GGP",
- [IPINIP] "IP",
- [ST] "ST",
- [TCP] "TCP",
- [UDP] "UDP",
- [ISO_TP4] "ISO_TP4",
- [RH] "Routinghdr",
- [FH] "Fraghdr",
- [IDRP] "IDRP",
- [RSVP] "RSVP",
- [AH] "Authhdr",
- [ESP] "ESP",
- [ICMPv6] "ICMPv6",
- [NNH] "Nonexthdr",
- [ISO_IP] "ISO_IP",
- [IGRP] "IGRP",
- [OSPF] "OSPF",
- };
- /*
- * well known IPv6 addresses
- */
- uchar v6Unspecified[IPaddrlen] = {
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0
- };
- uchar v6loopback[IPaddrlen] = {
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0x01
- };
- uchar v6linklocal[IPaddrlen] = {
- 0xfe, 0x80, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0
- };
- uchar v6linklocalmask[IPaddrlen] = {
- 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff,
- 0, 0, 0, 0,
- 0, 0, 0, 0
- };
- int v6linklocalprefix = 8;
- uchar v6sitelocal[IPaddrlen] = {
- 0xfe, 0xc0, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0
- };
- uchar v6sitelocalmask[IPaddrlen] = {
- 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff,
- 0, 0, 0, 0,
- 0, 0, 0, 0
- };
- int v6sitelocalprefix = 6;
- uchar v6glunicast[IPaddrlen] = {
- 0x08, 0, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0
- };
- uchar v6multicast[IPaddrlen] = {
- 0xff, 0, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0
- };
- uchar v6multicastmask[IPaddrlen] = {
- 0xff, 0, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0
- };
- int v6multicastprefix = 1;
- uchar v6allnodesN[IPaddrlen] = {
- 0xff, 0x01, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0x01
- };
- uchar v6allnodesNmask[IPaddrlen] = {
- 0xff, 0xff, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0
- };
- int v6allnodesprefix = 2;
- uchar v6allnodesL[IPaddrlen] = {
- 0xff, 0x02, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0x01
- };
- uchar v6allnodesLmask[IPaddrlen] = {
- 0xff, 0xff, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0
- };
- int v6allnodesLprefix = 2;
- uchar v6allroutersN[IPaddrlen] = {
- 0xff, 0x01, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0x02
- };
- uchar v6allroutersL[IPaddrlen] = {
- 0xff, 0x02, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0x02
- };
- uchar v6allroutersS[IPaddrlen] = {
- 0xff, 0x05, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0x02
- };
- uchar v6solicitednode[IPaddrlen] = {
- 0xff, 0x02, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0x01,
- 0xff, 0, 0, 0
- };
- uchar v6solicitednodemask[IPaddrlen] = {
- 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff,
- 0xff, 0x0, 0x0, 0x0
- };
- int v6solicitednodeprefix = 13;
- ushort
- ptclcsum(Block *bp, int offset, int len)
- {
- uchar *addr;
- ulong losum, hisum;
- ushort csum;
- int odd, blocklen, x;
- /* Correct to front of data area */
- while(bp != nil && offset && offset >= BLEN(bp)) {
- offset -= BLEN(bp);
- bp = bp->next;
- }
- if(bp == nil)
- return 0;
- addr = bp->rp + offset;
- blocklen = BLEN(bp) - offset;
- if(bp->next == nil) {
- if(blocklen < len)
- len = blocklen;
- return ~ptclbsum(addr, len) & 0xffff;
- }
- losum = 0;
- hisum = 0;
- odd = 0;
- while(len) {
- x = blocklen;
- if(len < x)
- x = len;
- csum = ptclbsum(addr, x);
- if(odd)
- hisum += csum;
- else
- losum += csum;
- odd = (odd+x) & 1;
- len -= x;
- bp = bp->next;
- if(bp == nil)
- break;
- blocklen = BLEN(bp);
- addr = bp->rp;
- }
- losum += hisum>>8;
- losum += (hisum&0xff)<<8;
- while((csum = losum>>16) != 0)
- losum = csum + (losum & 0xffff);
- return ~losum & 0xffff;
- }
- enum
- {
- Isprefix= 16,
- };
- static uchar prefixvals[256] =
- {
- [0x00] 0 | Isprefix,
- [0x80] 1 | Isprefix,
- [0xC0] 2 | Isprefix,
- [0xE0] 3 | Isprefix,
- [0xF0] 4 | Isprefix,
- [0xF8] 5 | Isprefix,
- [0xFC] 6 | Isprefix,
- [0xFE] 7 | Isprefix,
- [0xFF] 8 | Isprefix,
- };
- int
- eipfmt(Fmt *f)
- {
- char buf[5*8];
- static char *efmt = "%.2lux%.2lux%.2lux%.2lux%.2lux%.2lux";
- static char *ifmt = "%d.%d.%d.%d";
- uchar *p, ip[16];
- ulong *lp;
- ushort s;
- int i, j, n, eln, eli;
- switch(f->r) {
- case 'E': /* Ethernet address */
- p = va_arg(f->args, uchar*);
- snprint(buf, sizeof buf, efmt, p[0], p[1], p[2], p[3], p[4], p[5]);
- return fmtstrcpy(f, buf);
- case 'I': /* Ip address */
- p = va_arg(f->args, uchar*);
- common:
- if(memcmp(p, v4prefix, 12) == 0){
- snprint(buf, sizeof buf, ifmt, p[12], p[13], p[14], p[15]);
- return fmtstrcpy(f, buf);
- }
- /* find longest elision */
- eln = eli = -1;
- for(i = 0; i < 16; i += 2){
- for(j = i; j < 16; j += 2)
- if(p[j] != 0 || p[j+1] != 0)
- break;
- if(j > i && j - i > eln){
- eli = i;
- eln = j - i;
- }
- }
- /* print with possible elision */
- n = 0;
- for(i = 0; i < 16; i += 2){
- if(i == eli){
- n += sprint(buf+n, "::");
- i += eln;
- if(i >= 16)
- break;
- } else if(i != 0)
- n += sprint(buf+n, ":");
- s = (p[i]<<8) + p[i+1];
- n += sprint(buf+n, "%ux", s);
- }
- return fmtstrcpy(f, buf);
- case 'i': /* v6 address as 4 longs */
- lp = va_arg(f->args, ulong*);
- for(i = 0; i < 4; i++)
- hnputl(ip+4*i, *lp++);
- p = ip;
- goto common;
- case 'V': /* v4 ip address */
- p = va_arg(f->args, uchar*);
- snprint(buf, sizeof buf, ifmt, p[0], p[1], p[2], p[3]);
- return fmtstrcpy(f, buf);
- case 'M': /* ip mask */
- p = va_arg(f->args, uchar*);
- /* look for a prefix mask */
- for(i = 0; i < 16; i++)
- if(p[i] != 0xff)
- break;
- if(i < 16){
- if((prefixvals[p[i]] & Isprefix) == 0)
- goto common;
- for(j = i+1; j < 16; j++)
- if(p[j] != 0)
- goto common;
- n = 8*i + (prefixvals[p[i]] & ~Isprefix);
- } else
- n = 8*16;
- /* got one, use /xx format */
- snprint(buf, sizeof buf, "/%d", n);
- return fmtstrcpy(f, buf);
- }
- return fmtstrcpy(f, "(eipfmt)");
- }
- #define CLASS(p) ((*(uchar*)(p))>>6)
- extern char*
- v4parseip(uchar *to, char *from)
- {
- int i;
- char *p;
- p = from;
- for(i = 0; i < 4 && *p; i++){
- to[i] = strtoul(p, &p, 0);
- if(*p == '.')
- p++;
- }
- switch(CLASS(to)){
- case 0: /* class A - 1 uchar net */
- case 1:
- if(i == 3){
- to[3] = to[2];
- to[2] = to[1];
- to[1] = 0;
- } else if(i == 2){
- to[3] = to[1];
- to[1] = 0;
- }
- break;
- case 2: /* class B - 2 uchar net */
- if(i == 3){
- to[3] = to[2];
- to[2] = 0;
- }
- break;
- }
- return p;
- }
- int
- isv4(uchar *ip)
- {
- return memcmp(ip, v4prefix, IPv4off) == 0;
- }
- /*
- * the following routines are unrolled with no memset's to speed
- * up the usual case
- */
- void
- v4tov6(uchar *v6, uchar *v4)
- {
- v6[0] = 0;
- v6[1] = 0;
- v6[2] = 0;
- v6[3] = 0;
- v6[4] = 0;
- v6[5] = 0;
- v6[6] = 0;
- v6[7] = 0;
- v6[8] = 0;
- v6[9] = 0;
- v6[10] = 0xff;
- v6[11] = 0xff;
- v6[12] = v4[0];
- v6[13] = v4[1];
- v6[14] = v4[2];
- v6[15] = v4[3];
- }
- int
- v6tov4(uchar *v4, uchar *v6)
- {
- if(v6[0] == 0
- && v6[1] == 0
- && v6[2] == 0
- && v6[3] == 0
- && v6[4] == 0
- && v6[5] == 0
- && v6[6] == 0
- && v6[7] == 0
- && v6[8] == 0
- && v6[9] == 0
- && v6[10] == 0xff
- && v6[11] == 0xff)
- {
- v4[0] = v6[12];
- v4[1] = v6[13];
- v4[2] = v6[14];
- v4[3] = v6[15];
- return 0;
- } else {
- memset(v4, 0, 4);
- return -1;
- }
- }
- ulong
- parseip(uchar *to, char *from)
- {
- int i, elipsis = 0, v4 = 1;
- ulong x;
- char *p, *op;
- memset(to, 0, IPaddrlen);
- p = from;
- for(i = 0; i < 16 && *p; i+=2){
- op = p;
- x = strtoul(p, &p, 16);
- if(*p == '.' || (*p == 0 && i == 0)){
- p = v4parseip(to+i, op);
- i += 4;
- break;
- } else {
- to[i] = x>>8;
- to[i+1] = x;
- }
- if(*p == ':'){
- v4 = 0;
- if(*++p == ':'){
- elipsis = i+2;
- p++;
- }
- }
- }
- if(i < 16){
- memmove(&to[elipsis+16-i], &to[elipsis], i-elipsis);
- memset(&to[elipsis], 0, 16-i);
- }
- if(v4){
- to[10] = to[11] = 0xff;
- return nhgetl(to+12);
- } else
- return 6;
- }
- /*
- * hack to allow ip v4 masks to be entered in the old
- * style
- */
- ulong
- parseipmask(uchar *to, char *from)
- {
- ulong x;
- int i;
- uchar *p;
- if(*from == '/'){
- /* as a number of prefix bits */
- i = atoi(from+1);
- if(i < 0)
- i = 0;
- if(i > 128)
- i = 128;
- memset(to, 0, IPaddrlen);
- for(p = to; i >= 8; i -= 8)
- *p++ = 0xff;
- if(i > 0)
- *p = ~((1<<(8-i))-1);
- x = nhgetl(to+IPv4off);
- } else {
- /* as a straight bit mask */
- x = parseip(to, from);
- if(memcmp(to, v4prefix, IPv4off) == 0)
- memset(to, 0xff, IPv4off);
- }
- return x;
- }
- void
- maskip(uchar *from, uchar *mask, uchar *to)
- {
- int i;
- for(i = 0; i < IPaddrlen; i++)
- to[i] = from[i] & mask[i];
- }
- uchar classmask[4][16] = {
- 0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff, 0xff,0x00,0x00,0x00,
- 0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff, 0xff,0x00,0x00,0x00,
- 0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff, 0xff,0xff,0x00,0x00,
- 0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0x00,
- };
- uchar*
- defmask(uchar *ip)
- {
- if(isv4(ip))
- return classmask[ip[IPv4off]>>6];
- else {
- if(ipcmp(ip, v6loopback) == 0)
- return IPallbits;
- else if(memcmp(ip, v6linklocal, v6linklocalprefix) == 0)
- return v6linklocalmask;
- else if(memcmp(ip, v6sitelocal, v6sitelocalprefix) == 0)
- return v6sitelocalmask;
- else if(memcmp(ip, v6solicitednode, v6solicitednodeprefix) == 0)
- return v6solicitednodemask;
- else if(memcmp(ip, v6multicast, v6multicastprefix) == 0)
- return v6multicastmask;
- return IPallbits;
- }
- }
- void
- ipv62smcast(uchar *smcast, uchar *a)
- {
- assert(IPaddrlen == 16);
- memmove(smcast, v6solicitednode, IPaddrlen);
- smcast[13] = a[13];
- smcast[14] = a[14];
- smcast[15] = a[15];
- }
- /*
- * parse a hex mac address
- */
- int
- parsemac(uchar *to, char *from, int len)
- {
- char nip[4];
- char *p;
- int i;
- p = from;
- memset(to, 0, len);
- for(i = 0; i < len; i++){
- if(p[0] == '\0' || p[1] == '\0')
- break;
- nip[0] = p[0];
- nip[1] = p[1];
- nip[2] = '\0';
- p += 2;
- to[i] = strtoul(nip, 0, 16);
- if(*p == ':')
- p++;
- }
- return i;
- }
- /*
- * hashing tcp, udp, ... connections
- */
- ulong
- iphash(uchar *sa, ushort sp, uchar *da, ushort dp)
- {
- return ((sa[IPaddrlen-1]<<24) ^ (sp << 16) ^ (da[IPaddrlen-1]<<8) ^ dp ) % Nhash;
- }
- void
- iphtadd(Ipht *ht, Conv *c)
- {
- ulong hv;
- Iphash *h;
- hv = iphash(c->raddr, c->rport, c->laddr, c->lport);
- h = smalloc(sizeof(*h));
- if(ipcmp(c->raddr, IPnoaddr) != 0)
- h->match = IPmatchexact;
- else {
- if(ipcmp(c->laddr, IPnoaddr) != 0){
- if(c->lport == 0)
- h->match = IPmatchaddr;
- else
- h->match = IPmatchpa;
- } else {
- if(c->lport == 0)
- h->match = IPmatchany;
- else
- h->match = IPmatchport;
- }
- }
- h->c = c;
- lock(ht);
- h->next = ht->tab[hv];
- ht->tab[hv] = h;
- unlock(ht);
- }
- void
- iphtrem(Ipht *ht, Conv *c)
- {
- ulong hv;
- Iphash **l, *h;
- hv = iphash(c->raddr, c->rport, c->laddr, c->lport);
- lock(ht);
- for(l = &ht->tab[hv]; (*l) != nil; l = &(*l)->next)
- if((*l)->c == c){
- h = *l;
- (*l) = h->next;
- free(h);
- break;
- }
- unlock(ht);
- }
- /* look for a matching conversation with the following precedence
- * connected && raddr,rport,laddr,lport
- * announced && laddr,lport
- * announced && *,lport
- * announced && laddr,*
- * announced && *,*
- */
- Conv*
- iphtlook(Ipht *ht, uchar *sa, ushort sp, uchar *da, ushort dp)
- {
- ulong hv;
- Iphash *h;
- Conv *c;
- /* exact 4 pair match (connection) */
- hv = iphash(sa, sp, da, dp);
- lock(ht);
- for(h = ht->tab[hv]; h != nil; h = h->next){
- if(h->match != IPmatchexact)
- continue;
- c = h->c;
- if(sp == c->rport && dp == c->lport
- && ipcmp(sa, c->raddr) == 0 && ipcmp(da, c->laddr) == 0){
- unlock(ht);
- return c;
- }
- }
-
- /* match local address and port */
- hv = iphash(IPnoaddr, 0, da, dp);
- for(h = ht->tab[hv]; h != nil; h = h->next){
- if(h->match != IPmatchpa)
- continue;
- c = h->c;
- if(dp == c->lport && ipcmp(da, c->laddr) == 0){
- unlock(ht);
- return c;
- }
- }
-
- /* match just port */
- hv = iphash(IPnoaddr, 0, IPnoaddr, dp);
- for(h = ht->tab[hv]; h != nil; h = h->next){
- if(h->match != IPmatchport)
- continue;
- c = h->c;
- if(dp == c->lport){
- unlock(ht);
- return c;
- }
- }
-
- /* match local address */
- hv = iphash(IPnoaddr, 0, da, 0);
- for(h = ht->tab[hv]; h != nil; h = h->next){
- if(h->match != IPmatchaddr)
- continue;
- c = h->c;
- if(ipcmp(da, c->laddr) == 0){
- unlock(ht);
- return c;
- }
- }
-
- /* look for something that matches anything */
- hv = iphash(IPnoaddr, 0, IPnoaddr, 0);
- for(h = ht->tab[hv]; h != nil; h = h->next){
- if(h->match != IPmatchany)
- continue;
- c = h->c;
- unlock(ht);
- return c;
- }
- unlock(ht);
- return nil;
- }
|