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; }
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 wantsession(uint8_t *pkt) { int len; uint8_t *s; Pppoehdr *ph; ph = (Pppoehdr*)(pkt+EtherHdrSz); if(ph->code != CodeDiscSess) return bad("not a session confirmation"); if(nhgets(ph->sessid) == 0x0000) return bad("bad session id"); if(findtag(pkt, TagSrvName, &len, 0) == nil) return bad("no service name"); if(findtag(pkt, TagSrvNameErr, &len, 0)) return bad("service name error"); if(findtag(pkt, TagAcSysErr, &len, 0)) return bad("ac system error"); /* * rsc said: ``if there is no -S option given, the current code * waits for an offer with service name == "". * that's silly. it should take the first one it gets.'' */ if(srvname[0] != '\0') { if((s = findtag(pkt, TagSrvName, &len, 0)) == nil) return bad("no matching service name"); if(len != strlen(srvname) || memcmp(s, srvname, len) != 0) return bad("no matching service name"); } sessid = nhgets(ph->sessid); return 1; }
uint8_t* findtag(uint8_t *pkt, int tagtype, int *plen, int skip) { int len, sz, totlen; uint8_t *tagdat, *v; Etherhdr *eh; Pppoehdr *ph; Taghdr *t; eh = (Etherhdr*)pkt; ph = (Pppoehdr*)(pkt+EtherHdrSz); tagdat = pkt+Hdr; if(nhgets(eh->type) != EtherPppoeDiscovery) return nil; totlen = nhgets(ph->length); sz = 0; while(sz+4 <= totlen){ t = (Taghdr*)(tagdat+sz); v = tagdat+sz+4; len = nhgets(t->length); if(sz+4+len > totlen) break; if(nhgets(t->type) == tagtype && skip-- == 0){ *plen = len; return v; } sz += 2+2+len; } return nil; }
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); }
static void sunudpread(void *v) { int n, paraport, port; uchar *buf; Arg arg = *(Arg*)v; SunMsgUdp *msg; SunSrv *srv; Udphdr udp; uchar localip[IPaddrlen]; sendp(arg.csync, 0); srv = arg.srv; paraport = -1; /* 127.1 */ memmove(localip, v4prefix, IPaddrlen); localip[12] = 127; localip[15] = 1; buf = emalloc(UdpMaxRead); while((n = udpread(arg.fd, &udp, buf, UdpMaxRead)) > 0){ if(arg.srv->chatty) fprint(2, "udpread got %d (%d) from %I\n", n, Udphdrsize, udp.raddr); msg = emalloc(sizeof(SunMsgUdp)); msg->udp = udp; msg->msg.data = emalloc(n); msg->msg.count = n; memmove(msg->msg.data, buf, n); msg->msg.creply = arg.creply; msg->msg.srv = arg.srv; if(arg.srv->chatty) fprint(2, "message %p count %d\n", msg, msg->msg.count); if((srv->localonly || srv->localparanoia) && ipcmp(udp.raddr, localip) != 0){ fprint(2, "dropping message from %I: not local\n", udp.raddr); sunmsgreplyerror(&msg->msg, SunAuthTooWeak); continue; } if(srv->localparanoia){ port = nhgets(udp.rport); if(paraport == -1){ fprint(2, "paranoid mode: only %I/%d allowed\n", localip, port); paraport = port; }else if(paraport != port){ fprint(2, "dropping message from %I: not port %d\n", udp.raddr, port); sunmsgreplyerror(&msg->msg, SunAuthTooWeak); continue; } } if(srv->ipokay && !srv->ipokay(udp.raddr, nhgets(udp.rport))) msg->msg.rpc.status = SunProgUnavail; sendp(arg.srv->crequest, msg); } }
void dumptags(uint8_t *tagdat, int ntagdat) { int i,len, sz; uint8_t *v; Taghdr *t; sz = 0; while(sz+4 <= ntagdat){ t = (Taghdr*)(tagdat+sz); v = tagdat+sz+2+2; len = nhgets(t->length); if(sz+4+len > ntagdat) break; fprint(2, "\t0x%x %d: ", nhgets(t->type), len); switch(nhgets(t->type)){ case TagEnd: fprint(2, "end of tag list\n"); break; case TagSrvName: fprint(2, "service '%.*s'\n", len, (char*)v); break; case TagAcName: fprint(2, "ac '%.*s'\n", len, (char*)v); break; case TagHostUniq: fprint(2, "nonce "); Hex: for(i=0; i<len; i++) fprint(2, "%.2x", v[i]); fprint(2, "\n"); break; case TagAcCookie: fprint(2, "ac cookie "); goto Hex; case TagVendSpec: fprint(2, "vend spec "); goto Hex; case TagRelaySessId: fprint(2, "relay "); goto Hex; case TagSrvNameErr: fprint(2, "srverr '%.*s'\n", len, (char*)v); break; case TagAcSysErr: fprint(2, "syserr '%.*s'\n", len, (char*)v); break; } sz += 2+2+len; } if(sz != ntagdat) fprint(2, "warning: only dumped %d of %d bytes\n", sz, ntagdat); }
int so_accept(int fd, uchar *raddr, ushort *rport) { int nfd; socklen_t len; struct sockaddr sa; struct sockaddr_in *sin; sin = (struct sockaddr_in*)&sa; len = sizeof(sa); osenter(); if(doselect(fd) < 0) { osleave(); return -1; } nfd = accept(fd, &sa, &len); osleave(); if(nfd < 0) oserror(); if(sin->sin_family != AF_INET || len != sizeof(*sin)) error(Enotv4); ipw6(raddr, sin->sin_addr.s_addr); *rport = nhgets(&sin->sin_port); return nfd; }
int so_accept(int fd, unsigned long *raddr, unsigned short *rport) { int nfd, len; struct sockaddr sa; struct sockaddr_in *sin; sin = (struct sockaddr_in*)&sa; len = sizeof(sa); osenter(); if(doselect(fd) < 0) { osleave(); return -1; } nfd = accept(fd, &sa, &len); osleave(); if(nfd < 0) oserror(); if(sin->sin_family != AF_INET || len != sizeof(*sin)) error("not AF_INET"); *raddr = nhgetl(&sin->sin_addr.s_addr); *rport = nhgets(&sin->sin_port); return nfd; }
/* notify a slave that an area has changed. */ static void send_notify(char *slave, RR *soa, Request *req) { int i, len, n, reqno, status, fd; char *err; uchar ibuf[Maxudp+Udphdrsize], obuf[Maxudp+Udphdrsize]; RR *rp; Udphdr *up = (Udphdr*)obuf; DNSmsg repmsg; /* create the request */ reqno = rand(); n = mkreq(soa->owner, Cin, obuf, Fauth | Onotify, reqno); /* get an address */ if(strcmp(ipattr(slave), "ip") == 0) { if (parseip(up->raddr, slave) == -1) dnslog("bad address %s to notify", slave); } else { rp = dnresolve(slave, Cin, Ta, req, nil, 0, 1, 1, &status); if(rp == nil) rp = dnresolve(slave, Cin, Taaaa, req, nil, 0, 1, 1, &status); if(rp == nil) return; parseip(up->raddr, rp->ip->name); rrfreelist(rp); /* was rrfree */ } fd = udpport(nil); if(fd < 0) return; /* send 3 times or until we get anything back */ n += Udphdrsize; for(i = 0; i < 3; i++, freeanswers(&repmsg)){ dnslog("sending %d byte notify to %s/%I.%d about %s", n, slave, up->raddr, nhgets(up->rport), soa->owner->name); memset(&repmsg, 0, sizeof repmsg); if(write(fd, obuf, n) != n) break; alarm(2*1000); len = read(fd, ibuf, sizeof ibuf); alarm(0); if(len <= Udphdrsize) continue; err = convM2DNS(&ibuf[Udphdrsize], len, &repmsg, nil); if(err != nil) { free(err); continue; } if(repmsg.id == reqno && (repmsg.flags & Omask) == Onotify) break; } if (i < 3) freeanswers(&repmsg); close(fd); }
static int _nameextract(uchar *base, uchar *p, uchar *ep, int k, uchar *outbuf, int outbufmaxlen, int *outbuflenp) { uchar *op, *oep, *savep; savep = p; op = outbuf; oep = outbuf + outbufmaxlen; for (;;) { uchar b; int n; if (p >= ep) return 0; b = *p++; if (b == 0) break; if (k) { if (op >= oep) return 0; *op++ = '.'; } if ((b & 0xc0) == 0xc0) { ushort off; if (ep - p < 2) return 0; off = nhgets(p - 1) & 0x3fff; p++; if (_nameextract(base, base + off, p, k, op, oep - ep, &n) == 0) return 0; op += n; } else if ((b & 0xc0) != 0x00) return 0; else if (b != 0x20) return 0; else { int x; if (p + b > ep) return 0; if (op + b / 2 > oep) return 0; for (x = 0; x < b; x += 2) { uchar hn, ln; if (*p < 'A' || *p >= 'A' + 16) return 0; hn = *p++ - 'A'; if (*p < 'A' || *p >= 'A' + 16) return 0; ln = *p++ - 'A'; *op++ = (hn << 4) | ln; } } k++; } *outbuflenp = op - outbuf; return p - savep; }
long nbssscatterread(NbSession *nbs, NbScatterGather *a) { uchar hdr[4]; uchar flags; long length, total; NbScatterGather *ap; Session *s = (Session *)nbs; long l = 0; for (ap = a; ap->p; ap++) l += ap->l; //print("nbssscatterread %ld bytes\n", l); again: if (readn(s->fd, hdr, 4) != 4) { dead: s->state = Dead; return -1; } flags = hdr[1]; length = nhgets(hdr + 2) | ((flags & 1) << 16); //print("%.2ux: %d\n", hdr[0], length); switch (hdr[0]) { case 0x85: if (length != 0) { werrstr("length in keepalive not 0"); goto dead; } goto again; case 0x00: break; default: werrstr("unexpected session message code 0x%.2ux", hdr[0]); goto dead; } if (length > l) { werrstr("message too big (%ld)", length); goto dead; } total = length; for (ap = a; length && ap->p; ap++) { long thistime; long n; thistime = length; if (thistime > ap->l) thistime = ap->l; //print("reading %d\n", length); n = readn(s->fd, ap->p, thistime); if (n != thistime) goto dead; length -= thistime; } return total; }
int so_getservbyname(char *service, char *net, char *port) { struct servent *s; s = getservbyname(service, net); if(s == 0) return -1; sprint(port, "%d", nhgets(&s->s_port)); return 0; }
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; }
int recv_tcp(char *p, int len, nw_skt_t fd) { int recv_len, pkt_size, total_recv_len = 0, num_attempts = 0; if (fd < 0) { //TODO XXX Fix this.. I3_PRINT_DEBUG1 (I3_DEBUG_LEVEL_VERBOSE, "invalid fd = %d\n",fd); return -1; } /* recv header */ recv_len = recv(fd, p, TCP_I3_HEADER_SIZE, 0); if (recv_len < 0) { perror("TCP header recv"); fprintf (stderr, " on fd %d\n\n", fd); nw_close (fd); return recv_len; } /* recv rest of the packet */ if (recv_len > 0) { if( (TCP_I3_HEADER_MAGIC != p[0]) || // Invalid packet; Not i3? (recv_len < TCP_I3_HEADER_SIZE) ) { I3_PRINT_INFO1 (I3_INFO_LEVEL_WARNING, "Invalid i3 tcp header on fd %d\n", fd); return -1; } pkt_size = nhgets(p + 1); if (len < pkt_size) { // Invalid size I3_PRINT_INFO2 (I3_INFO_LEVEL_WARNING, "Invalid i3 tcp packet size %d (on fd %d)\n", pkt_size, fd); return -1; } while (pkt_size > 0 && num_attempts++ < MAX_ATTEMPTS) { recv_len = recv(fd, p, pkt_size, 0); total_recv_len += recv_len; pkt_size -= recv_len; p += recv_len; } } /* Hack! */ if (pkt_size > 0) { I3_PRINT_DEBUG0(I3_DEBUG_LEVEL_MINIMAL, "Still some more bytes to be received, quitting!\n"); return -1; } else { return total_recv_len; } }
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 malformed(uint8_t *pkt, int n, int wantet) { int et; Etherhdr *eh; Pppoehdr *ph; eh = (Etherhdr*)pkt; ph = (Pppoehdr*)(pkt+EtherHdrSz); if(n < Hdr || n < Hdr+nhgets(ph->length)){ werrstr("packet too short %d != %d", n, Hdr+nhgets(ph->length)); return 1; } et = nhgets(eh->type); if(et != wantet){ werrstr("wrong ethernet packet type 0x%x != 0x%x", et, wantet); return 1; } return 0; }
void dumppkt(uint8_t *pkt) { int et; Etherhdr *eh; Pppoehdr *ph; eh = (Etherhdr*)pkt; ph = (Pppoehdr*)(pkt+EtherHdrSz); et = nhgets(eh->type); fprint(2, "%E -> %E type 0x%x\n", eh->src, eh->dst, et); switch(et){ case EtherPppoeDiscovery: case EtherPppoeSession: fprint(2, "\tvers %d type %d code 0x%x sessid 0x%x length %d\n", ph->verstype>>4, ph->verstype&15, ph->code, nhgets(ph->sessid), nhgets(ph->length)); if(et == EtherPppoeDiscovery) dumptags(pkt+Hdr, nhgets(ph->length)); } }
void so_getsockname(int fd, uchar *laddr, ushort *lport) { socklen_t len; struct sockaddr sa; struct sockaddr_in *sin; len = sizeof(sa); if(getsockname(fd, &sa, &len) < 0) oserror(); sin = (struct sockaddr_in*)&sa; if(sin->sin_family != AF_INET || len != sizeof(*sin)) error(Enotv4); ipw6(laddr, sin->sin_addr.s_addr); *lport = nhgets(&sin->sin_port); }
void so_getsockname(int fd, uchar *laddr, ushort *lport) { int len; struct sockaddr_storage sa; struct sockaddr_in6 *sin6; len = sizeof(*sin6); if(getsockname(fd, (struct sockaddr*)&sa, &len) < 0) oserror(); sin6 = (struct sockaddr_in6*)&sa; if(sin6->sin6_family != AF_INET6 || len != sizeof(*sin6)) error("not AF_INET6"); memmove(laddr, &sin6->sin6_addr, IPaddrlen); *lport = nhgets(&sin6->sin6_port); }
void espadvise(Proto *esp, Block *bp, char *msg) { Esphdr *h; Conv *c; ulong spi; h = (Esphdr*)(bp->rp); spi = nhgets(h->espspi); qlock(esp); c = convlookup(esp, spi); if(c != nil) { qhangup(c->rq, msg); qhangup(c->wq, msg); } qunlock(esp); freeblist(bp); }
void so_getsockname(int fd, unsigned long *laddr, unsigned short *lport) { int len; struct sockaddr sa; struct sockaddr_in *sin; sin = (struct sockaddr_in*)&sa; len = sizeof(sa); if(getsockname(fd, &sa, &len) < 0) oserror(); if(sin->sin_family != AF_INET || len != sizeof(*sin)) error("not AF_INET"); *laddr = nhgetl(&sin->sin_addr.s_addr); *lport = nhgets(&sin->sin_port); }
static void tcpreader(void *a) { Session *s = a; uint8_t *buf; int buflen = smbglobals.maxreceive + 4; buf = nbemalloc(buflen); for (;;) { int n; uint8_t flags; uint16_t length; n = readn(s->fd, buf, 4); if (n != 4) { die: free(buf); if (s->state == Connected) (*s->write)(s, nil, -1); deletesession(s); return; } flags = buf[1]; length = nhgets(buf + 2) | ((flags & 1) << 16); if (length > buflen - 4) { print("nbss: too much data (%ud)\n", length); goto die; } n = readn(s->fd, buf + 4, length); if (n != length) goto die; if (s->state == Connected) { if ((*s->write)(s, buf + 4, length) != 0) { s->state = Dead; goto die; } } } }
int wantoffer(uint8_t *pkt) { int i, len; uint8_t *s; Etherhdr *eh; Pppoehdr *ph; eh = (Etherhdr*)pkt; ph = (Pppoehdr*)(pkt+EtherHdrSz); if(ph->code != CodeDiscOffer) return bad("not an offer"); if(nhgets(ph->sessid) != 0x0000) return bad("bad session id"); for(i=0;; i++){ if((s = findtag(pkt, TagSrvName, &len, i)) == nil) return bad("no matching service name"); if(len == strlen(srvname) && memcmp(s, srvname, len) == 0) break; } if((s = findtag(pkt, TagAcName, &len, 0)) == nil) return bad("no ac name"); acname = copy(s, len); if(wantac && strcmp(acname, wantac) != 0){ free(acname); return bad("wrong ac name"); } if(s = findtag(pkt, TagAcCookie, &len, 0)){ cookie = copy(s, len); cookielen = len; } memmove(etherdst, eh->src, sizeof etherdst); return 1; }
int so_accept(int fd, uchar *raddr, ushort *rport) { int nfd, len; struct sockaddr_storage sa; struct sockaddr_in6 *sin6; sin6 = (struct sockaddr_in6*)&sa; len = sizeof(*sin6); osenter(); nfd = accept(fd, (struct sockaddr*)&sa, &len); osleave(); if(nfd < 0) oserror(); if(sin6->sin6_family != AF_INET6 || len != sizeof(*sin6)) error("not AF_INET6"); memmove(raddr, &sin6->sin6_addr, IPaddrlen); *rport = nhgets(&sin6->sin6_port); return nfd; }
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); }
void udpkick(void *x, struct block *bp) { struct conv *c = x; Udp4hdr *uh4; Udp6hdr *uh6; uint16_t rport; uint8_t laddr[IPaddrlen], raddr[IPaddrlen]; Udpcb *ucb; int dlen, ptcllen; Udppriv *upriv; struct Fs *f; int version; struct conv *rc; upriv = c->p->priv; assert(upriv); f = c->p->f; netlog(c->p->f, Logudp, "udp: kick\n"); if (bp == NULL) return; ucb = (Udpcb *) c->ptcl; switch (ucb->headers) { case 7: /* get user specified addresses */ bp = pullupblock(bp, UDP_USEAD7); if (bp == NULL) return; ipmove(raddr, bp->rp); bp->rp += IPaddrlen; ipmove(laddr, bp->rp); bp->rp += IPaddrlen; /* pick interface closest to dest */ if (ipforme(f, laddr) != Runi) findlocalip(f, laddr, raddr); bp->rp += IPaddrlen; /* Ignore ifc address */ rport = nhgets(bp->rp); bp->rp += 2 + 2; /* Ignore local port */ break; case 6: /* get user specified addresses */ bp = pullupblock(bp, UDP_USEAD6); if (bp == NULL) return; ipmove(raddr, bp->rp); bp->rp += IPaddrlen; ipmove(laddr, bp->rp); bp->rp += IPaddrlen; /* pick interface closest to dest */ if (ipforme(f, laddr) != Runi) findlocalip(f, laddr, raddr); rport = nhgets(bp->rp); bp->rp += 2 + 2; /* Ignore local port */ break; default: rport = 0; break; } if (ucb->headers) { if (memcmp(laddr, v4prefix, IPv4off) == 0 || ipcmp(laddr, IPnoaddr) == 0) version = V4; else version = V6; } else { if ((memcmp(c->raddr, v4prefix, IPv4off) == 0 && memcmp(c->laddr, v4prefix, IPv4off) == 0) || ipcmp(c->raddr, IPnoaddr) == 0) version = V4; else version = V6; } dlen = blocklen(bp); /* fill in pseudo header and compute checksum */ switch (version) { case V4: bp = padblock(bp, UDP4_IPHDR_SZ + UDP_UDPHDR_SZ); if (bp == NULL) return; uh4 = (Udp4hdr *) (bp->rp); ptcllen = dlen + UDP_UDPHDR_SZ; uh4->Unused = 0; uh4->udpproto = IP_UDPPROTO; uh4->frag[0] = 0; uh4->frag[1] = 0; hnputs(uh4->udpplen, ptcllen); if (ucb->headers) { v6tov4(uh4->udpdst, raddr); hnputs(uh4->udpdport, rport); v6tov4(uh4->udpsrc, laddr); rc = NULL; } else { v6tov4(uh4->udpdst, c->raddr); hnputs(uh4->udpdport, c->rport); if (ipcmp(c->laddr, IPnoaddr) == 0) findlocalip(f, c->laddr, c->raddr); v6tov4(uh4->udpsrc, c->laddr); rc = c; } hnputs(uh4->udpsport, c->lport); hnputs(uh4->udplen, ptcllen); uh4->udpcksum[0] = 0; uh4->udpcksum[1] = 0; hnputs(uh4->udpcksum, ~ptclcsum(bp, UDP4_PHDR_OFF, UDP4_PHDR_SZ)); bp->checksum_start = UDP4_IPHDR_SZ; bp->checksum_offset = uh4->udpcksum - uh4->udpsport; bp->flag |= Budpck; uh4->vihl = IP_VER4; ipoput4(f, bp, 0, c->ttl, c->tos, rc); break; case V6: bp = padblock(bp, UDP6_IPHDR_SZ + UDP_UDPHDR_SZ); if (bp == NULL) return; // using the v6 ip header to create pseudo header // first then reset it to the normal ip header uh6 = (Udp6hdr *) (bp->rp); memset(uh6, 0, 8); ptcllen = dlen + UDP_UDPHDR_SZ; hnputl(uh6->viclfl, ptcllen); uh6->hoplimit = IP_UDPPROTO; if (ucb->headers) { ipmove(uh6->udpdst, raddr); hnputs(uh6->udpdport, rport); ipmove(uh6->udpsrc, laddr); rc = NULL; } else { ipmove(uh6->udpdst, c->raddr); hnputs(uh6->udpdport, c->rport); if (ipcmp(c->laddr, IPnoaddr) == 0) findlocalip(f, c->laddr, c->raddr); ipmove(uh6->udpsrc, c->laddr); rc = c; } hnputs(uh6->udpsport, c->lport); hnputs(uh6->udplen, ptcllen); uh6->udpcksum[0] = 0; uh6->udpcksum[1] = 0; hnputs(uh6->udpcksum, ptclcsum(bp, UDP6_PHDR_OFF, dlen + UDP_UDPHDR_SZ + UDP6_PHDR_SZ)); memset(uh6, 0, 8); uh6->viclfl[0] = IP_VER6; hnputs(uh6->len, ptcllen); uh6->nextheader = IP_UDPPROTO; ipoput6(f, bp, 0, c->ttl, c->tos, rc); break; default: panic("udpkick: version %d", version); } upriv->ustats.udpOutDatagrams++; }
void bootpdump(uint8_t *p, int n) { int len, i, code; Bootp *bp; Udphdr *up; bp = (Bootp*)p; up = (Udphdr*)bp->udphdr; if(n < bp->optmagic - p) { fprint(2, "dhcpclient: short bootp packet"); return; } fprint(2, "laddr=%I lport=%d raddr=%I rport=%d\n", up->laddr, nhgets(up->lport), up->raddr, nhgets(up->rport)); fprint(2, "op=%d htype=%d hlen=%d hops=%d\n", bp->op, bp->htype, bp->hlen, bp->hops); fprint(2, "xid=%ux secs=%d flags=%ux\n", nhgetl(bp->xid), nhgets(bp->secs), nhgets(bp->flags)); fprint(2, "ciaddr=%V yiaddr=%V siaddr=%V giaddr=%V\n", bp->ciaddr, bp->yiaddr, bp->siaddr, bp->giaddr); fprint(2, "chaddr="); for(i=0; i<16; i++) fprint(2, "%ux ", bp->chaddr[i]); fprint(2, "\n"); fprint(2, "sname=%s\n", bp->sname); fprint(2, "file = %s\n", bp->file); n -= bp->optmagic - p; p = bp->optmagic; if(n < 4) return; if(memcmp(optmagic, p, 4) != 0) fprint(2, "dhcpclient: bad opt magic %ux %ux %ux %ux\n", p[0], p[1], p[2], p[3]); p += 4; n -= 4; while(n>0) { code = *p++; n--; if(code == OBpad) continue; if(code == OBend) break; if(n == 0) { fprint(2, " bad option: %d", code); return; } len = *p++; n--; if(len > n) { fprint(2, " bad option: %d", code); return; } switch(code) { default: fprint(2, "unknown option %d\n", code); for(i = 0; i<len; i++) fprint(2, "%ux ", p[i]); case ODtype: fprint(2, "DHCP type %d\n", p[0]); break; case ODclientid: fprint(2, "client id="); for(i = 0; i<len; i++) fprint(2, "%ux ", p[i]); fprint(2, "\n"); break; case ODlease: fprint(2, "lease=%d\n", nhgetl(p)); break; case ODserverid: fprint(2, "server id=%V\n", p); break; case OBmask: fprint(2, "mask=%V\n", p); break; case OBrouter: fprint(2, "router=%V\n", p); break; } p += len; n -= len; } }
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); } }
int pppoe(char *ether) { char buf[64]; uint8_t pkt[1520]; int dfd, p[2], n, sfd, sz, timeout; Pppoehdr *ph; ph = (Pppoehdr*)(pkt+EtherHdrSz); snprint(buf, sizeof buf, "%s!%d", ether, EtherPppoeDiscovery); if((dfd = dial(buf, nil, nil, nil)) < 0) sysfatal("dial %s: %r", buf); snprint(buf, sizeof buf, "%s!%d", ether, EtherPppoeSession); if((sfd = dial(buf, nil, nil, nil)) < 0) sysfatal("dial %s: %r", buf); for(timeout=250; timeout<16000; timeout*=2){ clearstate(); memset(pkt, 0, sizeof pkt); sz = padi(pkt); if(debug) dumppkt(pkt); if(sz < EtherMintu) sz = EtherMintu; ewrite(dfd, pkt, sz); if(pktread(timeout, dfd, pkt, sizeof pkt, wantoffer) < 0) continue; memset(pkt, 0, sizeof pkt); sz = padr(pkt); if(debug) dumppkt(pkt); if(sz < EtherMintu) sz = EtherMintu; ewrite(dfd, pkt, sz); if(pktread(timeout, dfd, pkt, sizeof pkt, wantsession) < 0) continue; break; } if(sessid < 0) sysfatal("could not establish session"); rfork(RFNOTEG); if(pipe(p) < 0) sysfatal("pipe: %r"); switch(fork()){ case -1: sysfatal("fork: %r"); default: break; case 0: close(p[1]); while((n = read(p[0], pkt+Hdr, sizeof pkt-Hdr)) > 0){ etherhdr(pkt, etherdst, EtherPppoeSession); pppoehdr(pkt+EtherHdrSz, 0x00, sessid); hnputs(pkt+Hdr-2, n); sz = Hdr+n; if(debug > 1){ dumppkt(pkt); hexdump(pkt, sz); } if(sz < EtherMintu) sz = EtherMintu; if(write(sfd, pkt, sz) < 0){ if(debug) fprint(2, "write to ether failed: %r"); _exits(nil); } } _exits(nil); } switch(fork()){ case -1: sysfatal("fork: %r"); default: break; case 0: close(p[1]); while((n = read(sfd, pkt, sizeof pkt)) > 0){ if(malformed(pkt, n, EtherPppoeSession) || ph->code != 0x00 || nhgets(ph->sessid) != sessid){ if(debug) fprint(2, "malformed session pkt: %r\n"); if(debug) dumppkt(pkt); continue; } if(write(p[0], pkt+Hdr, nhgets(ph->length)) < 0){ if(debug) fprint(2, "write to ppp failed: %r\n"); _exits(nil); } } _exits(nil); } close(p[0]); return p[1]; }