| @@ -1,777 +0,0 @@ |
| 1 | | −implement Bootpd; |
| 2 | | − |
| 3 | | −include "sys.m"; |
| 4 | | − sys: Sys; |
| 5 | | − |
| 6 | | −include "draw.m"; |
| 7 | | − |
| 8 | | −include "bufio.m"; |
| 9 | | − bufio: Bufio; |
| 10 | | − Iobuf: import bufio; |
| 11 | | − |
| 12 | | −include "attrdb.m"; |
| 13 | | − attrdb: Attrdb; |
| 14 | | − Db, Dbentry: import attrdb; |
| 15 | | − |
| 16 | | −include "ip.m"; |
| 17 | | − ip: IP; |
| 18 | | − IPaddr, Udphdr: import ip; |
| 19 | | − |
| 20 | | −include "ether.m"; |
| 21 | | − ether: Ether; |
| 22 | | − |
| 23 | | −include "arg.m"; |
| 24 | | − |
| 25 | | −Bootpd: module |
| 26 | | −{ |
| 27 | | − init: fn(nil: ref Draw->Context, argv: list of string); |
| 28 | | −}; |
| 29 | | − |
| 30 | | −stderr: ref Sys->FD; |
| 31 | | −debug: int; |
| 32 | | −sniff: int; |
| 33 | | −verbose: int; |
| 34 | | − |
| 35 | | −siaddr: array of byte; |
| 36 | | −sysname: string; |
| 37 | | −progname := "bootpd"; |
| 38 | | −net := "/net"; |
| 39 | | − |
| 40 | | −Udphdrsize: con IP->OUdphdrlen; |
| 41 | | − |
| 42 | | −NEED_HA: con 1; |
| 43 | | −NEED_IP: con 0; |
| 44 | | −NEED_BF: con 0; |
| 45 | | −NEED_SM: con 0; |
| 46 | | −NEED_GW: con 0; |
| 47 | | −NEED_FS: con 0; |
| 48 | | −NEED_AU: con 0; |
| 49 | | − |
| 50 | | −init(nil: ref Draw->Context, args: list of string) |
| 51 | | −{ |
| 52 | | − sys = load Sys Sys->PATH; |
| 53 | | − stderr = sys->fildes(2); |
| 54 | | − bufio = load Bufio Bufio->PATH; |
| 55 | | − if(bufio == nil) |
| 56 | | − loadfail(Bufio->PATH); |
| 57 | | − attrdb = load Attrdb Attrdb->PATH; |
| 58 | | − if(attrdb == nil) |
| 59 | | − loadfail(Attrdb->PATH); |
| 60 | | − attrdb->init(); |
| 61 | | − ip = load IP IP->PATH; |
| 62 | | − if(ip == nil) |
| 63 | | − loadfail(IP->PATH); |
| 64 | | − ip->init(); |
| 65 | | − ether = load Ether Ether->PATH; |
| 66 | | − if(ether == nil) |
| 67 | | − loadfail(Ether->PATH); |
| 68 | | − ether->init(); |
| 69 | | − |
| 70 | | − fname := "/services/bootp/db"; |
| 71 | | − verbose = 1; |
| 72 | | − sniff = 0; |
| 73 | | − debug = 0; |
| 74 | | − arg := load Arg Arg->PATH; |
| 75 | | − if(arg == nil) |
| 76 | | − raise "fail: load Arg"; |
| 77 | | − arg->init(args); |
| 78 | | − arg->setusage("bootpd [-dsqv] [-f file] [-x network]"); |
| 79 | | − progname = arg->progname(); |
| 80 | | − while((o := arg->opt()) != 0) |
| 81 | | − case o { |
| 82 | | − 'd' => debug++; |
| 83 | | − 's' => sniff = 1; debug = 255; |
| 84 | | − 'q' => verbose = 0; |
| 85 | | − 'v' => verbose = 1; |
| 86 | | − 'x' => net = arg->earg(); |
| 87 | | − 'f' => fname = arg->earg(); |
| 88 | | − * => arg->usage(); |
| 89 | | − } |
| 90 | | − args = arg->argv(); |
| 91 | | − if(args != nil) |
| 92 | | − arg->usage(); |
| 93 | | − arg = nil; |
| 94 | | − |
| 95 | | − sys->pctl(Sys->FORKFD|Sys->FORKNS, nil); |
| 96 | | − if(tabopen(fname)) |
| 97 | | − raise "fail: open database"; |
| 98 | | − |
| 99 | | − if(!sniff && (err := dbread()) != nil) |
| 100 | | − error(sys->sprint("error in %s: %s", fname, err)); |
| 101 | | − |
| 102 | | − addr := net+"/udp!*!67"; |
| 103 | | − if(debug) |
| 104 | | − sys->fprint(stderr, "bootp: announcing %s\n", addr); |
| 105 | | − (ok, c) := sys->announce(addr); |
| 106 | | − if(ok < 0) |
| 107 | | − error(sys->sprint("can't announce %s: %r", addr)); |
| 108 | | − get_sysname(); |
| 109 | | − get_ip(); |
| 110 | | − |
| 111 | | − if(sys->fprint(c.cfd, "headers") < 0) |
| 112 | | − error(sys->sprint("can't set headers mode: %r")); |
| 113 | | − sys->fprint(c.cfd, "oldheaders"); |
| 114 | | − |
| 115 | | − if(debug) |
| 116 | | − sys->fprint(stderr, "bootp: opening %s/data\n", c.dir); |
| 117 | | − c.dfd = sys->open(c.dir+"/data", sys->ORDWR); |
| 118 | | − if(c.dfd == nil) |
| 119 | | − error(sys->sprint("can't open %s/data: %r", c.dir)); |
| 120 | | − |
| 121 | | − spawn server(c); |
| 122 | | −} |
| 123 | | − |
| 124 | | −loadfail(s: string) |
| 125 | | −{ |
| 126 | | − error(sys->sprint("can't load %s: %r", s)); |
| 127 | | −} |
| 128 | | − |
| 129 | | −error(s: string) |
| 130 | | −{ |
| 131 | | − sys->fprint(stderr, "bootp: %s\n", s); |
| 132 | | − raise "fail:error"; |
| 133 | | −} |
| 134 | | − |
| 135 | | −server(c: Sys->Connection) |
| 136 | | −{ |
| 137 | | − buf := array[2048] of byte; |
| 138 | | − badread := 0; |
| 139 | | − for(;;) { |
| 140 | | − if(debug) |
| 141 | | − sys->fprint(stderr, "bootp: listening for bootp requests...\n"); |
| 142 | | − n := sys->read(c.dfd, buf, len buf); |
| 143 | | − if(n <0) { |
| 144 | | − if (badread++ > 10) |
| 145 | | − break; |
| 146 | | − continue; |
| 147 | | − } |
| 148 | | − badread = 0; |
| 149 | | − if(n < Udphdrsize) { |
| 150 | | − if(debug) |
| 151 | | − sys->fprint(stderr, "bootp: short Udphdr: %d bytes\n", n); |
| 152 | | − continue; |
| 153 | | − } |
| 154 | | − hdr := Udphdr.unpack(buf, Udphdrsize); |
| 155 | | − if(debug) |
| 156 | | − sys->fprint(stderr, "bootp: received request from udp!%s!%d\n", hdr.raddr.text(), hdr.rport); |
| 157 | | − if(n < Udphdrsize+300) { |
| 158 | | − if(debug) |
| 159 | | − sys->fprint(stderr, "bootp: short request of %d bytes\n", n - Udphdrsize); |
| 160 | | − continue; |
| 161 | | − } |
| 162 | | − |
| 163 | | − (err, bootp) := M2S(buf[Udphdrsize:]); |
| 164 | | − if(err != nil) { |
| 165 | | − if(debug) |
| 166 | | − sys->fprint(stderr, "bootp: M2S failed: %s\n", err); |
| 167 | | − continue; |
| 168 | | − } |
| 169 | | − if(debug >= 2) |
| 170 | | − ppkt(bootp); |
| 171 | | − if(sniff) |
| 172 | | − continue; |
| 173 | | − if(bootp.htype != byte 1 || bootp.hlen != byte 6) { |
| 174 | | − # if it isn't ether, we don't do it |
| 175 | | − if(debug) |
| 176 | | − sys->fprint(stderr, "bootp: hardware type not ether; ignoring.\n"); |
| 177 | | − continue; |
| 178 | | − } |
| 179 | | − if((err = dbread()) != nil) { |
| 180 | | − sys->fprint(stderr, "bootp: getreply: dbread failed: %s\n", err); |
| 181 | | − continue; |
| 182 | | − } |
| 183 | | − rec := lookup(bootp); |
| 184 | | − if(rec == nil) { |
| 185 | | − # we can't answer this request |
| 186 | | − if(debug) |
| 187 | | − sys->fprint(stderr, "bootp: cannot answer request.\n"); |
| 188 | | − continue; |
| 189 | | − } |
| 190 | | − if(debug){ |
| 191 | | − sys->fprint(stderr, "bootp: found a matching entry:\n"); |
| 192 | | − pinfbp(rec); |
| 193 | | − } |
| 194 | | − mkreply(bootp, rec); |
| 195 | | − if(verbose) sys->print("bootp: %s -> %s %s\n", ether->text(rec.ha), rec.hostname, iptoa(rec.ip)); |
| 196 | | − if(debug >= 2) { |
| 197 | | − sys->fprint(stderr, "bootp: reply message:\n"); |
| 198 | | − ppkt(bootp); |
| 199 | | − } |
| 200 | | − repl:= S2M(bootp); |
| 201 | | − |
| 202 | | − if(debug) |
| 203 | | − sys->fprint(stderr, "bootp: sending reply.\n"); |
| 204 | | − arpenter(iptoa(rec.ip), ether->text(rec.ha)); |
| 205 | | − send(repl); |
| 206 | | − } |
| 207 | | − sys->fprint(stderr, "bootp: %d read errors: %r\n", badread); |
| 208 | | −} |
| 209 | | − |
| 210 | | −arpenter(ip, ha: string) |
| 211 | | −{ |
| 212 | | − if(debug) sys->fprint(stderr, "bootp: arp: %s -> %s\n", ip, ha); |
| 213 | | − fd := sys->open(net+"/arp", Sys->OWRITE); |
| 214 | | − if(fd == nil) { |
| 215 | | − if(debug) |
| 216 | | − sys->fprint(stderr, "bootp: arp open failed: %r\n"); |
| 217 | | − return; |
| 218 | | − } |
| 219 | | − if(sys->fprint(fd, "add %s %s", ip, ha) < 0){ |
| 220 | | − if(debug) |
| 221 | | − sys->fprint(stderr, "bootp: error writing arp: %r\n"); |
| 222 | | − } |
| 223 | | −} |
| 224 | | − |
| 225 | | −get_sysname() |
| 226 | | −{ |
| 227 | | − fd := sys->open("/dev/sysname", sys->OREAD); |
| 228 | | − if(fd == nil) { |
| 229 | | − sysname = "anon"; |
| 230 | | − return; |
| 231 | | − } |
| 232 | | − buf := array[128] of byte; |
| 233 | | − n := sys->read(fd, buf, len buf); |
| 234 | | − if(n <= 0) { |
| 235 | | − sysname = "anon"; |
| 236 | | − return; |
| 237 | | − } |
| 238 | | − sysname = string buf[0:n]; |
| 239 | | −} |
| 240 | | − |
| 241 | | −get_ip() |
| 242 | | −{ |
| 243 | | − siaddr = array[4] of { * => byte 0 }; |
| 244 | | − # get a local IP address by translating our sysname with cs(8) |
| 245 | | − fd := sys->open(net+"/cs", Sys->ORDWR); |
| 246 | | − if(fd == nil){ |
| 247 | | − if(debug) |
| 248 | | − sys->fprint(stderr, "bootp: cannot open %s/cs for reading: %r.\n", net); |
| 249 | | − return; |
| 250 | | − } |
| 251 | | − if(sys->fprint(fd, "net!%s!0", sysname) < 0){ |
| 252 | | − if(debug) |
| 253 | | − sys->fprint(stderr, "bootp: can't translate net!%s!0 via %s/cs: %r\n", sysname, net); |
| 254 | | − return; |
| 255 | | − } |
| 256 | | − sys->seek(fd, big 0, 0); |
| 257 | | − a := array[1024] of byte; |
| 258 | | − n := sys->read(fd, a, len a); |
| 259 | | − if(n < 0) { |
| 260 | | − if(debug) sys->fprint(stderr, "bootp: read from /net/cs: %r.\n"); |
| 261 | | − return; |
| 262 | | − } |
| 263 | | − reply := string a[0:n]; |
| 264 | | − if(debug) sys->fprint(stderr, "bootp: read %s from /net/cs\n", reply); |
| 265 | | − |
| 266 | | − (l, addr):= sys->tokenize(reply, " "); |
| 267 | | − if(l != 2) { |
| 268 | | − if(debug) sys->fprint(stderr, "bootp: bad format from cs\n"); |
| 269 | | − return; |
| 270 | | − } |
| 271 | | − (l, addr) = sys->tokenize(hd tl addr, "!"); |
| 272 | | − if(l < 2) { |
| 273 | | − if(debug) sys->fprint(stderr, "bootp: short addr from cs\n"); |
| 274 | | − return; |
| 275 | | − } |
| 276 | | − err:= ""; |
| 277 | | − (err, siaddr) = get_ipaddr(hd addr); |
| 278 | | − if(err != nil || siaddr == nil) { |
| 279 | | − if(debug) sys->fprint(stderr, "bootp: invalid local IP addr %s.\n", hd tl addr); |
| 280 | | − siaddr = array[4] of { * => byte 0 }; |
| 281 | | − }; |
| 282 | | − if(debug) sys->fprint(stderr, "bootp: local IP address is %s.\n", iptoa(siaddr)); |
| 283 | | −} |
| 284 | | − |
| 285 | | −# byte op; /* opcode */ |
| 286 | | −# byte htype; /* hardware type */ |
| 287 | | −# byte hlen; /* hardware address len */ |
| 288 | | −# byte hops; /* hops */ |
| 289 | | −# byte xid[4]; /* a random number */ |
| 290 | | −# byte secs[2]; /* elapsed snce client started booting */ |
| 291 | | −# byte pad[2]; |
| 292 | | −# byte ciaddr[4]; /* client IP address (client tells server) */ |
| 293 | | −# byte yiaddr[4]; /* client IP address (server tells client) */ |
| 294 | | −# byte siaddr[4]; /* server IP address */ |
| 295 | | −# byte giaddr[4]; /* gateway IP address */ |
| 296 | | −# byte chaddr[16]; /* client hardware address */ |
| 297 | | −# byte sname[64]; /* server host name (optional) */ |
| 298 | | −# byte file[128]; /* boot file name */ |
| 299 | | −# byte vend[128]; /* vendor-specific goo */ |
| 300 | | − |
| 301 | | −BootpPKT: adt |
| 302 | | −{ |
| 303 | | − op: byte; # Start of udp datagram |
| 304 | | − htype: byte; |
| 305 | | − hlen: byte; |
| 306 | | − hops: byte; |
| 307 | | − xid: int; |
| 308 | | − secs: int; |
| 309 | | − ciaddr: array of byte; |
| 310 | | − yiaddr: array of byte; |
| 311 | | − siaddr: array of byte; |
| 312 | | − giaddr: array of byte; |
| 313 | | − chaddr: array of byte; |
| 314 | | − sname: string; |
| 315 | | − file: string; |
| 316 | | − vend: array of byte; |
| 317 | | −}; |
| 318 | | − |
| 319 | | −InfBP: adt { |
| 320 | | − hostname: string; |
| 321 | | − |
| 322 | | − ha: array of byte; # hardware addr |
| 323 | | − ip: array of byte; # client IP addr |
| 324 | | − bf: array of byte; # boot file path |
| 325 | | − sm: array of byte; # subnet mask |
| 326 | | − gw: array of byte; # gateway IP addr |
| 327 | | − fs: array of byte; # file server IP addr |
| 328 | | − au: array of byte; # authentication server IP addr |
| 329 | | −}; |
| 330 | | − |
| 331 | | −records: array of ref InfBP; |
| 332 | | − |
| 333 | | −tabbio: ref Bufio->Iobuf; |
| 334 | | −tabname: string; |
| 335 | | −mtime: int; |
| 336 | | − |
| 337 | | −tabopen(fname: string): int |
| 338 | | −{ |
| 339 | | − if(sniff) return 0; |
| 340 | | − tabname = fname; |
| 341 | | − if((tabbio = bufio->open(tabname, bufio->OREAD)) == nil) { |
| 342 | | − sys->fprint(stderr, "bootp: cannot open %s: %r\n", tabname); |
| 343 | | − return 1; |
| 344 | | − } |
| 345 | | − return 0; |
| 346 | | −} |
| 347 | | − |
| 348 | | −send(msg: array of byte) |
| 349 | | −{ |
| 350 | | − if(debug) sys->fprint(stderr, "bootp: dialing udp!broadcast!68\n"); |
| 351 | | − (n, c) := sys->dial(net+"/udp!255.255.255.255!68", "67"); |
| 352 | | −# (n, c) := sys->dial(net+"/udp!255.255.255.255!68", "192.168.129.1!67"); |
| 353 | | − if(n < 0) { |
| 354 | | − sys->fprint(stderr, "bootp: send: error calling dial: %r\n"); |
| 355 | | − return; |
| 356 | | − } |
| 357 | | − if(debug) sys->fprint(stderr, "bootp: writing to %s/data\n", c.dir); |
| 358 | | − n = sys->write(c.dfd, msg, len msg); |
| 359 | | − if(n <=0) { |
| 360 | | − sys->fprint(stderr, "bootp: send: error writing to %s/data: %r\n", c.dir); |
| 361 | | − return; |
| 362 | | − } |
| 363 | | − if(debug) sys->fprint(stderr, "bootp: successfully wrote %d bytes to %s/data\n", n, c.dir); |
| 364 | | −} |
| 365 | | − |
| 366 | | −mkreply(bootp: ref BootpPKT, rec: ref InfBP) |
| 367 | | −{ |
| 368 | | − bootp.op = byte 2; # boot reply |
| 369 | | − bootp.yiaddr = rec.ip; |
| 370 | | − bootp.siaddr = siaddr; |
| 371 | | − bootp.giaddr = array[4] of { * => byte 0 }; |
| 372 | | − bootp.sname = sysname; |
| 373 | | − bootp.file = string rec.bf; |
| 374 | | − bootp.vend = array of byte sys->sprint("p9 %s %s %s %s", iptoa(rec.sm), iptoa(rec.fs), iptoa(rec.au), iptoa(rec.gw)); |
| 375 | | −} |
| 376 | | − |
| 377 | | −lookup(bootp: ref BootpPKT): ref InfBP |
| 378 | | −{ |
| 379 | | − for(i := 0; i < len records; i++) |
| 380 | | − if(eqa(bootp.chaddr[0:6], records[i].ha) || eqa(bootp.ciaddr, records[i].ip)) |
| 381 | | − return records[i]; |
| 382 | | − return nil; |
| 383 | | −} |
| 384 | | − |
| 385 | | −dbread(): string |
| 386 | | −{ |
| 387 | | − (n, dir) := sys->fstat(tabbio.fd); |
| 388 | | − if(n < 0) |
| 389 | | − return sys->sprint("cannot fstat %s: %r", tabname); |
| 390 | | − if(mtime == 0 || mtime != dir.mtime) { |
| 391 | | − if(bufio->tabbio.seek(big 0, Sys->SEEKSTART) < big 0) |
| 392 | | − return sys->sprint("error seeking to start of %s.", tabname); |
| 393 | | − mtime = dir.mtime; |
| 394 | | − lnum: int = 0; |
| 395 | | − trecs: list of ref InfBP; |
| 396 | | −LINES: while((line := bufio->tabbio.gets('\n')) != nil) { |
| 397 | | − lnum++; |
| 398 | | − if(line[0] == '#') # comment |
| 399 | | − continue LINES; |
| 400 | | − fields: list of string; |
| 401 | | − (n, fields) = sys->tokenize(line, ":\r\n"); |
| 402 | | − if(n <= 0) { # blank line or colons |
| 403 | | − if(len line > 0) { |
| 404 | | − sys->fprint(stderr, "bootp: %s: %d empty entry.\n", tabname, lnum); |
| 405 | | − } |
| 406 | | − continue LINES; |
| 407 | | − } |
| 408 | | − rec := ref InfBP; |
| 409 | | − rec.hostname = hd fields; |
| 410 | | − fields = tl fields; |
| 411 | | − err: string; |
| 412 | | −FIELDS: for(; fields != nil; fields = tl fields) { |
| 413 | | − field := hd fields; |
| 414 | | − if(len field <= len "xx=") { |
| 415 | | − sys->fprint(stderr, "bootp: %s:%d invalid field \"%s\" in entry for %s", |
| 416 | | − tabname, lnum, field, rec.hostname); |
| 417 | | − continue FIELDS; |
| 418 | | − } |
| 419 | | − err = nil; |
| 420 | | − case field[0:3] { |
| 421 | | − "ha=" => |
| 422 | | − if(rec.ha != nil) { |
| 423 | | − sys->fprint(stderr, |
| 424 | | − "bootp: warning: %s:%d hardware address redefined for %s.\n", |
| 425 | | − tabname, lnum, rec.hostname); |
| 426 | | − } |
| 427 | | − (err, rec.ha) = get_haddr(field[3:]); |
| 428 | | − "ip=" => |
| 429 | | − if(rec.ip != nil) { |
| 430 | | − sys->fprint(stderr, "bootp: warning: %s:%d IP address redefined for %s.\n", |
| 431 | | − tabname, lnum, rec.hostname); |
| 432 | | − } |
| 433 | | − (err, rec.ip) = get_ipaddr(field[3:]); |
| 434 | | − "bf=" => |
| 435 | | − if(rec.bf != nil) { |
| 436 | | − sys->fprint(stderr, "bootp: warning: %s:%d bootfile redefined for %s.\n", |
| 437 | | − tabname, lnum, rec.hostname); |
| 438 | | − } |
| 439 | | − (err, rec.bf) = get_path(field[3:]); |
| 440 | | − "sm=" => |
| 441 | | − if(rec.sm != nil) { |
| 442 | | − sys->fprint(stderr, "bootp: warning: %s:%d subnet mask redefined for %s.\n", |
| 443 | | − tabname, lnum, rec.hostname); |
| 444 | | − } |
| 445 | | − (err, rec.sm) = get_ipaddr(field[3:]); |
| 446 | | − "gw=" => |
| 447 | | − if(rec.gw != nil) { |
| 448 | | − sys->fprint(stderr, "bootp: warning: %s:%d gateway redefined for %s.\n", |
| 449 | | − tabname, lnum, rec.hostname); |
| 450 | | − } |
| 451 | | − (err, rec.gw) = get_ipaddr(field[3:]); |
| 452 | | − "fs=" => |
| 453 | | − if(rec.fs != nil) { |
| 454 | | − sys->fprint(stderr, "bootp: warning: %s:%d file server redefined for %s.\n", |
| 455 | | − tabname, lnum, rec.hostname); |
| 456 | | − } |
| 457 | | − (err, rec.fs) = get_ipaddr(field[3:]); |
| 458 | | − "au=" => |
| 459 | | − if(rec.au != nil) { |
| 460 | | − sys->fprint(stderr, |
| 461 | | − "bootp: warning: %s:%d authentication server redefined for %s.\n", |
| 462 | | − tabname, lnum, rec.hostname); |
| 463 | | − } |
| 464 | | − (err, rec.au) = get_ipaddr(field[3:]); |
| 465 | | − * => |
| 466 | | − sys->fprint(stderr, |
| 467 | | − "bootp: %s:%d invalid or unsupported tag \"%s\" in entry for %s.\n", |
| 468 | | − tabname, lnum, field[0:2], rec.hostname); |
| 469 | | − continue FIELDS; |
| 470 | | − } |
| 471 | | − if(err != nil) { |
| 472 | | − sys->fprint(stderr, |
| 473 | | − "bootp: %s:%d %s for %s.\nbootp: skipping entry for %s.\n", |
| 474 | | − tabname, lnum, err, rec.hostname, |
| 475 | | − rec.hostname); |
| 476 | | − continue LINES; |
| 477 | | − } |
| 478 | | − } |
| 479 | | − if(rec.ha == nil) { |
| 480 | | − if(NEED_HA) { |
| 481 | | − sys->fprint(stderr, "bootp: %s:%d no hardware address defined for %s.\n", |
| 482 | | − tabname, lnum, rec.hostname); |
| 483 | | − sys->fprint(stderr, "bootp: skipping entry for %s.\n", rec.hostname); |
| 484 | | − continue LINES; |
| 485 | | − } |
| 486 | | − } |
| 487 | | − if(rec.ip == nil) { |
| 488 | | − if(NEED_IP) { |
| 489 | | − sys->fprint(stderr, "bootp: %s:%d no IP address defined for %s.\n", |
| 490 | | − tabname, lnum, rec.hostname); |
| 491 | | − sys->fprint(stderr, "bootp: skipping entry for %s.\n", rec.hostname); |
| 492 | | − continue LINES; |
| 493 | | − } |
| 494 | | − } |
| 495 | | − if(rec.bf == nil) { |
| 496 | | − if(NEED_BF) { |
| 497 | | − sys->fprint(stderr, "bootp: %s:%d no bootfile defined for %s.\n", |
| 498 | | − tabname, lnum, rec.hostname); |
| 499 | | − sys->fprint(stderr, "bootp: skipping entry for %s.\n", rec.hostname); |
| 500 | | − continue LINES; |
| 501 | | − } |
| 502 | | − } |
| 503 | | − if(rec.sm == nil) { |
| 504 | | − if(NEED_SM) { |
| 505 | | − sys->fprint(stderr, "bootp: %s:%d no subnet mask defined for %s.\n", |
| 506 | | − tabname, lnum, rec.hostname); |
| 507 | | − sys->fprint(stderr, "bootp: skipping entry for %s.\n", rec.hostname); |
| 508 | | − continue LINES; |
| 509 | | − } |
| 510 | | − } |
| 511 | | − if(rec.gw == nil) { |
| 512 | | − if(NEED_GW) { |
| 513 | | − sys->fprint(stderr, "bootp: %s:%d no gateway defined for %s.\n", |
| 514 | | − tabname, lnum, rec.hostname); |
| 515 | | − sys->fprint(stderr, "bootp: skipping entry for %s.\n", rec.hostname); |
| 516 | | − continue LINES; |
| 517 | | − } |
| 518 | | − } |
| 519 | | − if(rec.fs == nil) { |
| 520 | | − if(NEED_FS) { |
| 521 | | − sys->fprint(stderr, "bootp: %s:%d no file server defined for %s.\n", |
| 522 | | − tabname, lnum, rec.hostname); |
| 523 | | − sys->fprint(stderr, "bootp: skipping entry for %s.\n", rec.hostname); |
| 524 | | − continue LINES; |
| 525 | | − } |
| 526 | | − } |
| 527 | | − if(rec.au == nil) { |
| 528 | | − if(NEED_AU) { |
| 529 | | − sys->fprint(stderr, |
| 530 | | − "bootp: %s:%d no authentication server defined for %s.\n", |
| 531 | | − tabname, lnum, rec.hostname); |
| 532 | | − sys->fprint(stderr, "bootp: skipping entry for %s.\n", rec.hostname); |
| 533 | | − continue LINES; |
| 534 | | − } |
| 535 | | − } |
| 536 | | − if(debug) pinfbp(rec); |
| 537 | | − trecs = rec :: trecs; |
| 538 | | − } |
| 539 | | − if(trecs == nil) { |
| 540 | | − sys->fprint(stderr, "bootp: no valid entries in %s.\n", tabname); |
| 541 | | − if(records != nil) { |
| 542 | | − sys->fprint(stderr, "bootp: reverting to previous state.\n"); |
| 543 | | − return nil; |
| 544 | | − } |
| 545 | | − return "no entries."; |
| 546 | | − } |
| 547 | | − records = array[len trecs] of ref InfBP; |
| 548 | | − for(n = len records; n > 0; trecs = tl trecs) |
| 549 | | − records[--n] = hd trecs; |
| 550 | | − } |
| 551 | | − return nil; |
| 552 | | −} |
| 553 | | − |
| 554 | | −get_haddr(str: string): (string, array of byte) |
| 555 | | −{ |
| 556 | | − addr := ether->parse(str); |
| 557 | | − if(addr == nil) |
| 558 | | − return (sys->sprint("invalid hardware address \"%s\"", str), nil); |
| 559 | | − return (nil, addr); |
| 560 | | −} |
| 561 | | − |
| 562 | | −get_ipaddr(str: string): (string, array of byte) |
| 563 | | −{ |
| 564 | | − (ok, a) := IPaddr.parse(str); |
| 565 | | − if(ok < 0) |
| 566 | | − return (sys->sprint("invalid address: %s", str), nil); |
| 567 | | − return (nil, a.v4()); |
| 568 | | −} |
| 569 | | − |
| 570 | | −get_path(str: string): (string, array of byte) |
| 571 | | −{ |
| 572 | | − if(str == nil) { |
| 573 | | − return ("nil path", nil); |
| 574 | | − } |
| 575 | | − path := array of byte str; |
| 576 | | − if(len path > 128) |
| 577 | | − return (sys->sprint("path too long (>128 bytes) \"%s...\"", string path[0:16]), nil); |
| 578 | | − return (nil, path); |
| 579 | | −} |
| 580 | | − |
| 581 | | −iptoa(addr: array of byte): string |
| 582 | | −{ |
| 583 | | − if(len addr != 4) |
| 584 | | − return "0.0.0.0"; |
| 585 | | − return sys->sprint("%d.%d.%d.%d", |
| 586 | | − int addr[0], |
| 587 | | − int addr[1], |
| 588 | | − int addr[2], |
| 589 | | − int addr[3]); |
| 590 | | −} |
| 591 | | − |
| 592 | | −dtoa(data: array of byte): string |
| 593 | | −{ |
| 594 | | − if(data == nil) |
| 595 | | − return nil; |
| 596 | | − result: string; |
| 597 | | − for(i:=0; i < len data; i++) |
| 598 | | − result += sys->sprint(".%d", int data[i]); |
| 599 | | − return result[1:]; |
| 600 | | −} |
| 601 | | − |
| 602 | | −bptohw(bp: ref BootpPKT): string |
| 603 | | −{ |
| 604 | | − l := int bp.hlen; |
| 605 | | − if(l > 0 && l < len bp.chaddr) |
| 606 | | − return ether->text(bp.chaddr[0:l]); |
| 607 | | − return ""; |
| 608 | | −} |
| 609 | | − |
| 610 | | −ctostr(cstr: array of byte): string |
| 611 | | −{ |
| 612 | | − for(i:=0; i<len cstr; i++) |
| 613 | | − if(cstr[i] == byte 0) |
| 614 | | − break; |
| 615 | | − return string cstr[0:i]; |
| 616 | | −} |
| 617 | | − |
| 618 | | −strtoc(s: string): array of byte |
| 619 | | −{ |
| 620 | | − as := array of byte s; |
| 621 | | − cs := array[1 + len as] of byte; |
| 622 | | − cs[0:] = as; |
| 623 | | − cs[len cs - 1] = byte 0; |
| 624 | | − return cs; |
| 625 | | −} |
| 626 | | − |
| 627 | | −ppkt(bootp: ref BootpPKT) |
| 628 | | −{ |
| 629 | | − sys->fprint(stderr, "BootpPKT {\n"); |
| 630 | | − sys->fprint(stderr, "\top == %d\n", int bootp.op); |
| 631 | | − sys->fprint(stderr, "\thtype == %d\n", int bootp.htype); |
| 632 | | − sys->fprint(stderr, "\thlen == %d\n", int bootp.hlen); |
| 633 | | − sys->fprint(stderr, "\thops == %d\n", int bootp.hops); |
| 634 | | − sys->fprint(stderr, "\txid == %d\n", bootp.xid); |
| 635 | | − sys->fprint(stderr, "\tsecs == %d\n", bootp.secs); |
| 636 | | − sys->fprint(stderr, "\tC client == %s\n", dtoa(bootp.ciaddr)); |
| 637 | | − sys->fprint(stderr, "\tY client == %s\n", dtoa(bootp.yiaddr)); |
| 638 | | − sys->fprint(stderr, "\tserver == %s\n", dtoa(bootp.siaddr)); |
| 639 | | − sys->fprint(stderr, "\tgateway == %s\n", dtoa(bootp.giaddr)); |
| 640 | | − sys->fprint(stderr, "\thwaddr == %s\n", bptohw(bootp)); |
| 641 | | − sys->fprint(stderr, "\thost == %s\n", bootp.sname); |
| 642 | | − sys->fprint(stderr, "\tfile == %s\n", bootp.file); |
| 643 | | − sys->fprint(stderr, "\tmagic == %s\n", magic(bootp.vend[0:4])); |
| 644 | | − if(magic(bootp.vend[0:4]) == "plan9") { |
| 645 | | − (n, strs) := sys->tokenize(string bootp.vend[4:], " \r\n"); |
| 646 | | − if(strs != nil) { |
| 647 | | − sys->fprint(stderr, "\t\tsm == %s\n", hd strs); |
| 648 | | − strs = tl strs; |
| 649 | | − } |
| 650 | | − if(strs != nil) { |
| 651 | | − sys->fprint(stderr, "\t\tfs == %s\n", hd strs); |
| 652 | | − strs = tl strs; |
| 653 | | − } |
| 654 | | − if(strs != nil) { |
| 655 | | − sys->fprint(stderr, "\t\tau == %s\n", hd strs); |
| 656 | | − strs = tl strs; |
| 657 | | − } |
| 658 | | − if(strs != nil) { |
| 659 | | − sys->fprint(stderr, "\t\tgw == %s\n", hd strs); |
| 660 | | − strs = tl strs; |
| 661 | | − } |
| 662 | | − } |
| 663 | | − sys->fprint(stderr, "}\n\n"); |
| 664 | | −} |
| 665 | | − |
| 666 | | −eqa(a1: array of byte, a2: array of byte): int |
| 667 | | −{ |
| 668 | | − if(len a1 != len a2) |
| 669 | | − return 0; |
| 670 | | − for(i := 0; i < len a1; i++) |
| 671 | | − if(a1[i] != a2[i]) |
| 672 | | − return 0; |
| 673 | | − return 1; |
| 674 | | −} |
| 675 | | − |
| 676 | | −magic(cookie: array of byte): string |
| 677 | | −{ |
| 678 | | − if(eqa(cookie, array[] of { byte 'p', byte '9', byte ' ', byte ' ' })) |
| 679 | | − return "plan9"; |
| 680 | | − if(eqa(cookie, array[] of { byte 99, byte 130, byte 83, byte 99 })) |
| 681 | | − return "rfc1048"; |
| 682 | | − if(eqa(cookie, array[] of { byte 'C', byte 'M', byte 'U', byte 0 })) |
| 683 | | − return "cmu"; |
| 684 | | − return dtoa(cookie); |
| 685 | | −} |
| 686 | | − |
| 687 | | −pinfbp(rec: ref InfBP) |
| 688 | | −{ |
| 689 | | − sys->fprint(stderr, "Bootp entry {\n"); |
| 690 | | − sys->fprint(stderr, "\tha == %s\n", ether->text(rec.ha)); |
| 691 | | − sys->fprint(stderr, "\tip == %s\n", dtoa(rec.ip)); |
| 692 | | − sys->fprint(stderr, "\tbf == %s\n", string rec.bf); |
| 693 | | − sys->fprint(stderr, "\tsm == %s\n", dtoa(rec.sm)); |
| 694 | | − sys->fprint(stderr, "\tgw == %s\n", dtoa(rec.gw)); |
| 695 | | − sys->fprint(stderr, "\tfs == %s\n", dtoa(rec.fs)); |
| 696 | | − sys->fprint(stderr, "\tau == %s\n", dtoa(rec.au)); |
| 697 | | − sys->fprint(stderr, "}\n"); |
| 698 | | −} |
| 699 | | − |
| 700 | | −M2S(data: array of byte): (string, ref BootpPKT) |
| 701 | | −{ |
| 702 | | − if(len data < 300) |
| 703 | | − return ("too short", nil); |
| 704 | | − |
| 705 | | − bootp := ref BootpPKT; |
| 706 | | − |
| 707 | | − bootp.op = data[0]; |
| 708 | | − bootp.htype = data[1]; |
| 709 | | − bootp.hlen = data[2]; |
| 710 | | − bootp.hops = data[3]; |
| 711 | | − bootp.xid = nhgetl(data[4:8]); |
| 712 | | − bootp.secs = nhgets(data[8:10]); |
| 713 | | − # data[10:12] unused |
| 714 | | − bootp.ciaddr = data[12:16]; |
| 715 | | − bootp.yiaddr = data[16:20]; |
| 716 | | − bootp.siaddr = data[20:24]; |
| 717 | | − bootp.giaddr = data[24:28]; |
| 718 | | − bootp.chaddr = data[28:44]; |
| 719 | | − bootp.sname = ctostr(data[44:108]); |
| 720 | | − bootp.file = ctostr(data[108:236]); |
| 721 | | − bootp.vend = data[236:300]; |
| 722 | | − |
| 723 | | − return (nil, bootp); |
| 724 | | −} |
| 725 | | − |
| 726 | | −S2M(bootp: ref BootpPKT): array of byte |
| 727 | | −{ |
| 728 | | − data := array[364] of { * => byte 0 }; |
| 729 | | − |
| 730 | | − data[0] = bootp.op; |
| 731 | | − data[1] = bootp.htype; |
| 732 | | − data[2] = bootp.hlen; |
| 733 | | − data[3] = bootp.hops; |
| 734 | | − data[4:] = nhputl(bootp.xid); |
| 735 | | − data[8:] = nhputs(bootp.secs); |
| 736 | | − # data[10:12] unused |
| 737 | | − data[12:] = bootp.ciaddr; |
| 738 | | − data[16:] = bootp.yiaddr; |
| 739 | | − data[20:] = bootp.siaddr; |
| 740 | | − data[24:] = bootp.giaddr; |
| 741 | | − data[28:] = bootp.chaddr; |
| 742 | | − data[44:] = array of byte bootp.sname; |
| 743 | | − data[108:] = array of byte bootp.file; |
| 744 | | − data[236:] = bootp.vend; |
| 745 | | − |
| 746 | | − return data; |
| 747 | | −} |
| 748 | | − |
| 749 | | −nhgetl(data: array of byte): int |
| 750 | | −{ |
| 751 | | − return (int data[0]<<24) | (int data[1]<<16) | |
| 752 | | − (int data[2]<<8) | int data[3]; |
| 753 | | −} |
| 754 | | − |
| 755 | | −nhgets(data: array of byte): int |
| 756 | | −{ |
| 757 | | − return (int data[0]<<8) | int data[1]; |
| 758 | | −} |
| 759 | | − |
| 760 | | −nhputl(value: int): array of byte |
| 761 | | −{ |
| 762 | | − return array[] of { |
| 763 | | − byte (value >> 24), |
| 764 | | − byte (value >> 16), |
| 765 | | − byte (value >> 8), |
| 766 | | − byte (value >> 0), |
| 767 | | − }; |
| 768 | | −} |
| 769 | | − |
| 770 | | −nhputs(value: int): array of byte |
| 771 | | −{ |
| 772 | | − return array[] of { |
| 773 | | − byte (value >> 8), |
| 774 | | − byte (value >> 0), |
| 775 | | − }; |
| 776 | | −} |
| 777 | | − |