/* * add to self routing cache * called with c->car locked */ static void addselfcache(Fs *f, Ipifc *ifc, Iplifc *lifc, uint8_t *a, int type) { Ipself *p; Iplink *lp; int h; qlock(f->self); /* see if the address already exists */ h = hashipa(a); for(p = f->self->hash[h]; p; p = p->next) if(memcmp(a, p->a, IPaddrlen) == 0) break; /* allocate a local address and add to hash chain */ if(p == nil){ p = smalloc(sizeof(*p)); ipmove(p->a, a); p->type = type; p->next = f->self->hash[h]; f->self->hash[h] = p; /* if the null address, accept all packets */ if(ipcmp(a, v4prefix) == 0 || ipcmp(a, IPnoaddr) == 0) f->self->acceptall = 1; } /* look for a link for this lifc */ for(lp = p->link; lp; lp = lp->selflink) if(lp->lifc == lifc) break; /* allocate a lifc-to-local link and link to both */ if(lp == nil){ lp = smalloc(sizeof(*lp)); lp->ref = 1; lp->lifc = lifc; lp->self = p; lp->selflink = p->link; p->link = lp; lp->lifclink = lifc->link; lifc->link = lp; /* add to routing table */ if(isv4(a)) v4addroute(f, tifc, a+IPv4off, IPallbits+IPv4off, a+IPv4off, type); else v6addroute(f, tifc, a, IPallbits, a, type); if((type & Rmulti) && ifc->medium->addmulti != nil) (*ifc->medium->addmulti)(ifc, a, lifc->local); } else lp->ref++; qunlock(f->self); }
static void ipifcregisterproxy(Fs *f, Ipifc *ifc, uint8_t *ip) { Conv **cp, **e; Ipifc *nifc; Iplifc *lifc; Medium *m; uint8_t net[IPaddrlen]; /* register the address on any network that will proxy for us */ e = &f->ipifc->conv[f->ipifc->nc]; if(!isv4(ip)) { /* V6 */ for(cp = f->ipifc->conv; cp < e; cp++){ if(*cp == nil || (nifc = (Ipifc*)(*cp)->ptcl) == ifc) continue; rlock(nifc); m = nifc->medium; if(m == nil || m->addmulti == nil) { runlock(nifc); continue; } for(lifc = nifc->lifc; lifc; lifc = lifc->next){ maskip(ip, lifc->mask, net); if(ipcmp(net, lifc->remote) == 0) { /* add solicited-node multicast addr */ ipv62smcast(net, ip); addselfcache(f, nifc, lifc, net, Rmulti); arpenter(f, V6, ip, nifc->mac, 6, 0); // (*m->addmulti)(nifc, net, ip); break; } } runlock(nifc); } } else { /* V4 */ for(cp = f->ipifc->conv; cp < e; cp++){ if(*cp == nil || (nifc = (Ipifc*)(*cp)->ptcl) == ifc) continue; rlock(nifc); m = nifc->medium; if(m == nil || m->areg == nil){ runlock(nifc); continue; } for(lifc = nifc->lifc; lifc; lifc = lifc->next){ maskip(ip, lifc->mask, net); if(ipcmp(net, lifc->remote) == 0){ (*m->areg)(nifc, ip); break; } } runlock(nifc); } } }
/* * return multicast version if any */ int ipismulticast(uint8_t *ip) { if(isv4(ip)){ if(ip[IPv4off] >= 0xe0 && ip[IPv4off] < 0xf0) return V4; } else if(ip[0] == 0xff) return V6; return 0; }
int v6addrtype(uint8_t *addr) { if(isv4(addr) || ipcmp(addr, IPnoaddr) == 0) return unknownv6; else if(islinklocal(addr) || isv6mcast(addr) && (addr[1] & 0xF) <= Link_local_scop) return linklocalv6; else return globalv6; }
/* * return first v6 address associated with an interface */ int ipv6local(struct Ipifc *ifc, uint8_t * addr) { struct Iplifc *lifc; for (lifc = ifc->lifc; lifc; lifc = lifc->next) { if (!isv4(lifc->local) && !(lifc->tentative)) { ipmove(addr, lifc->local); return 1; } } return 0; }
int ipv6anylocal(struct Ipifc *ifc, uint8_t * addr) { struct Iplifc *lifc; for (lifc = ifc->lifc; lifc; lifc = lifc->next) { if (!isv4(lifc->local)) { ipmove(addr, lifc->local); return SRC_UNI; } } return SRC_UNSPEC; }
/* * return first v4 address associated with an interface */ int ipv4local(struct Ipifc *ifc, uint8_t * addr) { struct Iplifc *lifc; for (lifc = ifc->lifc; lifc; lifc = lifc->next) { if (isv4(lifc->local)) { memmove(addr, lifc->local + IPv4off, IPv4addrlen); return 1; } } return 0; }
int ipv6anylocal(Ipifc *ifc, uchar *addr) { Iplifc *lifc; for(lifc = ifc->lifc; lifc; lifc = lifc->next){ if(!isv4(lifc->local)){ ipmove(addr, lifc->local); return SRC_UNI; } } return SRC_UNSPEC; }
int ipisbm(uint8_t *ip) { if(isv4(ip)){ if(ip[IPv4off] >= 0xe0 && ip[IPv4off] < 0xf0) return V4; else if(ipcmp(ip, IPv4bcast) == 0) return V4; } else if(ip[0] == 0xff) return V6; return 0; }
/* * remove a logical interface from an ifc * always called with ifc wlock'd */ static char* ipifcremlifc(Ipifc *ifc, Iplifc *lifc) { Iplifc **l; Fs *f; f = ifc->conv->p->f; /* * find address on this interface and remove from chain. * for pt to pt we actually specify the remote address as the * addresss to remove. */ for(l = &ifc->lifc; *l != nil && *l != lifc; l = &(*l)->next) ; if(*l == nil) return "address not on this interface"; *l = lifc->next; /* disassociate any addresses */ while(lifc->link) remselfcache(f, ifc, lifc, lifc->link->self->a); /* remove the route for this logical interface */ if(isv4(lifc->local)) v4delroute(f, lifc->remote+IPv4off, lifc->mask+IPv4off, 1); else { v6delroute(f, lifc->remote, lifc->mask, 1); if(ipcmp(lifc->local, v6loopback) == 0) /* remove route for all node multicast */ v6delroute(f, v6allnodesN, v6allnodesNmask, 1); else if(memcmp(lifc->local, v6linklocal, v6llpreflen) == 0) /* remove route for all link multicast */ v6delroute(f, v6allnodesL, v6allnodesLmask, 1); } free(lifc); return nil; }
/* * convert address into a reverse lookup address */ static void mkptrname(char *ip, char *rip, int rlen) { uchar a[IPaddrlen]; char *p, *e; int i; if(cistrstr(ip, "in-addr.arpa") || cistrstr(ip, "ip6.arpa") || parseip(a, ip) == -1) snprint(rip, rlen, "%s", ip); else if(isv4(a)) snprint(rip, rlen, "%ud.%ud.%ud.%ud.in-addr.arpa", a[15], a[14], a[13], a[12]); else { p = rip; e = rip + rlen; for(i = 15; i >= 0; i--) { p = seprint(p, e, "%ux.", a[i]&0xf); p = seprint(p, e, "%ux.", a[i]>>4); } seprint(p, e, "ip6.arpa"); } }
void so_connect(int fd, uchar *raddr, ushort rport) { int r; struct sockaddr sa; struct sockaddr_in *sin; if(!isv4(raddr)) error(Enotv4); memset(&sa, 0, sizeof(sa)); sin = (struct sockaddr_in*)&sa; sin->sin_family = AF_INET; hnputs(&sin->sin_port, rport); memmove(&sin->sin_addr.s_addr, raddr+IPv4off, IPv4addrlen); osenter(); r = connect(fd, &sa, sizeof(sa)); osleave(); if(r < 0) oserror(); }
void arpadd(char *ipaddr, char *eaddr, int n) { #ifdef SIOCGARP struct arpreq a; struct sockaddr_in pa; int s; uchar addr[IPaddrlen]; s = socket(AF_INET, SOCK_DGRAM, 0); memset(&a, 0, sizeof(a)); memset(&pa, 0, sizeof(pa)); pa.sin_family = AF_INET; pa.sin_port = 0; parseip(addr, ipaddr); if(!isv4(addr)){ close(s); error(Ebadarg); } memmove(&pa.sin_addr, ipaddr+IPv4off, IPv4addrlen); memmove(&a.arp_pa, &pa, sizeof(pa)); while(ioctl(s, SIOCGARP, &a) != -1) { ioctl(s, SIOCDARP, &a); memset(&a.arp_ha, 0, sizeof(a.arp_ha)); } a.arp_ha.sa_family = AF_UNSPEC; parsemac((uchar*)a.arp_ha.sa_data, eaddr, 6); a.arp_flags = ATF_PERM; if(ioctl(s, SIOCSARP, &a) == -1) { oserrstr(up->env->errstr, ERRMAX); close(s); error(up->env->errstr); } close(s); #else error("arp not implemented"); #endif }
int str2addr(char *s, uchar *a) { uchar *a0, ip[16]; char *p; if((s = strchr(s, '!')) == nil) return 0; if((p = strchr(++s, '!')) == nil) return 0; if(strchr(++p, '!') != nil) return 0; if(parseip(ip, s) == -1) return 0; a0 = a; if(socksver == 4){ a += 2; hnputs(a, atoi(p)); a += 2; v6tov4(a, ip); a += 4; } else { a += 3; if(isv4(ip)){ *a++ = 0x01; v6tov4(a, ip); a += 4; } else { *a++ = 0x04; memmove(a, ip, 16); a += 16; } hnputs(a, atoi(p)); a += 2; } return a - a0; }
/* * create a new arp entry for an ip address. */ static struct arpent *newarp6(struct arp *arp, uint8_t *ip, struct Ipifc *ifc, int addrxt) { unsigned int t; struct block *next, *xp; struct arpent *a, *e, *f, **l; struct medium *m = ifc->m; int empty; /* find oldest entry */ e = &arp->cache[NCACHE]; a = arp->cache; t = a->utime; for (f = a; f < e; f++) { if (f->utime < t) { t = f->utime; a = f; } } /* dump waiting packets */ xp = a->hold; a->hold = NULL; if (isv4(a->ip)) { while (xp) { next = xp->list; freeblist(xp); xp = next; } } else { /* queue icmp unreachable for rxmitproc later, w/o arp lock */ if (xp) { if (arp->dropl == NULL) arp->dropf = xp; else arp->dropl->list = xp; for (next = xp->list; next; next = next->list) xp = next; arp->dropl = xp; rendez_wakeup(&arp->rxmtq); } } /* take out of current chain */ l = &arp->hash[haship(a->ip)]; for (f = *l; f; f = f->hash) { if (f == a) { *l = a->hash; break; } l = &f->hash; } /* insert into new chain */ l = &arp->hash[haship(ip)]; a->hash = *l; *l = a; memmove(a->ip, ip, sizeof(a->ip)); a->utime = NOW; a->ctime = 0; /* somewhat of a "last sent time". 0, to trigger a send. */ a->type = m; a->rtime = NOW + ReTransTimer; a->rxtsrem = MAX_MULTICAST_SOLICIT; a->ifc = ifc; a->ifcid = ifc->ifcid; /* put to the end of re-transmit chain; addrxt is 0 when isv4(a->ip) */ if (!ipismulticast(a->ip) && addrxt) { l = &arp->rxmt; empty = (*l == NULL); for (f = *l; f; f = f->nextrxt) { if (f == a) { *l = a->nextrxt; break; } l = &f->nextrxt; } for (f = *l; f; f = f->nextrxt) { l = &f->nextrxt; } *l = a; if (empty) rendez_wakeup(&arp->rxmtq); } a->nextrxt = NULL; return a; }
int arpwrite(struct Fs *fs, char *s, long len) { int n; struct route *r; struct arp *arp; struct block *bp; struct arpent *a, *fl, **l; struct medium *m; char *f[4], buf[256]; uint8_t ip[IPaddrlen], mac[MAClen]; arp = fs->arp; if (len <= 0) error(EINVAL, ERROR_FIXME); if (len > sizeof(buf)) len = sizeof(buf); strlcpy(buf, s, sizeof(buf)); if (len > 0 && buf[len - 2] == '\n') buf[len - 2] = 0; n = getfields(buf, f, 4, 1, " "); if (strcmp(f[0], "flush") == 0) { qlock(&arp->qlock); for (a = arp->cache; a < &arp->cache[NCACHE]; a++) { memset(a->ip, 0, sizeof(a->ip)); memset(a->mac, 0, sizeof(a->mac)); a->hash = NULL; a->state = 0; a->utime = 0; while (a->hold != NULL) { bp = a->hold->list; freeblist(a->hold); a->hold = bp; } } memset(arp->hash, 0, sizeof(arp->hash)); /* clear all pkts on these lists (rxmt, dropf/l) */ arp->rxmt = NULL; arp->dropf = NULL; arp->dropl = NULL; qunlock(&arp->qlock); } else if (strcmp(f[0], "add") == 0) { switch (n) { default: error(EINVAL, ERROR_FIXME); case 3: parseip(ip, f[1]); if (isv4(ip)) r = v4lookup(fs, ip + IPv4off, NULL); else r = v6lookup(fs, ip, NULL); if (r == NULL) error(EHOSTUNREACH, "Destination unreachable"); m = r->rt.ifc->m; n = parsemac(mac, f[2], m->maclen); break; case 4: m = ipfindmedium(f[1]); if (m == NULL) error(EINVAL, ERROR_FIXME); parseip(ip, f[2]); n = parsemac(mac, f[3], m->maclen); break; } if (m->ares == NULL) error(EINVAL, ERROR_FIXME); m->ares(fs, V6, ip, mac, n, 0); } else if (strcmp(f[0], "del") == 0) { if (n != 2) error(EINVAL, ERROR_FIXME); parseip(ip, f[1]); qlock(&arp->qlock); l = &arp->hash[haship(ip)]; for (a = *l; a; a = a->hash) { if (memcmp(ip, a->ip, sizeof(a->ip)) == 0) { *l = a->hash; break; } l = &a->hash; } if (a) { /* take out of re-transmit chain */ l = &arp->rxmt; for (fl = *l; fl; fl = fl->nextrxt) { if (fl == a) { *l = a->nextrxt; break; } l = &fl->nextrxt; } a->nextrxt = NULL; a->hash = NULL; a->hold = NULL; a->last = NULL; a->ifc = NULL; memset(a->ip, 0, sizeof(a->ip)); memset(a->mac, 0, sizeof(a->mac)); } qunlock(&arp->qlock); } else error(EINVAL, ERROR_FIXME); return len; }
/* * fill in all the requested attributes for a system. * if the system's entry doesn't have all required, * walk through successively more inclusive networks * for inherited attributes. */ Ndbtuple* ndbipinfo(Ndb *db, char *attr, char *val, char **alist, int n) { Ndbtuple *t, *nt, *f; Ndbs s; char *ipstr; uint8_t net[IPaddrlen], ip[IPaddrlen]; int prefix, smallestprefix, force; int64_t r; /* just in case */ fmtinstall('I', eipfmt); fmtinstall('M', eipfmt); /* get needed attributes */ f = mkfilter(n, alist); /* * first look for a matching entry with an ip address */ t = nil; ipstr = ndbgetvalue(db, &s, attr, val, "ip", &nt); if(ipstr == nil){ /* none found, make one up */ if(strcmp(attr, "ip") != 0) { ndbfree(f); return nil; } t = ndbnew("ip", val); t->line = t; t->entry = nil; r = parseip(net, val); if(r == -1) ndbfree(t); } else { /* found one */ while(nt != nil){ nt = ndbreorder(nt, s.t); t = ndbconcatenate(t, nt); nt = ndbsnext(&s, attr, val); } r = parseip(net, ipstr); free(ipstr); } if(r < 0){ ndbfree(f); return nil; } ipmove(ip, net); t = filter(db, t, f); /* * now go through subnets to fill in any missing attributes */ if(isv4(net)){ prefix = 127; smallestprefix = 100; force = 0; } else { /* in v6, the last 8 bytes have no structure (we hope) */ prefix = 64; smallestprefix = 2; memset(net+8, 0, 8); force = 1; } /* * to find a containing network, keep turning off * the lower bit and look for a network with * that address and a shorter mask. tedius but * complete, we may need to find a trick to speed this up. */ for(; prefix >= smallestprefix; prefix--){ if(filtercomplete(f)) break; if(!force && (net[prefix/8] & (1<<(7-(prefix%8)))) == 0) continue; force = 0; net[prefix/8] &= ~(1<<(7-(prefix%8))); t = ndbconcatenate(t, subnet(db, net, f, prefix)); } /* * if there's an unfulfilled ipmask, make one up */ nt = ndbfindattr(f, f, "ipmask"); if(nt && !(nt->ptr & Fignore)){ char x[64]; snprint(x, sizeof(x), "%M", defmask(ip)); t = ndbconcatenate(t, ndbnew("ipmask", x)); } ndbfree(f); ndbsetmalloctag(t, getcallerpc(&db)); return t; }
/* * Decrement reference for this address on this link. * Unlink from selftab if this is the last ref. * called with c->car locked */ static void remselfcache(Fs *f, Ipifc *ifc, Iplifc *lifc, uint8_t *a) { Ipself *p, **l; Iplink *link, **l_self, **l_lifc; qlock(f->self); /* find the unique selftab entry */ l = &f->self->hash[hashipa(a)]; for(p = *l; p; p = *l){ if(ipcmp(p->a, a) == 0) break; l = &p->next; } if(p == nil) goto out; /* * walk down links from an ifc looking for one * that matches the selftab entry */ l_lifc = &lifc->link; for(link = *l_lifc; link; link = *l_lifc){ if(link->self == p) break; l_lifc = &link->lifclink; } if(link == nil) goto out; /* * walk down the links from the selftab looking for * the one we just found */ l_self = &p->link; for(link = *l_self; link; link = *l_self){ if(link == *l_lifc) break; l_self = &link->selflink; } if(link == nil) panic("remselfcache"); if(--(link->ref) != 0) goto out; if((p->type & Rmulti) && ifc->medium->remmulti != nil) (*ifc->medium->remmulti)(ifc, a, lifc->local); /* ref == 0, remove from both chains and free the link */ *l_lifc = link->lifclink; *l_self = link->selflink; iplinkfree(link); if(p->link != nil) goto out; /* remove from routing table */ if(isv4(a)) v4delroute(f, a+IPv4off, IPallbits+IPv4off, 1); else v6delroute(f, a, IPallbits, 1); /* no more links, remove from hash and free */ *l = p->next; ipselffree(p); /* if IPnoaddr, forget */ if(ipcmp(a, v4prefix) == 0 || ipcmp(a, IPnoaddr) == 0) f->self->acceptall = 0; out: qunlock(f->self); }
/* * add an address to an interface. */ char* ipifcadd(Ipifc *ifc, char **argv, int argc, int tentative, Iplifc *lifcp) { int i, type, mtu, sendnbrdisc = 0; uint8_t ip[IPaddrlen], mask[IPaddrlen], rem[IPaddrlen]; uint8_t bcast[IPaddrlen], net[IPaddrlen]; Iplifc *lifc, **l; Fs *f; if(ifc->medium == nil) return "ipifc not yet bound to device"; f = ifc->conv->p->f; type = Rifc; memset(ip, 0, IPaddrlen); memset(mask, 0, IPaddrlen); memset(rem, 0, IPaddrlen); switch(argc){ case 6: if(strcmp(argv[5], "proxy") == 0) type |= Rproxy; /* fall through */ case 5: mtu = strtoul(argv[4], 0, 0); if(mtu >= ifc->medium->mintu && mtu <= ifc->medium->maxtu) ifc->maxtu = mtu; /* fall through */ case 4: if (parseip(ip, argv[1]) == -1 || parseip(rem, argv[3]) == -1) return Ebadip; parseipmask(mask, argv[2]); maskip(rem, mask, net); break; case 3: if (parseip(ip, argv[1]) == -1) return Ebadip; parseipmask(mask, argv[2]); maskip(ip, mask, rem); maskip(rem, mask, net); break; case 2: if (parseip(ip, argv[1]) == -1) return Ebadip; memmove(mask, defmask(ip), IPaddrlen); maskip(ip, mask, rem); maskip(rem, mask, net); break; default: return Ebadarg; } if(isv4(ip)) tentative = 0; wlock(ifc); /* ignore if this is already a local address for this ifc */ for(lifc = ifc->lifc; lifc; lifc = lifc->next) { if(ipcmp(lifc->local, ip) == 0) { if(lifc->tentative != tentative) lifc->tentative = tentative; if(lifcp) { lifc->onlink = lifcp->onlink; lifc->autoflag = lifcp->autoflag; lifc->validlt = lifcp->validlt; lifc->preflt = lifcp->preflt; lifc->origint = lifcp->origint; } goto out; } } /* add the address to the list of logical ifc's for this ifc */ lifc = smalloc(sizeof(Iplifc)); ipmove(lifc->local, ip); ipmove(lifc->mask, mask); ipmove(lifc->remote, rem); ipmove(lifc->net, net); lifc->tentative = tentative; if(lifcp) { lifc->onlink = lifcp->onlink; lifc->autoflag = lifcp->autoflag; lifc->validlt = lifcp->validlt; lifc->preflt = lifcp->preflt; lifc->origint = lifcp->origint; } else { /* default values */ lifc->onlink = lifc->autoflag = 1; lifc->validlt = lifc->preflt = ~0L; lifc->origint = NOW / 1000; } lifc->next = nil; for(l = &ifc->lifc; *l; l = &(*l)->next) ; *l = lifc; /* check for point-to-point interface */ if(ipcmp(ip, v6loopback)) /* skip v6 loopback, it's a special address */ if(ipcmp(mask, IPallbits) == 0) type |= Rptpt; /* add local routes */ if(isv4(ip)) v4addroute(f, tifc, rem+IPv4off, mask+IPv4off, rem+IPv4off, type); else v6addroute(f, tifc, rem, mask, rem, type); addselfcache(f, ifc, lifc, ip, Runi); if((type & (Rproxy|Rptpt)) == (Rproxy|Rptpt)){ ipifcregisterproxy(f, ifc, rem); goto out; } if(isv4(ip) || ipcmp(ip, IPnoaddr) == 0) { /* add subnet directed broadcast address to the self cache */ for(i = 0; i < IPaddrlen; i++) bcast[i] = (ip[i] & mask[i]) | ~mask[i]; addselfcache(f, ifc, lifc, bcast, Rbcast); /* add subnet directed network address to the self cache */ for(i = 0; i < IPaddrlen; i++) bcast[i] = (ip[i] & mask[i]) & mask[i]; addselfcache(f, ifc, lifc, bcast, Rbcast); /* add network directed broadcast address to the self cache */ memmove(mask, defmask(ip), IPaddrlen); for(i = 0; i < IPaddrlen; i++) bcast[i] = (ip[i] & mask[i]) | ~mask[i]; addselfcache(f, ifc, lifc, bcast, Rbcast); /* add network directed network address to the self cache */ memmove(mask, defmask(ip), IPaddrlen); for(i = 0; i < IPaddrlen; i++) bcast[i] = (ip[i] & mask[i]) & mask[i]; addselfcache(f, ifc, lifc, bcast, Rbcast); addselfcache(f, ifc, lifc, IPv4bcast, Rbcast); } else { if(ipcmp(ip, v6loopback) == 0) { /* add node-local mcast address */ addselfcache(f, ifc, lifc, v6allnodesN, Rmulti); /* add route for all node multicast */ v6addroute(f, tifc, v6allnodesN, v6allnodesNmask, v6allnodesN, Rmulti); } /* add all nodes multicast address */ addselfcache(f, ifc, lifc, v6allnodesL, Rmulti); /* add route for all nodes multicast */ v6addroute(f, tifc, v6allnodesL, v6allnodesLmask, v6allnodesL, Rmulti); /* add solicited-node multicast address */ ipv62smcast(bcast, ip); addselfcache(f, ifc, lifc, bcast, Rmulti); sendnbrdisc = 1; } /* register the address on this network for address resolution */ if(isv4(ip) && ifc->medium->areg != nil) (*ifc->medium->areg)(ifc, ip); out: wunlock(ifc); if(tentative && sendnbrdisc) icmpns(f, 0, SRC_UNSPEC, ip, TARG_MULTI, ifc->mac); return nil; }
int udprelay(int fd, char *dir) { struct { Udphdr; uchar data[8*1024]; } msg; char addr[128], ldir[40]; int r, n, rfd, cfd; uchar *p; snprint(addr, sizeof(addr), "%s/udp!*!0", outside); if((cfd = announce(addr, ldir)) < 0) return -1; if(write(cfd, "headers", 7) != 7) return -1; strcat(ldir, "/data"); if((rfd = open(ldir, ORDWR)) < 0) return -1; close(cfd); if((r = rfork(RFMEM|RFPROC|RFNOWAIT)) <= 0) return r; if((cfd = listen(dir, ldir)) < 0) return -1; close(fd); /* close inside udp server */ if((fd = accept(cfd, ldir)) < 0) return -1; switch(rfork(RFMEM|RFPROC|RFNOWAIT)){ case -1: return -1; case 0: while((r = read(fd, msg.data, sizeof(msg.data))) > 0){ if(r < 4) continue; p = msg.data; if(p[0] | p[1] | p[2]) continue; p += 3; switch(*p++){ default: continue; case 0x01: r -= 2+1+1+4+2; if(r < 0) continue; v4tov6(msg.raddr, p); p += 4; break; case 0x04: r -= 2+1+1+16+2; if(r < 0) continue; memmove(msg.raddr, p, 16); p += 16; break; } memmove(msg.rport, p, 2); p += 2; memmove(msg.data, p, r); write(rfd, &msg, sizeof(Udphdr)+r); } break; default: while((r = read(rfd, &msg, sizeof(msg))) > 0){ r -= sizeof(Udphdr); if(r < 0) continue; p = msg.data; if(isv4(msg.raddr)) n = 2+1+1+4+2; else n = 2+1+1+16+2; if(r+n > sizeof(msg.data)) r = sizeof(msg.data)-n; memmove(p+n, p, r); *p++ = 0; *p++ = 0; *p++ = 0; if(isv4(msg.raddr)){ *p++ = 0x01; v6tov4(p, msg.raddr); p += 4; } else { *p++ = 0x04; memmove(p, msg.raddr, 16); p += 16; } memmove(p, msg.rport, 2); r += n; write(fd, msg.data, r); } } return -1; }
static void ipifcregisterproxy(struct Fs *f, struct Ipifc *ifc, uint8_t * ip) { struct conv **cp, **e; struct Ipifc *nifc; struct Iplifc *lifc; struct medium *m; uint8_t net[IPaddrlen]; /* register the address on any network that will proxy for us */ e = &f->ipifc->conv[f->ipifc->nc]; if (!isv4(ip)) { // V6 for (cp = f->ipifc->conv; cp < e; cp++) { if (*cp == NULL) continue; nifc = (struct Ipifc *)(*cp)->ptcl; if (nifc == ifc) continue; rlock(&nifc->rwlock); m = nifc->m; if (m == NULL || m->addmulti == NULL) { runlock(&nifc->rwlock); continue; } for (lifc = nifc->lifc; lifc; lifc = lifc->next) { maskip(ip, lifc->mask, net); if (ipcmp(net, lifc->remote) == 0) { /* add solicited-node multicast address */ ipv62smcast(net, ip); addselfcache(f, nifc, lifc, net, Rmulti); arpenter(f, V6, ip, nifc->mac, 6, 0); //(*m->addmulti)(nifc, net, ip); break; } } runlock(&nifc->rwlock); } return; } else { // V4 for (cp = f->ipifc->conv; cp < e; cp++) { if (*cp == NULL) continue; nifc = (struct Ipifc *)(*cp)->ptcl; if (nifc == ifc) continue; rlock(&nifc->rwlock); m = nifc->m; if (m == NULL || m->areg == NULL) { runlock(&nifc->rwlock); continue; } for (lifc = nifc->lifc; lifc; lifc = lifc->next) { maskip(ip, lifc->mask, net); if (ipcmp(net, lifc->remote) == 0) { (*m->areg) (nifc, ip); break; } } runlock(&nifc->rwlock); } } }
/* * find the local address 'closest' to the remote system, copy it to * local and return the ifc for that address */ void findlocalip(struct Fs *f, uint8_t * local, uint8_t * remote) { struct Ipifc *ifc; struct Iplifc *lifc; struct route *r; uint8_t gate[IPaddrlen]; uint8_t gnet[IPaddrlen]; int version; int atype = unspecifiedv6, atypel = unknownv6; qlock(&f->ipifc->qlock); r = v6lookup(f, remote, NULL); version = isv4(remote) ? V4 : V6; if (r != NULL) { ifc = r->rt.ifc; if (r->rt.type & Rv4) v4tov6(gate, r->v4.gate); else { ipmove(gate, r->v6.gate); ipmove(local, v6Unspecified); } /* find ifc address closest to the gateway to use */ switch (version) { case V4: for (lifc = ifc->lifc; lifc; lifc = lifc->next) { maskip(gate, lifc->mask, gnet); if (ipcmp(gnet, lifc->net) == 0) { ipmove(local, lifc->local); goto out; } } break; case V6: for (lifc = ifc->lifc; lifc; lifc = lifc->next) { atypel = v6addrtype(lifc->local); maskip(gate, lifc->mask, gnet); if (ipcmp(gnet, lifc->net) == 0) if (atypel > atype) if (v6addrcurr(lifc)) { ipmove(local, lifc->local); atype = atypel; if (atype == globalv6) break; } } if (atype > unspecifiedv6) goto out; break; default: panic("findlocalip: version %d", version); } } switch (version) { case V4: findprimaryipv4(f, local); break; case V6: findprimaryipv6(f, local); break; default: panic("findlocalip2: version %d", version); } out: qunlock(&f->ipifc->qlock); }