#include #include #include #include #include #include "nbcache.h" enum { Tnop, Tip, TNip, Tname, Tint8, Tint16, Tint32, Tlower, Omask = 1, /* netmask */ Osysname = 12, /* system name */ Odnsdom = 15, /* fully qualified domain name */ Olease = 51, /* lease time */ Oip = 50, /* ip address */ }; typedef struct { int id; char *name; int type; int len; union { int num; char *str; uchar *ip; }; } Opt; static Opt Opts[] = { { 0, "nop", Tnop }, /* no length, NOP / padding */ { 1, "mask", Tip }, /* no length, Net mask */ { 2, "time-diff", Tint32 }, /* no length, GMT time, 32 bits */ { 3, "gateway", TNip }, /* N/4 Router addresses */ { 6, "dns", TNip }, /* N/4 DNS Server addresses */ { 9, "print", TNip }, /* N/4 Printer Server addresses */ { 12, "sys", Tlower }, /* Hostname string */ { 15, "dnsdom", Tlower }, /* The DNS domain name of the client */ { 42, "ntp", TNip }, /* NTP Server Addresses */ // { 43, nil, Traw }, /* Vendor specific information */ { 44, "nbns", Tlower }, /* NETBIOS Name Servers */ { 45, "nbdd", Tlower }, /* NETBIOS datagram service */ { 46, "nbtype", Tlower }, /* NETBIOS node type */ { 47, "nbscope", Tlower }, /* NETBIOS Name scope */ { 50, "ip", TNip }, /* requested IP address */ { 51, "ttl", Tint32 }, /* IP address lease time */ { 53, nil, Tint8 }, /* DHCP subtype */ // // { 55, nil, Traw }, /* parameter request list */ // { 60, nil, Traw }, /* vendor class identifier */ // { 61, nil, Traw }, /* Client identifier */ // { 66, "tftp", Tlower }, /* TFTP Server Name */ { 67, "bootf", Tname }, /* Boot File Name */ { 69, "smtp", TNip }, /* Simple Mail Server Addresses */ { 70, "pop3", TNip }, /* Post Office Server Addresses */ { 71, "nntp", TNip }, /* Network News Server Addresses */ { 81, "dom", Tlower }, /* Fully Qualified Domain Name */ }; static Opt * lookopt(int n) { Opt *o; for(o = Opts; o < &Opts[nelem(Opts)]; o++) if(n == o->id) return o; return nil; } static char * stropt(int n) { Opt *o; for(o = Opts; o < &Opts[nelem(Opts)]; o++) if(n == o->id && o->len != 0) return o->str; return nil; } static int numopt(int n) { Opt *o; for(o = Opts; o < &Opts[nelem(Opts)]; o++) if(n == o->id && o->len != 0) return o->num; return -1; } static uchar * ipopt(int n) { Opt *o; for(o = Opts; o < &Opts[nelem(Opts)]; o++) if(n == o->id && o->len != 0) return o->ip; return nil; } static uchar * ipnopt(int n, int *num) { Opt *o; for(o = Opts; o < &Opts[nelem(Opts)]; o++) if(n == o->id && o->len != 0){ *num = o->len; return o->ip; } return nil; } static void freeopts(void) { Opt *o; for(o = Opts; o < &Opts[nelem(Opts)]; o++) switch(o->type){ case Tnop: case Tint8: case Tint16: case Tint32: o->len = 0; break; case Tip: case TNip: free(o->ip); o->ip = nil; o->len = 0; break; case Tname: case Tlower: free(o->str); o->str = nil; o->len = 0; break; default: sysfatal("dhcp: type=%d unknown\n", o->type); break; } } static void network(void) { Node *n; Attr *a; char *serv, ipstr[20]; int lease, i, ndns, ttl; uchar net[IPv4addrlen], *mask, *gate, *dhcp, *dns; mask = ipopt(1); gate = ipopt(3); dhcp = ipopt(54); ttl = numopt(54); dns = ipnopt(6, &ndns); if(gate == nil || mask == nil) return; for(i = 0; i < IPv4addrlen; i++) net[i] = gate[i] & mask[i]; n = getnode(Thost, ttl, "net-%V", net); if((lease = numopt(54)) != -1) setval(n, "leases", "%d", lease); setval(n, "ipgw", "%V", gate); setval(n, "ipmask", "%V", mask); SET(a); if(ndns > 0) a = setval(n, "dns", "%V", dns); for(i = 1; i < ndns; i++) addval(a, "dns", "%V", dns + i*IPv4addrlen); if(dhcp){ snprint(ipstr, sizeof(ipstr), "%V", dhcp); serv = csgetvalue(Netdir, "ip", ipstr, "sys", nil); if(serv == nil) serv = csgetvalue(Netdir, "ip", ipstr, "dom", nil); if(serv == nil) setval(n, "dhcp", "%s", ipstr); else setval(n, "dhcp", "%d", serv); } if(Debug) setval(n, "src", "dhcp-net"); } static void host(uchar mac[Etheraddrlen], uchar ip[IPv4addrlen]) { Node *n; Attr *a; char *name, *vendor; if((name = stropt(12)) == nil) return; n = getnode(Thost, -1, "%s", name); a = setval(n, "ip", "%V", ip); addval(a, "ether", "%E", mac); if(Debug) addval(a, "src", "dhcp-host"); if((vendor = nicvendor(mac)) != nil){ addval(a, "vendor", "%s", vendor); free(vendor); } } void dhcp(Pkt *p) { Opt *o; int subtype, x, id; char bp_servname[64], bp_bootfile[128]; uchar bp_myip[IPv4addrlen], bp_mac[Etheraddrlen]; uchar bp_yourip[IPv4addrlen], bp_srvip[IPv4addrlen], bp_gateip[IPv4addrlen]; static uchar zeros[IPv4addrlen]; r8(p); /* DHCP message type */ if(r8(p) != 1) /* Phys medium (Ethernet) */ return; if(r8(p) != Etheraddrlen) /* MAC address length (Ethernet) */ return; skip(p, 1); /* hops */ skip(p, 4); /* transaction ID */ skip(p, 2); /* uptime of client */ skip(p, 2); /* flags */ rmem(p, bp_myip, IPv4addrlen); /* client's view of its IP addr */ rmem(p, bp_yourip, IPv4addrlen); /* server's view of client's IP addr */ rmem(p, bp_srvip, IPv4addrlen); /* server's IP address */ rmem(p, bp_gateip, IPv4addrlen); /* gateway's IP addr */ rmem(p, bp_mac, Etheraddrlen); /* client's MAC address */ skip(p, 16-Etheraddrlen); rmem(p, bp_servname, 64); /* server's hostname */ rmem(p, bp_bootfile, 128); /* server's hostname */ if(rb32(p) != 0x63825363) /* DHCP magic */ return; if(p->end - p->pos < 1) /* No more data (??!) */ return; while((id = r8(p)) != 255){ if((o = lookopt(id)) == nil){ x = r8(p); skip(p, x); /* fprint(2, "dhcp: ignored id=%d len=%d\n", id, x); */ continue; } switch(o->type){ case Tnop: continue; case Tip: o->len = IPv4addrlen; if((o->ip = malloc(IPv4addrlen)) == nil) sysfatal("No memory %r\n"); rmem(p, o->ip, IPv4addrlen); break; case TNip: x = r8(p); o->len = x; if((o->ip = malloc(x)) == nil) sysfatal("No memory %r\n"); rmem(p, o->ip, x); break; case Tname: x = r8(p); o->len = x; if((o->str = malloc(x+1)) == nil) sysfatal("No memory %r\n"); o->str[x] = 0; rmem(p, o->str, x); break; case Tlower: x = r8(p); o->len = x; if((o->str = malloc(x+1)) == nil) sysfatal("No memory %r\n"); rmem(p, o->str, x); o->str[x] = 0; strlwr(o->str); break; case Tint8: o->len = r8(p); o->num = r8(p); break; case Tint16: o->len = r8(p); o->num = rb16(p); break; case Tint32: o->len = r8(p); o->num = rb32(p); break; default: sysfatal("dhcp: type=%d unknown\n", o->type); break; } } subtype = numopt(53); switch(subtype){ case 5: /* ack */ network(); break; case 8: /* inform */ host(bp_mac, bp_myip); break; case 2: /* offer (more info in following ack) */ case 3: /* request (more info in following ack) */ case 1: /* discover (more info in following ack) */ case 4: /* decline (never seen one) */ case 6: /* nak (never seen one) */ default: break; } freeopts(); }