void rudpadvise(Proto *rudp, Block *bp, char *msg) { Udphdr *h; uint8_t source[IPaddrlen], dest[IPaddrlen]; uint16_t psource, pdest; Conv *s, **p; h = (Udphdr*)(bp->rp); v4tov6(dest, h->udpdst); v4tov6(source, h->udpsrc); psource = nhgets(h->udpsport); pdest = nhgets(h->udpdport); /* Look for a connection */ for(p = rudp->conv; *p; p++) { s = *p; if(s->rport == pdest) if(s->lport == psource) if(ipcmp(s->raddr, dest) == 0) if(ipcmp(s->laddr, source) == 0){ qhangup(s->rq, msg); qhangup(s->wq, msg); break; } } freeblist(bp); }
int so_recv(int sock, void *va, int len, void *hdr, int hdrlen) { int r, l; struct sockaddr sa; struct sockaddr_in *sin; char h[Udphdrlen]; osenter(); if(doselect(sock) < 0) { osleave(); return -1; } if(hdr == 0) r = recv(sock, va, len, 0); else { sin = (struct sockaddr_in*)&sa; l = sizeof(sa); r = recvfrom(sock, va, len, 0, &sa, &l); if(r >= 0) { memset(h, sizeof h, 0); switch(hdrlen){ case OUdphdrlenv4: memmove(h, &sin->sin_addr, 4); memmove(h+2*IPv4addrlen, &sin->sin_port, 2); break; case OUdphdrlen: v4tov6(h, (uchar*)&sin->sin_addr); memmove(h+2*IPaddrlen, &sin->sin_port, 2); break; default: v4tov6(h, (uchar*)&sin->sin_addr); memmove(h+3*IPaddrlen, &sin->sin_port, 2); break; } /* alas there's no way to get the local addr/port correctly. Pretend. */ getsockname(sock, &sa, &l); switch(hdrlen){ case OUdphdrlenv4: memmove(h+IPv4addrlen, &sin->sin_addr, IPv4addrlen); memmove(h+2*IPv4addrlen+2, &sin->sin_port, 2); break; case OUdphdrlen: v4tov6(h+IPaddrlen, (uchar*)&sin->sin_addr); memmove(h+2*IPaddrlen+2, &sin->sin_port, 2); break; default: v4tov6(h+IPaddrlen, (uchar*)&sin->sin_addr); v4tov6(h+2*IPaddrlen, (uchar*)&sin->sin_addr); /* ifcaddr */ memmove(h+3*IPaddrlen+2, &sin->sin_port, 2); break; } memmove(hdr, h, hdrlen); } } osleave(); return r; }
void udpadvise(Proto *udp, Block *bp, char *msg) { Udp4hdr *h4; Udp6hdr *h6; uchar source[IPaddrlen], dest[IPaddrlen]; ushort psource, pdest; Conv *s, **p; int version; h4 = (Udp4hdr*)(bp->rp); version = ((h4->vihl&0xF0)==IP_VER6) ? 6 : 4; switch(version) { case V4: v4tov6(dest, h4->udpdst); v4tov6(source, h4->udpsrc); psource = nhgets(h4->udpsport); pdest = nhgets(h4->udpdport); break; case V6: h6 = (Udp6hdr*)(bp->rp); ipmove(dest, h6->udpdst); ipmove(source, h6->udpsrc); psource = nhgets(h6->udpsport); pdest = nhgets(h6->udpdport); break; default: panic("udpadvise: version %d", version); return; /* to avoid a warning */ } /* Look for a connection */ qlock(udp); for(p = udp->conv; *p; p++) { s = *p; if(s->rport == pdest) if(s->lport == psource) if(ipcmp(s->raddr, dest) == 0) if(ipcmp(s->laddr, source) == 0){ if(s->ignoreadvice) break; qlock(s); qunlock(udp); qhangup(s->rq, msg); qhangup(s->wq, msg); qunlock(s); freeblist(bp); return; } } qunlock(udp); freeblist(bp); }
int so_accept(int fd, unsigned char *raddr, unsigned short *rport) { int nfd; socklen_t len; struct sockaddr_storage ss; len = sizeof(ss); nfd = accept(fd, (struct sockaddr*)&ss, &len); if(nfd < 0) oserror(); switch(ss.ss_family){ case AF_INET: v4tov6(raddr, (unsigned char*)&((struct sockaddr_in*)&ss)->sin_addr.s_addr); *rport = nhgets(&((struct sockaddr_in*)&ss)->sin_port); break; case AF_INET6: memcpy(raddr, &((struct sockaddr_in6*)&ss)->sin6_addr.s6_addr, sizeof(struct in6_addr)); *rport = nhgets(&((struct sockaddr_in6*)&ss)->sin6_port); break; default: error("not AF_INET or AF_INET6"); } return nfd; }
static int parse_addr_rta(struct ifaddrmsg *addr, int len, struct in6_addr *res) { struct rtattr *rta; len -= NLMSG_ALIGN(sizeof(*addr)); rta = IFA_RTA(addr); while (RTA_OK(rta, len)) { switch(rta->rta_type) { case IFA_LOCAL: case IFA_ADDRESS: switch (addr->ifa_family) { case AF_INET: if (res) v4tov6(res->s6_addr, RTA_DATA(rta)); break; case AF_INET6: if (res) memcpy(res->s6_addr, RTA_DATA(rta), 16); break; default: kdebugf("ifaddr: unexpected address family %d\n", addr->ifa_family); return -1; break; } break; default: break; } rta = RTA_NEXT(rta, len); } return 0; }
static int resolve(char *name, char **hostv, int n, int isnumeric) { int i; struct addrinfo *res0, *r; char buf[5*8]; uchar addr[IPaddrlen]; struct addrinfo hints; memset(&hints, 0, sizeof hints); hints.ai_flags = isnumeric? AI_NUMERICHOST: 0; hints.ai_family = PF_UNSPEC; hints.ai_socktype = SOCK_STREAM; if(getaddrinfo(name, nil, &hints, &res0) < 0) return 0; i = 0; for(r = res0; r != nil && i < n; r = r->ai_next) { if(r->ai_family == AF_INET) v4tov6(addr, (uchar*)&((struct sockaddr_in*)r->ai_addr)->sin_addr); else if(r->ai_family == AF_INET6) memmove(addr, &((struct sockaddr_in6*)r->ai_addr)->sin6_addr, IPaddrlen); else continue; snprint(buf, sizeof buf, "%I", addr); hostv[i++] = strdup(buf); } freeaddrinfo(res0); return i; }
int so_send(int sock, void *va, int len, void *hdr, int hdrlen) { int r; struct sockaddr_storage sa; struct sockaddr_in6 *sin6; char *h = hdr; osenter(); if(hdr == 0) r = write(sock, va, len); else { memset(&sa, 0, sizeof(sa)); sin6 = (struct sockaddr_in6*)&sa; sin6->sin6_family = AF_INET6; switch(hdrlen){ case OUdphdrlenv4: v4tov6((uchar*)&sin6->sin6_addr, h); memmove(&sin6->sin6_port, h+8, 2); break; case OUdphdrlen: memmove((uchar*)&sin6->sin6_addr, h, IPaddrlen); memmove(&sin6->sin6_port, h+2*IPaddrlen, 2); /* rport */ break; default: memmove((uchar*)&sin6->sin6_addr, h, IPaddrlen); memmove(&sin6->sin6_port, h+3*IPaddrlen, 2); break; } r = sendto(sock, va, len, 0, (struct sockaddr*)sin6, sizeof(*sin6)); } osleave(); return r; }
uint8_t* v4defmask(uint8_t *ip) { uint8_t v6ip[IPaddrlen]; v4tov6(v6ip, ip); ip = defmask(v6ip); return ip+IPv4off; }
static void grekick(void *x, Block *bp) { Conv *c = x; GREhdr *ghp; uchar laddr[IPaddrlen], raddr[IPaddrlen]; if(bp == nil) return; /* Make space to fit ip header (gre header already there) */ bp = padblock(bp, GRE_IPONLY); if(bp == nil) return; /* make sure the message has a GRE header */ bp = pullupblock(bp, GRE_IPONLY+GRE_IPPLUSGRE); if(bp == nil) return; ghp = (GREhdr *)(bp->rp); ghp->vihl = IP_VER4; if(!((GREpriv*)c->p->priv)->raw){ v4tov6(raddr, ghp->dst); if(ipcmp(raddr, v4prefix) == 0) memmove(ghp->dst, c->raddr + IPv4off, IPv4addrlen); v4tov6(laddr, ghp->src); if(ipcmp(laddr, v4prefix) == 0){ if(ipcmp(c->laddr, IPnoaddr) == 0) findlocalip(c->p->f, c->laddr, raddr); /* pick interface closest to dest */ memmove(ghp->src, c->laddr + IPv4off, IPv4addrlen); } hnputs(ghp->eproto, c->rport); } ghp->proto = IP_GREPROTO; ghp->frag[0] = 0; ghp->frag[1] = 0; ipoput4(c->p->f, bp, 0, c->ttl, c->tos, nil); }
/* * fill in the media address if we have it. Otherwise return an * arpent that represents the state of the address resolution FSM * for ip. Add the packet to be sent onto the list of packets * waiting for ip->mac to be resolved. */ struct arpent *arpget(struct arp *arp, struct block *bp, int version, struct Ipifc *ifc, uint8_t *ip, uint8_t *mac) { int hash, len; struct arpent *a; struct medium *type = ifc->m; uint8_t v6ip[IPaddrlen]; uint16_t *s, *d; if (version == V4) { v4tov6(v6ip, ip); ip = v6ip; } qlock(&arp->qlock); hash = haship(ip); for (a = arp->hash[hash]; a; a = a->hash) { if (ipcmp(ip, a->ip) == 0) if (type == a->type) break; } if (a == NULL) { a = newarp6(arp, ip, ifc, (version != V4)); a->state = AWAIT; } a->utime = NOW; if (a->state == AWAIT) { if (bp != NULL) { if (a->hold) a->last->list = bp; else a->hold = bp; a->last = bp; bp->list = NULL; } return a; /* return with arp qlocked */ } s = (uint16_t *)a->mac; d = (uint16_t *)mac; len = a->type->maclen / 2; while (len) { *d++ = *s++; len--; } /* remove old entries */ if (NOW - a->ctime > 15 * 60 * 1000) cleanarpent(arp, a); qunlock(&arp->qlock); return NULL; }
int optgetaddr(Bootp *bp, int op, uint8_t *ip) { uint8_t *p; p = optget(bp, op, 4); if(p == 0) return 0; v4tov6(ip, p); return 1; }
char* addr2str(char *proto, uchar *a){ static char s[128]; uchar ip[16]; int n, port; if(socksver == 4){ a += 2; port = nhgets(a); a += 2; if((a[0] | a[1] | a[2]) == 0 && a[3]){ a += 4; a += strlen((char*)a)+1; snprint(s, sizeof(s), "%s!%s!%d", proto, (char*)a, port); return s; } v4tov6(ip, a); } else { a += 3; switch(*a++){ default: return nil; case 0x01: v4tov6(ip, a); port = nhgets(a+4); break; case 0x04: memmove(ip, a, 16); port = nhgets(a+16); break; case 0x03: n = *a++; port = nhgets(a+n); snprint(s, sizeof(s), "%s!%.*s!%d", proto, n, (char*)a, port); return s; } } snprint(s, sizeof(s), "%s!%I!%d", proto, ip, port); return s; }
static void getpktspiaddrs(uint8_t *pkt, Versdep *vp) { Esp4hdr *eh4; Esp6hdr *eh6; switch(vp->version) { case V4: eh4 = (Esp4hdr*)pkt; v4tov6(vp->raddr, eh4->espsrc); v4tov6(vp->laddr, eh4->espdst); vp->spi = nhgetl(eh4->espspi); break; case V6: eh6 = (Esp6hdr*)pkt; ipmove(vp->raddr, eh6->src); ipmove(vp->laddr, eh6->dst); vp->spi = nhgetl(eh6->espspi); break; default: panic("esp: getpktspiaddrs vp->version %ld wrong", vp->version); } }
void so_getsockname(int fd, unsigned char *laddr, unsigned short *lport) { socklen_t len; struct sockaddr_storage ss; len = sizeof(ss); if(getsockname(fd, (struct sockaddr*)&ss, &len) < 0) oserror(); switch(ss.ss_family){ case AF_INET: v4tov6(laddr, (unsigned char*)&((struct sockaddr_in*)&ss)->sin_addr.s_addr); *lport = nhgets(&((struct sockaddr_in*)&ss)->sin_port); break; case AF_INET6: memcpy(laddr, &((struct sockaddr_in6*)&ss)->sin6_addr.s6_addr, sizeof(struct in6_addr)); *lport = nhgets(&((struct sockaddr_in6*)&ss)->sin6_port); break; default: error("not AF_INET or AF_INET6"); } }
int nbnsfindname(uchar *serveripaddr, NbName name, uchar *ipaddr, ulong *ttlp) { NbnsMessage *nq; Alt aa[3]; int tries = NbnsRetryBroadcast; NbnsAlarm *a; int rv; NbnsMessage *response; nq = nbnsmessagenamequeryrequestnew(0, serveripaddr == nil, name); if (nq == nil) return -1; a = nbnsalarmnew(); if (a == nil) { free(nq); return -1; } aa[0].c = a->c; aa[0].v = nil; aa[0].op = CHANRCV; aa[1].op = CHANRCV; aa[2].op = CHANEND; while (tries > 0) { NbnsTransaction *t; nq->id = nbnsnextid(); t = nbnstransactionnew(nq, serveripaddr); aa[1].c = t->c; aa[1].v = &response; nbnsalarmset(a, NbnsTimeoutBroadcast); for (;;) { int i; i = alt(aa); if (i == 0) { tries--; break; } else if (i == 1) { if (response->opcode == NbnsOpQuery) { nbnstransactionfree(&t); goto done; } nbnsmessagefree(&response); } } nbnstransactionfree(&t); } done: if (tries == 0) rv = -1; else { if (response->rcode != 0) rv = response->rcode; else if (response->an == nil) rv = -1; else { rv = 0; v4tov6(ipaddr, response->an->rdata + 2); if (ttlp) *ttlp = response->an->ttl; } nbnsmessagefree(&response); } nbnsalarmfree(&a); nbnsmessagefree(&nq); return rv; }
/* * find the local address 'closest' to the remote system, copy it to * local and return the ifc for that address */ void findlocalip(Fs *f, uint8_t *local, uint8_t *remote) { int version, atype = unspecifiedv6, atypel = unknownv6; int atyper, deprecated; uint8_t gate[IPaddrlen], gnet[IPaddrlen]; Ipifc *ifc; Iplifc *lifc; Route *r; USED(atype); USED(atypel); qlock(f->ipifc); r = v6lookup(f, remote, nil); version = (memcmp(remote, v4prefix, IPv4off) == 0)? V4: V6; if(r != nil){ ifc = r->ifc; if(r->type & Rv4) v4tov6(gate, r->v4.gate); else { ipmove(gate, r->v6.gate); ipmove(local, v6Unspecified); } switch(version) { case V4: /* find ifc address closest to the gateway to use */ 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: /* find ifc address with scope matching the destination */ atyper = v6addrtype(remote); deprecated = 0; for(lifc = ifc->lifc; lifc; lifc = lifc->next){ atypel = v6addrtype(lifc->local); /* prefer appropriate scope */ if(atypel > atype && atype < atyper || atypel < atype && atype > atyper){ ipmove(local, lifc->local); deprecated = !v6addrcurr(lifc); atype = atypel; } else if(atypel == atype){ /* avoid deprecated addresses */ if(deprecated && v6addrcurr(lifc)){ ipmove(local, lifc->local); atype = atypel; deprecated = 0; } } if(atype == atyper && !deprecated) goto out; } if(atype >= atyper) 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); }
void espiput(Proto *esp, Ipifc*, Block *bp) { Esphdr *eh; Esptail *et; Userhdr *uh; Conv *c; Espcb *ecb; uchar raddr[IPaddrlen], laddr[IPaddrlen]; Fs *f; uchar *auth; ulong spi; int payload, nexthdr; f = esp->f; bp = pullupblock(bp, EsphdrSize+EsptailSize); if(bp == nil) { netlog(f, Logesp, "esp: short packet\n"); return; } eh = (Esphdr*)(bp->rp); spi = nhgetl(eh->espspi); v4tov6(raddr, eh->espsrc); v4tov6(laddr, eh->espdst); qlock(esp); /* Look for a conversation structure for this port */ c = convlookup(esp, spi); if(c == nil) { qunlock(esp); netlog(f, Logesp, "esp: no conv %I -> %I!%d\n", raddr, laddr, spi); icmpnoconv(f, bp); freeblist(bp); return; } qlock(c); qunlock(esp); ecb = c->ptcl; // too hard to do decryption/authentication on block lists if(bp->next) bp = concatblock(bp); if(BLEN(bp) < EsphdrSize + ecb->espivlen + EsptailSize + ecb->ahlen) { qunlock(c); netlog(f, Logesp, "esp: short block %I -> %I!%d\n", raddr, laddr, spi); freeb(bp); return; } eh = (Esphdr*)(bp->rp); auth = bp->wp - ecb->ahlen; if(!ecb->auth(ecb, eh->espspi, auth-eh->espspi, auth)) { qunlock(c); print("esp: bad auth %I -> %I!%ld\n", raddr, laddr, spi); netlog(f, Logesp, "esp: bad auth %I -> %I!%d\n", raddr, laddr, spi); freeb(bp); return; } payload = BLEN(bp)-EsphdrSize-ecb->ahlen; if(payload<=0 || payload%4 != 0 || payload%ecb->espblklen!=0) { qunlock(c); netlog(f, Logesp, "esp: bad length %I -> %I!%d payload=%d BLEN=%d\n", raddr, laddr, spi, payload, BLEN(bp)); freeb(bp); return; } if(!ecb->cipher(ecb, bp->rp+EsphdrSize, payload)) { qunlock(c); print("esp: cipher failed %I -> %I!%ld: %r\n", raddr, laddr, spi); netlog(f, Logesp, "esp: cipher failed %I -> %I!%d: %r\n", raddr, laddr, spi); freeb(bp); return; } payload -= EsptailSize; et = (Esptail*)(bp->rp + EsphdrSize + payload); payload -= et->pad + ecb->espivlen; nexthdr = et->nexthdr; if(payload <= 0) { qunlock(c); netlog(f, Logesp, "esp: short packet after decrypt %I -> %I!%d\n", raddr, laddr, spi); freeb(bp); return; } // trim packet bp->rp += EsphdrSize + ecb->espivlen; bp->wp = bp->rp + payload; if(ecb->header) { // assume UserhdrSize < EsphdrSize bp->rp -= UserhdrSize; uh = (Userhdr*)bp->rp; memset(uh, 0, UserhdrSize); uh->nexthdr = nexthdr; } if(qfull(c->rq)){ netlog(f, Logesp, "esp: qfull %I -> %I.%uld\n", raddr, laddr, spi); freeblist(bp); }else { //print("esp: pass up: %uld\n", BLEN(bp)); qpass(c->rq, bp); } qunlock(c); }
static int parse_kernel_route_rta(struct rtmsg *rtm, int len, struct kernel_route *route) { int table = rtm->rtm_table; struct rtattr *rta= RTM_RTA(rtm);; len -= NLMSG_ALIGN(sizeof(*rtm)); memset(&route->prefix, 0, sizeof(struct in6_addr)); memset(&route->gw, 0, sizeof(struct in6_addr)); route->plen = rtm->rtm_dst_len; if(rtm->rtm_family == AF_INET) { const unsigned char zeroes[4] = {0, 0, 0, 0}; v4tov6(route->prefix, zeroes); route->plen += 96; } route->metric = 0; route->ifindex = 0; route->proto = rtm->rtm_protocol; #define COPY_ADDR(d, s) \ do { \ if(rtm->rtm_family == AF_INET6) \ memcpy(d, s, 16); \ else if(rtm->rtm_family == AF_INET) \ v4tov6(d, s); \ else \ return -1; \ } while(0) while(RTA_OK(rta, len)) { switch (rta->rta_type) { case RTA_DST: COPY_ADDR(route->prefix, RTA_DATA(rta)); break; case RTA_GATEWAY: COPY_ADDR(route->gw, RTA_DATA(rta)); break; case RTA_OIF: route->ifindex = *(int*)RTA_DATA(rta); break; case RTA_PRIORITY: route->metric = *(int*)RTA_DATA(rta); if(route->metric < 0 || route->metric > KERNEL_INFINITY) route->metric = KERNEL_INFINITY; break; case RTA_TABLE: table = *(int*)RTA_DATA(rta); break; default: break; } rta = RTA_NEXT(rta, len); } #undef COPY_ADDR if(table != import_table) return -1; return 0; }
static void greiput(Proto *gre, Ipifc*, Block *bp) { int len; GREhdr *ghp; Conv *c, **p; ushort eproto; uchar raddr[IPaddrlen]; GREpriv *gpriv; gpriv = gre->priv; ghp = (GREhdr*)(bp->rp); v4tov6(raddr, ghp->src); eproto = nhgets(ghp->eproto); qlock(gre); /* Look for a conversation structure for this port and address */ c = nil; for(p = gre->conv; *p; p++) { c = *p; if(c->inuse == 0) continue; if(c->rport == eproto && (gpriv->raw || ipcmp(c->raddr, raddr) == 0)) break; } if(*p == nil) { qunlock(gre); freeblist(bp); return; } qunlock(gre); /* * Trim the packet down to data size */ len = nhgets(ghp->len) - GRE_IPONLY; if(len < GRE_IPPLUSGRE){ freeblist(bp); return; } bp = trimblock(bp, GRE_IPONLY, len); if(bp == nil){ gpriv->lenerr++; return; } /* * Can't delimit packet so pull it all into one block. */ if(qlen(c->rq) > 64*1024) freeblist(bp); else{ bp = concatblock(bp); if(bp == 0) panic("greiput"); qpass(c->rq, bp); } }
static int parse_kernel_route(const struct rt_msghdr *rtm, struct kernel_route *route) { struct sockaddr *sa; char *rta = (char*)rtm + sizeof(struct rt_msghdr); uint32_t excluded_flags = 0; if(ifindex_lo < 0) { ifindex_lo = if_nametoindex("lo0"); if(ifindex_lo <= 0) return -1; } memset(route, 0, sizeof(*route)); route->metric = 0; route->ifindex = rtm->rtm_index; #if defined(RTF_IFSCOPE) /* Filter out kernel route on OS X */ excluded_flags |= RTF_IFSCOPE; #endif #if defined(RTF_MULTICAST) /* Filter out multicast route on others BSD */ excluded_flags |= RTF_MULTICAST; #endif /* Filter out our own route */ excluded_flags |= RTF_PROTO2; if((rtm->rtm_flags & excluded_flags) != 0) return -1; /* Prefix */ if(!(rtm->rtm_addrs & RTA_DST)) return -1; sa = (struct sockaddr *)rta; rta += ROUNDUP(sa->sa_len); if(sa->sa_family == AF_INET6) { struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa; memcpy(route->prefix, &sin6->sin6_addr, 16); if(IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) || IN6_IS_ADDR_MC_LINKLOCAL(&sin6->sin6_addr)) return -1; } else if(sa->sa_family == AF_INET) { struct sockaddr_in *sin = (struct sockaddr_in *)sa; #if defined(IN_LINKLOCAL) if(IN_LINKLOCAL(ntohl(sin->sin_addr.s_addr))) return -1; #endif if(IN_MULTICAST(ntohl(sin->sin_addr.s_addr))) return -1; v4tov6(route->prefix, (unsigned char *)&sin->sin_addr); } else { return -1; } /* Gateway */ if(!(rtm->rtm_addrs & RTA_GATEWAY)) return -1; sa = (struct sockaddr *)rta; rta += ROUNDUP(sa->sa_len); if(sa->sa_family == AF_INET6) { struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa; memcpy(route->gw, &sin6->sin6_addr, 16); if(IN6_IS_ADDR_LINKLOCAL (&sin6->sin6_addr)) { route->ifindex = IN6_LINKLOCAL_IFINDEX(sin6->sin6_addr); SET_IN6_LINKLOCAL_IFINDEX(sin6->sin6_addr, 0); } } else if(sa->sa_family == AF_INET) { struct sockaddr_in *sin = (struct sockaddr_in *)sa; v4tov6(route->gw, (unsigned char *)&sin->sin_addr); } if((int)route->ifindex == ifindex_lo) return -1; /* Netmask */ if((rtm->rtm_addrs & RTA_NETMASK) != 0) { sa = (struct sockaddr *)rta; rta += ROUNDUP(sa->sa_len); if(!v4mapped(route->prefix)) { struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa; route->plen = mask2len((unsigned char*)&sin6->sin6_addr, 16); } else { struct sockaddr_in *sin = (struct sockaddr_in *)sa; route->plen = mask2len((unsigned char*)&sin->sin_addr, 4); } } if(v4mapped(route->prefix)) route->plen += 96; if(rtm->rtm_flags & RTF_HOST) route->plen = 128; return 0; }
/* * broadcast routes onto all networks */ void sendto(Ifc *ip) { int h, n; uint8_t raddr[Pasize], mbuf[Udphdrsize+512]; Ripmsg *m; Route *r; Udphdr *u; u = (Udphdr*)mbuf; for(n = 0; n < Pasize; n++) raddr[n] = ip->net[n] | ~(ip->mask[n]); v4tov6(u->raddr, raddr); hnputs(u->rport, 520); m = (Ripmsg*)(mbuf+Udphdrsize); m->type = Response; m->vers = Version; if(debug) fprint(2, "to %V\n", u->raddr); n = 0; for(h = 0; h < Nhash; h++){ for(r = ralloc.hash[h]; r; r = r->next){ /* * don't send any route back to the net * it came from */ if(onnet(r->gate, ip->net, ip->mask)) continue; /* * don't tell a network about itself */ if(equivip(r->dest, ip->net)) continue; /* * don't tell nets about other net's subnets */ if(!equivip(r->mask, v4defmask(r->dest)) && !equivip(ip->cmask, v4defmask(r->dest))) continue; memset(&m->rip[n], 0, sizeof(m->rip[n])); memmove(m->rip[n].addr, r->dest, Pasize); if(r->metric < 1) hnputl(m->rip[n].metric, 1); else hnputl(m->rip[n].metric, r->metric); hnputs(m->rip[n].family, AF_INET); if(debug) fprint(2, " %16V & %16V -> %16V %2d\n", r->dest, r->mask, r->gate, r->metric); if(++n == Maxroutes && !readonly){ write(ripfd, mbuf, Udphdrsize + 4 + n*20); n = 0; } } } if(n && !readonly) write(ripfd, mbuf, Udphdrsize+4+n*20); }
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; }
void dhcprecv(void) { uint8_t buf[2000]; Bootp *bp; int n, type; uint32_t lease; uint8_t mask[IPaddrlen]; qunlock(&dhcp.lk); n = read(dhcp.fd, buf, sizeof(buf)); qlock(&dhcp.lk); if(n <= 0) myfatal("dhcprecv: bad read: %r"); bp = parse(buf, n); if(bp == 0) return; if(1) { fprint(2, "recved\n"); bootpdump(buf, n); } type = optgetbyte(bp, ODtype); switch(type) { default: fprint(2, "dhcprecv: unknown type: %d\n", type); break; case Offer: if(dhcp.state != Sselecting) break; lease = optgetulong(bp, ODlease); if(lease == 0) myfatal("bad lease"); if(!optgetaddr(bp, OBmask, mask)) memset(mask, 0xff, sizeof(mask)); v4tov6(dhcp.client, bp->yiaddr); if(!optgetaddr(bp, ODserverid, dhcp.server)) { fprint(2, "dhcprecv: Offer from server with invalid serverid\n"); break; } dhcp.lease = lease; ipmove(dhcp.mask, mask); memmove(dhcp.sname, bp->sname, sizeof(dhcp.sname)); dhcp.sname[sizeof(dhcp.sname)-1] = 0; dhcpsend(Request); dhcp.state = Srequesting; dhcp.resend = 0; dhcp.timeout = 4; break; case Ack: if(dhcp.state != Srequesting) if(dhcp.state != Srenewing) if(dhcp.state != Srebinding) break; lease = optgetulong(bp, ODlease); if(lease == 0) myfatal("bad lease"); if(!optgetaddr(bp, OBmask, mask)) memset(mask, 0xff, sizeof(mask)); v4tov6(dhcp.client, bp->yiaddr); dhcp.lease = lease; ipmove(dhcp.mask, mask); dhcp.state = Sbound; break; case Nak: myfatal("recved nak"); break; } }
void rudpiput(Proto *rudp, Ipifc *ifc, Block *bp) { int len, olen, ottl; Udphdr *uh; Conv *c; Rudpcb *ucb; uint8_t raddr[IPaddrlen], laddr[IPaddrlen]; uint16_t rport, lport; Rudppriv *upriv; Fs *f; uint8_t *p; upriv = rudp->priv; f = rudp->f; upriv->ustats.rudpInDatagrams++; uh = (Udphdr*)(bp->rp); /* Put back pseudo header for checksum * (remember old values for icmpnoconv()) */ ottl = uh->Unused; uh->Unused = 0; len = nhgets(uh->udplen); olen = nhgets(uh->udpplen); hnputs(uh->udpplen, len); v4tov6(raddr, uh->udpsrc); v4tov6(laddr, uh->udpdst); lport = nhgets(uh->udpdport); rport = nhgets(uh->udpsport); if(nhgets(uh->udpcksum)) { if(ptclcsum(bp, UDP_IPHDR, len+UDP_PHDRSIZE)) { upriv->ustats.rudpInErrors++; upriv->csumerr++; netlog(f, Logrudp, "rudp: checksum error %I\n", raddr); DPRINT("rudp: checksum error %I\n", raddr); freeblist(bp); return; } } qlock(&rudp->ql); c = iphtlook(&upriv->ht, raddr, rport, laddr, lport); if(c == nil){ /* no conversation found */ upriv->ustats.rudpNoPorts++; qunlock(&rudp->ql); netlog(f, Logudp, "udp: no conv %I!%d -> %I!%d\n", raddr, rport, laddr, lport); uh->Unused = ottl; hnputs(uh->udpplen, olen); icmpnoconv(f, bp); freeblist(bp); return; } ucb = (Rudpcb*)c->ptcl; qlock(&ucb->ql); qunlock(&rudp->ql); if(reliput(c, bp, raddr, rport) < 0){ qunlock(&ucb->ql); freeb(bp); return; } /* * Trim the packet down to data size */ len -= (UDP_RHDRSIZE-UDP_PHDRSIZE); bp = trimblock(bp, UDP_IPHDR+UDP_RHDRSIZE, len); if(bp == nil) { netlog(f, Logrudp, "rudp: len err %I.%d -> %I.%d\n", raddr, rport, laddr, lport); DPRINT("rudp: len err %I.%d -> %I.%d\n", raddr, rport, laddr, lport); upriv->lenerr++; return; } netlog(f, Logrudpmsg, "rudp: %I.%d -> %I.%d l %d\n", raddr, rport, laddr, lport, len); switch(ucb->headers){ case 7: /* pass the src address */ bp = padblock(bp, UDP_USEAD7); p = bp->rp; ipmove(p, raddr); p += IPaddrlen; ipmove(p, laddr); p += IPaddrlen; ipmove(p, ifc->lifc->local); p += IPaddrlen; hnputs(p, rport); p += 2; hnputs(p, lport); break; default: /* connection oriented rudp */ if(ipcmp(c->raddr, IPnoaddr) == 0){ /* save the src address in the conversation */ ipmove(c->raddr, raddr); c->rport = rport; /* reply with the same ip address (if not broadcast) */ if(ipforme(f, laddr) == Runi) ipmove(c->laddr, laddr); else v4tov6(c->laddr, ifc->lifc->local); } break; } if(bp->next) bp = concatblock(bp); if(qfull(c->rq)) { netlog(f, Logrudp, "rudp: qfull %I.%d -> %I.%d\n", raddr, rport, laddr, lport); freeblist(bp); } else qpass(c->rq, bp); qunlock(&ucb->ql); }
void udpiput(struct Proto *udp, struct Ipifc *ifc, struct block *bp) { int len; Udp4hdr *uh4; Udp6hdr *uh6; struct conv *c; Udpcb *ucb; uint8_t raddr[IPaddrlen], laddr[IPaddrlen]; uint16_t rport, lport; Udppriv *upriv; struct Fs *f; int version; int ottl, oviclfl, olen; uint8_t *p; upriv = udp->priv; f = udp->f; upriv->ustats.udpInDatagrams++; uh4 = (Udp4hdr *) (bp->rp); version = ((uh4->vihl & 0xF0) == IP_VER6) ? V6 : V4; /* * Put back pseudo header for checksum * (remember old values for icmpnoconv()) */ switch (version) { case V4: ottl = uh4->Unused; uh4->Unused = 0; len = nhgets(uh4->udplen); olen = nhgets(uh4->udpplen); hnputs(uh4->udpplen, len); v4tov6(raddr, uh4->udpsrc); v4tov6(laddr, uh4->udpdst); lport = nhgets(uh4->udpdport); rport = nhgets(uh4->udpsport); if (!(bp->flag & Budpck) && (uh4->udpcksum[0] || uh4->udpcksum[1]) && ptclcsum(bp, UDP4_PHDR_OFF, len + UDP4_PHDR_SZ)) { upriv->ustats.udpInErrors++; netlog(f, Logudp, "udp: checksum error %I\n", raddr); printd("udp: checksum error %I\n", raddr); freeblist(bp); return; } uh4->Unused = ottl; hnputs(uh4->udpplen, olen); break; case V6: uh6 = (Udp6hdr *) (bp->rp); len = nhgets(uh6->udplen); oviclfl = nhgetl(uh6->viclfl); olen = nhgets(uh6->len); ottl = uh6->hoplimit; ipmove(raddr, uh6->udpsrc); ipmove(laddr, uh6->udpdst); lport = nhgets(uh6->udpdport); rport = nhgets(uh6->udpsport); memset(uh6, 0, 8); hnputl(uh6->viclfl, len); uh6->hoplimit = IP_UDPPROTO; if (ptclcsum(bp, UDP6_PHDR_OFF, len + UDP6_PHDR_SZ)) { upriv->ustats.udpInErrors++; netlog(f, Logudp, "udp: checksum error %I\n", raddr); printd("udp: checksum error %I\n", raddr); freeblist(bp); return; } hnputl(uh6->viclfl, oviclfl); hnputs(uh6->len, olen); uh6->nextheader = IP_UDPPROTO; uh6->hoplimit = ottl; break; default: panic("udpiput: version %d", version); return; /* to avoid a warning */ } qlock(&udp->qlock); c = iphtlook(&upriv->ht, raddr, rport, laddr, lport); if (c == NULL) { /* no converstation found */ upriv->ustats.udpNoPorts++; qunlock(&udp->qlock); netlog(f, Logudp, "udp: no conv %I!%d -> %I!%d\n", raddr, rport, laddr, lport); switch (version) { case V4: icmpnoconv(f, bp); break; case V6: icmphostunr(f, ifc, bp, icmp6_port_unreach, 0); break; default: panic("udpiput2: version %d", version); } freeblist(bp); return; } ucb = (Udpcb *) c->ptcl; if (c->state == Announced) { if (ucb->headers == 0) { /* create a new conversation */ if (ipforme(f, laddr) != Runi) { switch (version) { case V4: v4tov6(laddr, ifc->lifc->local); break; case V6: ipmove(laddr, ifc->lifc->local); break; default: panic("udpiput3: version %d", version); } } c = Fsnewcall(c, raddr, rport, laddr, lport, version); if (c == NULL) { qunlock(&udp->qlock); freeblist(bp); return; } iphtadd(&upriv->ht, c); ucb = (Udpcb *) c->ptcl; } } qlock(&c->qlock); qunlock(&udp->qlock); /* * Trim the packet down to data size */ len -= UDP_UDPHDR_SZ; switch (version) { case V4: bp = trimblock(bp, UDP4_IPHDR_SZ + UDP_UDPHDR_SZ, len); break; case V6: bp = trimblock(bp, UDP6_IPHDR_SZ + UDP_UDPHDR_SZ, len); break; default: bp = NULL; panic("udpiput4: version %d", version); } if (bp == NULL) { qunlock(&c->qlock); netlog(f, Logudp, "udp: len err %I.%d -> %I.%d\n", raddr, rport, laddr, lport); upriv->lenerr++; return; } netlog(f, Logudpmsg, "udp: %I.%d -> %I.%d l %d\n", raddr, rport, laddr, lport, len); switch (ucb->headers) { case 7: /* pass the src address */ bp = padblock(bp, UDP_USEAD7); p = bp->rp; ipmove(p, raddr); p += IPaddrlen; ipmove(p, laddr); p += IPaddrlen; ipmove(p, ifc->lifc->local); p += IPaddrlen; hnputs(p, rport); p += 2; hnputs(p, lport); break; case 6: /* pass the src address */ bp = padblock(bp, UDP_USEAD6); p = bp->rp; ipmove(p, raddr); p += IPaddrlen; ipmove(p, ipforme(f, laddr) == Runi ? laddr : ifc->lifc->local); p += IPaddrlen; hnputs(p, rport); p += 2; hnputs(p, lport); break; } if (bp->next) bp = concatblock(bp); if (qfull(c->rq)) { qunlock(&c->qlock); netlog(f, Logudp, "udp: qfull %I.%d -> %I.%d\n", raddr, rport, laddr, lport); freeblist(bp); return; } qpass(c->rq, bp); qunlock(&c->qlock); }
/* * lookup info about a client in the database. Find an address on the * same net as riip. */ int lookup(Bootp *bp, Info *iip, Info *riip) { Ndbtuple *t, *nt; Ndbs s; char *hwattr; char *hwval, hwbuf[33]; uchar ciaddr[IPaddrlen]; if(opendb() == nil){ warning(1, "can't open db"); return -1; } memset(iip, 0, sizeof(*iip)); /* client knows its address? */ v4tov6(ciaddr, bp->ciaddr); if(validip(ciaddr)){ if(lookupip(ciaddr, iip, 0) < 0) { if (debug) warning(0, "don't know %I", ciaddr); return -1; /* don't know anything about it */ } if(!samenet(riip->ipaddr, iip)){ warning(0, "%I not on %I", ciaddr, riip->ipnet); return -1; } /* * see if this is a masquerade, i.e., if the ether * address doesn't match what we expected it to be. */ if(memcmp(iip->etheraddr, zeroes, 6) != 0) if(memcmp(bp->chaddr, iip->etheraddr, 6) != 0) warning(0, "ciaddr %I rcvd from %E instead of %E", ciaddr, bp->chaddr, iip->etheraddr); return 0; } if(bp->hlen > Maxhwlen) return -1; switch(bp->htype){ case 1: hwattr = "ether"; hwval = hwbuf; snprint(hwbuf, sizeof(hwbuf), "%E", bp->chaddr); break; default: syslog(0, blog, "not ethernet %E, htype %d, hlen %d", bp->chaddr, bp->htype, bp->hlen); return -1; } /* * use hardware address to find an ip address on * same net as riip */ t = ndbsearch(db, &s, hwattr, hwval); while(t){ for(nt = t; nt; nt = nt->entry){ if(strcmp(nt->attr, "ip") != 0) continue; parseip(ciaddr, nt->val); if(lookupip(ciaddr, iip, 0) < 0) continue; if(samenet(riip->ipaddr, iip)){ ndbfree(t); return 0; } } ndbfree(t); t = ndbsnext(&s, hwattr, hwval); } return -1; }
void arpenter(struct Fs *fs, int version, uint8_t *ip, uint8_t *mac, int n, int refresh) { ERRSTACK(1); struct arp *arp; struct route *r; struct arpent *a, *f, **l; struct Ipifc *ifc; struct medium *type; struct block *bp, *next; uint8_t v6ip[IPaddrlen]; arp = fs->arp; if (n != 6) { return; } switch (version) { case V4: r = v4lookup(fs, ip, NULL); v4tov6(v6ip, ip); ip = v6ip; break; case V6: r = v6lookup(fs, ip, NULL); break; default: panic("arpenter: version %d", version); return; /* to supress warnings */ } if (r == NULL) { return; } ifc = r->rt.ifc; type = ifc->m; qlock(&arp->qlock); for (a = arp->hash[haship(ip)]; a; a = a->hash) { if (a->type != type || (a->state != AWAIT && a->state != AOK)) continue; if (ipcmp(a->ip, ip) == 0) { a->state = AOK; memmove(a->mac, mac, type->maclen); if (version == V6) { /* take out of re-transmit chain */ l = &arp->rxmt; for (f = *l; f; f = f->nextrxt) { if (f == a) { *l = a->nextrxt; break; } l = &f->nextrxt; } } a->ifc = ifc; a->ifcid = ifc->ifcid; bp = a->hold; a->hold = NULL; if (version == V4) ip += IPv4off; a->utime = NOW; a->ctime = a->utime; qunlock(&arp->qlock); while (bp) { next = bp->list; if (ifc != NULL) { rlock(&ifc->rwlock); if (waserror()) { runlock(&ifc->rwlock); nexterror(); } if (ifc->m != NULL) ifc->m->bwrite(ifc, bp, version, ip); else freeb(bp); runlock(&ifc->rwlock); poperror(); } else freeb(bp); bp = next; } return; } } if (refresh == 0) { a = newarp6(arp, ip, ifc, 0); a->state = AOK; a->type = type; a->ctime = NOW; memmove(a->mac, mac, type->maclen); } qunlock(&arp->qlock); }
/* * 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); }