#include #include #include #include "a1.h" int a1readlen(uchar *a, int *llen) { int len, i; if((a[0] & 0x80) == 0) { *llen = 1; return a[0]; } *llen = (*a++ & 0x7f) + 1; for(i=0, len=0; i<*llen-1; i++) len = (len << 8) | *a++; return len; } int a1readint(uchar *a, int len) { int tot, neg, tlen; tlen = len; if(len > sizeof(int)) return 0; tot = *a & 0x7f; neg = *a & 0x80; for(tlen--, a++; tlen > 0; tlen--, a++) tot = (tot << 8) | *a; if(neg) tot -= (1<<((len*8)-1)); return tot; } char *snmpatype[] = { "get", "getn", "resp", "set", "trap" }; void Sfree(Snmp *s) { free(s->pdu); free(s); } Snmp* Salloc(void) { Snmp *s; if((s = malloc(sizeof(*s))) == 0) return 0; memset(s, 0, sizeof(*s)); return s; } int objidfmt(char *s, int ns, uchar *a, int na) { int i, n, dot; dot = 0; n = snprint(s, ns, "%d.%d", a[0]/40, a[0]%40); for(i=1; ivers, s->private ? "private" : "public", 0xa0 <= s->type && s->type <= 0xa4 ? snmpatype[s->type-0xa0] : "", s->reqid, s->estat, s->eindex); for(i=0; inpdu; i++){ print("\t%s ", s->pdu[i].objid); switch(s->pdu[i].type) { case Anull: break; case Aint: print("int %d", s->pdu[i].i); break; case Acounter: print("counter %d", s->pdu[i].i); break; case Agauge: print("gauge %d", s->pdu[i].i); break; case Atimeticks: print("timeticks %d", s->pdu[i].i); break; case Aoctstr: print("octstr %.*s", utfnlen(s->pdu[i].s, s->pdu[i].len), s->pdu[i].s); break; case Aobjid: objidfmt(buf, sizeof buf, (uchar*)s->pdu[i].s, s->pdu[i].len); print("objid %s", buf); break; case Aipaddr: print("ipaddr %V", (uchar*)s->pdu[i].s); break; default: print("unknown type %d", s->pdu[i].type); break; } print("\n"); } } int Sparse(void *va, int na, Snmp *dst) { SnmpPdu *pdu; uchar *a = va; uchar *ea = a+na; int j, tlen, llen, npdu; chat("Sparse %d...", ea-a); if(dst == 0){ werrstr("bad args to Sparse"); return -1; } chat("."); if(*a++ != Aseq || (tlen = a1readlen(a, &llen)) < 0) goto die; chat("tlen=%d...", tlen); a += llen; if(a+tlen < ea) ea = a+tlen; if(a > ea) goto die; if(*a++ != Aint) goto die; if((j=a1readlen(a, &llen)) < 0) goto die; chat("llen =%d\n", llen); a++; dst->vers = a1readint(a, j); a += j; chat("vers=%d...", dst->vers); if(a > ea) goto die; chat("nxt=%d", *a); if(*a++ != Aoctstr || (j=a1readlen(a, &llen)) < 0) goto die; a += llen; if(a > ea) goto diespace; if(strncmp((char*)a, "private", j) == 0) dst->private = 1; else dst->private = 0; chat("(%d)%s...", j, dst->private?"private":"public"); a += j; chat("%x", *a); if(*a < 0xa0 || *a > 0xa4){ werrstr("bad pkt type"); goto die; } dst->type = *a; a++; chat("type=%s", snmpatype[dst->type-0xa0]); if((j = a1readlen(a, &llen)) < 0) goto die; a += llen; if(ea < a+j) goto die; if(*a++ != Aint || (j=a1readlen(a, &llen)) < 0) goto die; a += llen; dst->reqid = a1readint(a, j); a += j; if(a > ea) goto die; if(*a++ != Aint || *a++ != 1) goto die; dst->estat = *a++; if(*a++ != Aint || *a++ != 1) goto die; dst->eindex = *a++; if(a > ea) goto die; if(*a++ != Aseq || (j = a1readlen(a, &llen)) < 0) goto die; a += llen; if(ea < a+j) goto die; npdu = 0; while(a < ea && npdu < Mpdu) { chat("pdu..."); ++npdu; chat("npdu=%d", npdu); pdu = &dst->pdu[npdu-1]; if(*a++ != Aseq || (a1readlen(a, &llen)) < 0) goto die; a += llen; if(a > ea) goto die; if(*a++ != Aobjid || (j=a1readlen(a, &llen)) < 0) goto die; a += llen; if(a > ea) goto die; objidfmt(pdu->objid, Objidlen, a, j); chat("objid %s...", pdu->objid); a += j; pdu->type = *a; chat("type %d...", pdu->type); a++; if(a > ea) goto die; if((j = a1readlen(a, &llen)) < 0) goto die; a += llen; if(a > ea) goto die; pdu->len = j; chat("len %d...", j); switch(pdu->type) { case Aint: case Acounter: case Agauge: case Atimeticks: pdu->i = a1readint(a, j); break; case Aoctstr: case Aobjid: case Aipaddr: default: pdu->s = (char*)a; break; } a += j; if(a > ea) goto die; } dst->npdu = npdu; return 0; diespace: werrstr("out of space"); die: chat("die...a=%d ea=%d", a-(uchar*)va, ea-(uchar*)va); return -1; } static int wobjid(uchar *oa, char *s) { uchar *a = oa; int i, j, dot; int dots[32]; char *f[32]; int nf; s = strdup(s); nf = getfields(s, f, 32, 0, "."); if(nf < 0) { free(s); return 0; } for(i=0; i=2; j--) { dot = dots[j]; *--a = dot & 0x7f; dot >>= 7; while(dot) { *--a = 0x80|(dot&0x7f); dot >>= 7; } } *--a = dots[0] * 40 + dots[1]; free(s); return (oa-a); } static int wlen(uchar *oa, int len) { uchar *a = oa; if(len < 128) { *--a = len; return 1; } while(len) { *--a = len; len >>= 8; } --a; *a = (oa-a-1)|0x80; return (oa-a); } static int wint(uchar *oa, int i) { int neg, n; uchar *a = oa; n = i; neg = 0; if(n < 0) { neg = 1; n = -n; } *--a = n; n >>= 8; while(n) { *--a = n; n >>= 8; } if(*a & 0x80) *--a = 0; if(neg) *a |= 0x80; return (oa-a); } int Sunparse(Snmp *s, void *va, int na) { uchar *atop = va; uchar *a = va; uchar *oa; uchar *ea = a+na; SnmpPdu *pdu; int i,l; /* we build the packet backwards at the end of * the buffer and then memmove it to the * beginning */ a = ea; pdu = &s->pdu[s->npdu]; for(i=s->npdu-1; i>=0; i--) { oa = a; pdu--; switch(pdu->type) { case Aint: case Acounter: case Agauge: case Atimeticks: a -= wint(a, pdu->i); break; case Aobjid: a -= wobjid(a, pdu->s); break; case Anull: default: /* do nothing */ break; case Aipaddr: pdu->len = 4; /* fall through */ case Aoctstr: a -= pdu->len; memcpy(a, pdu->s, pdu->len); break; } pdu->len = oa-a; /* now write len of pdu data*/ a -= wlen(a, pdu->len); *--a = pdu->type; /* now write objid */ a -= (l=wobjid(a, pdu->objid)); a -= wlen(a, l); *--a = Aobjid; /* now write len of pdu */ a -= wlen(a, oa-a); *--a = Aseq; } /* now write length of all pdus */ a -= wlen(a, ea-a); *--a = Aseq; /* eindex */ *--a = 0; *--a = 1; *--a = Aint; /* estat */ *--a = 0; *--a = 1; *--a = Aint; /* request id */ a -= (l=wint(a, s->reqid)); a -= wlen(a, l); *--a = Aint; /* let's just toss the length of the packet so far * in here, just to make sure we haven't forgotten. * bit decay, you know. */ a -= wlen(a, (ea-a)); /* DO NOT *--a = Aseq; [sic] */ *--a = s->type; if(s->private) { a -= 7; memcpy(a, "private", 7); a -= wlen(a, 7); } else { a -= 6; memcpy(a, "public", 6); a -= wlen(a, 6); } *--a = Aoctstr; a -= (l=wint(a, s->vers)); a -= wlen(a, l); *--a = Aint; /* bit decay check */ a -= wlen(a, ea-a); *--a = Aseq; /* done! */ memmove(atop, a, ea-a); return ea-a; } int readflag, alarmflag; int alarmtr(void*, char *why) { if(!readflag) return 0; if(strcmp(why, "alarm")==0) { alarmflag++; return 1; } return 0; } int dosnmp(int nfd, Snmp *s, Snmp *srep) { int nn, n, reqid; static char buf[4096]; static int reg; if(!reg) { atnotify(alarmtr, 1); reg = 1; } if(s == 0 || srep == 0){ werrstr("bad args to dosnmp"); return -1; } if(s->reqid == 0) s->reqid = (nsec()&0x7FFE)+1; reqid = s->reqid; n = Sunparse(s, buf, sizeof(buf)); if(n <= 0){ werrstr("Sunparse: %r"); return -1; } nn = write(nfd, buf, n); if(nn != n) { werrstr("write failed: %r"); return -1; } memset(srep, 0, sizeof(*srep)); alarmflag = 0; readflag = 1; alarm(5000); do { n = read(nfd, buf, sizeof buf); if(n > 0){ chat("sparse %d?", n); memset(srep, 0, sizeof(*srep)); if(Sparse(buf, n, srep) < 0){ print("parse error: %r\n"); continue; } if(srep->reqid != reqid) print("mismatch id %d %d\n", srep->reqid, reqid); } } while(!alarmflag && n > 0 && srep->reqid != reqid); alarm(0); if(alarmflag){ werrstr("alarmed"); return -1; } readflag = 0; if(srep->reqid == reqid) { return 0; } if(n < 0) werrstr("read failed: %r"); else if(n == 0) werrstr("read got eof"); else werrstr("got reqid %d wanted %d", srep->reqid, reqid); return -1; }