1implement IP; 2 3# 4# Copyright © 2003,2004 Vita Nuova Holdings Limited. All rights reserved. 5# 6 7include "sys.m"; 8 sys: Sys; 9 10include "ip.m"; 11 12init() 13{ 14 sys = load Sys Sys->PATH; 15 v4prefix = array[] of { 16 byte 0, byte 0, byte 0, byte 0, 17 byte 0, byte 0, byte 0, byte 0, 18 byte 0, byte 0, byte 16rFF, byte 16rFF, 19 }; 20 21 v4bcast = IPaddr(array[] of { 22 byte 0, byte 0, byte 0, byte 0, 23 byte 0, byte 0, byte 0, byte 0, 24 byte 0, byte 0, byte 16rFF, byte 16rFF, 25 byte 16rFF, byte 16rFF, byte 16rFF, byte 16rFF, 26 }); 27 28 v4allsys = IPaddr(array[] of { 29 byte 0, byte 0, byte 0, byte 0, 30 byte 0, byte 0, byte 0, byte 0, 31 byte 0, byte 0, byte 16rFF, byte 16rFF, 32 byte 16rE0, byte 0, byte 0, byte 16r01, 33 }); 34 35 v4allrouter = IPaddr(array[] of { 36 byte 0, byte 0, byte 0, byte 0, 37 byte 0, byte 0, byte 0, byte 0, 38 byte 0, byte 0, byte 16rFF, byte 16rFF, 39 byte 16rE0, byte 0, byte 0, byte 16r02, 40 }); 41 42 v4noaddr = IPaddr(array[] of { 43 byte 0, byte 0, byte 0, byte 0, 44 byte 0, byte 0, byte 0, byte 0, 45 byte 0, byte 0, byte 16rFF, byte 16rFF, 46 byte 0, byte 0, byte 0, byte 0, 47 }); 48 49 selfv6 = IPaddr(array[] of { 50 byte 0, byte 0, byte 0, byte 0, 51 byte 0, byte 0, byte 0, byte 0, 52 byte 0, byte 0, byte 0, byte 0, 53 byte 0, byte 0, byte 0, byte 1, 54 }); 55 56 selfv4 = IPaddr(array[] of { 57 byte 0, byte 0, byte 0, byte 0, 58 byte 0, byte 0, byte 0, byte 0, 59 byte 0, byte 0, byte 16rFF, byte 16rFF, 60 byte 127, byte 0, byte 0, byte 1, 61 }); 62 63 noaddr = IPaddr(array[] of {0 to IPaddrlen-1 => byte 0}); 64 allbits = IPaddr(array[] of {0 to IPaddrlen-1 => byte 16rFF}); 65} 66 67IPaddr.newv6(a: array of byte): IPaddr 68{ 69 b := array[IPaddrlen] of byte; 70 b[0:] = a[0:IPaddrlen]; 71 return IPaddr(b); 72} 73 74IPaddr.newv4(a: array of byte): IPaddr 75{ 76 b := array[IPaddrlen] of byte; 77 b[0:] = v4prefix; 78 b[IPv4off:] = a[0:IPv4addrlen]; 79 return IPaddr(b); 80} 81 82IPaddr.copy(ip: self IPaddr): IPaddr 83{ 84 if(ip.a == nil) 85 return noaddr.copy(); 86 a := array[IPaddrlen] of byte; 87 a[0:] = ip.a; 88 return IPaddr(a); 89} 90 91IPaddr.eq(ip: self IPaddr, v: IPaddr): int 92{ 93 a := ip.a; 94 if(a == nil) 95 a = noaddr.a; 96 b := v.a; 97 if(b == nil) 98 b = noaddr.a; 99 for(i := 0; i < IPaddrlen; i++) 100 if(a[i] != b[i]) 101 return 0; 102 return 1; 103} 104 105IPaddr.mask(a1: self IPaddr, a2: IPaddr): IPaddr 106{ 107 c := array[IPaddrlen] of byte; 108 for(i := 0; i < IPaddrlen; i++) 109 c[i] = a1.a[i] & a2.a[i]; 110 return IPaddr(c); 111} 112 113IPaddr.maskn(a1: self IPaddr, a2: IPaddr): IPaddr 114{ 115 c := array[IPaddrlen] of byte; 116 for(i := 0; i < IPaddrlen; i++) 117 c[i] = a1.a[i] & ~a2.a[i]; 118 return IPaddr(c); 119} 120 121IPaddr.isv4(ip: self IPaddr): int 122{ 123 for(i := 0; i < IPv4off; i++) 124 if(ip.a[i] != v4prefix[i]) 125 return 0; 126 return 1; 127} 128 129IPaddr.ismulticast(ip: self IPaddr): int 130{ 131 if(ip.isv4()){ 132 v := int ip.a[IPv4off]; 133 return v >= 16rE0 && v < 16rF0 || ip.eq(v4bcast); # rfc1112 134 } 135 return ip.a[0] == byte 16rFF; 136} 137 138IPaddr.isvalid(ip: self IPaddr): int 139{ 140 return !ip.eq(noaddr) && !ip.eq(v4noaddr); 141} 142 143IPaddr.v4(ip: self IPaddr): array of byte 144{ 145 if(!ip.isv4() && !ip.eq(noaddr)) 146 return nil; 147 a := array[4] of byte; 148 for(i := 0; i < 4; i++) 149 a[i] = ip.a[IPv4off+i]; 150 return a; 151} 152 153IPaddr.v6(ip: self IPaddr): array of byte 154{ 155 a := array[IPaddrlen] of byte; 156 a[0:] = ip.a; 157 return a; 158} 159 160IPaddr.class(ip: self IPaddr): int 161{ 162 if(!ip.isv4()) 163 return 6; 164 return int ip.a[IPv4off]>>6; 165} 166 167IPaddr.classmask(ip: self IPaddr): IPaddr 168{ 169 m := allbits.copy(); 170 if(!ip.isv4()) 171 return m; 172 if((n := ip.class()) == 0) 173 n = 1; 174 for(i := IPaddrlen-4+n; i < IPaddrlen; i++) 175 m.a[i] = byte 0; 176 return m; 177} 178 179# 180# rfc2373 181# 182 183IPaddr.parse(s: string): (int, IPaddr) 184{ 185 a := noaddr.copy(); 186 col := 0; 187 gap := 0; 188 for(i:=0; i<IPaddrlen && s != ""; i+=2){ 189 c := 'x'; 190 v := 0; 191 for(m := 0; m < len s && (c = s[m]) != '.' && c != ':'; m++){ 192 d := 0; 193 if(c >= '0' && c <= '9') 194 d = c-'0'; 195 else if(c >= 'a' && c <= 'f') 196 d = c-'a'+10; 197 else if(c >= 'A' && c <= 'F') 198 d = c-'A'+10; 199 else 200 return (-1, a); 201 v = (v<<4) | d; 202 } 203 if(c == '.'){ 204 if(parseipv4(a.a[i:], s) < 0) 205 return (-1, noaddr.copy()); 206 i += IPv4addrlen; 207 break; 208 } 209 if(v > 16rFFFF) 210 return (-1, a); 211 a.a[i] = byte (v>>8); 212 a.a[i+1] = byte v; 213 if(c == ':'){ 214 col = 1; 215 if(++m < len s && s[m] == ':'){ 216 if(gap > 0) 217 return (-1, a); 218 gap = i+2; 219 m++; 220 } 221 } 222 s = s[m:]; 223 } 224 if(i < IPaddrlen){ # mind the gap 225 ns := i-gap; 226 for(j := 1; j <= ns; j++){ 227 a.a[IPaddrlen-j] = a.a[i-j]; 228 a.a[i-j] = byte 0; 229 } 230 } 231 if(!col) 232 a.a[0:] = v4prefix; 233 return (0, IPaddr(a)); 234} 235 236IPaddr.parsemask(s: string): (int, IPaddr) 237{ 238 return parsemask(s, 128); 239} 240 241IPaddr.parsecidr(s: string): (int, IPaddr, IPaddr) 242{ 243 for(i := 0; i < len s && s[i] != '/'; i++) 244 ; 245 (ok, a) := IPaddr.parse(s[0:i]); 246 if(i < len s){ 247 (ok2, m) := IPaddr.parsemask(s[i:]); 248 if(ok < 0 || ok2 < 0) 249 return (-1, a, m); 250 return (0, a, m); 251 } 252 return (ok, a, allbits.copy()); 253} 254 255parseipv4(b: array of byte, s: string): int 256{ 257 a := array[4] of {* => 0}; 258 o := 0; 259 for(i := 0; i < 4 && o < len s; i++){ 260 for(m := o; m < len s && (c := s[m]) != '.'; m++) 261 if(!(c >= '0' && c <= '9')) 262 return -1; 263 if(m == o) 264 return -1; 265 a[i] = int big s[o:m]; 266 b[i] = byte a[i]; 267 if(m < len s && s[m] == '.') 268 m++; 269 o = m; 270 } 271 case i { 272 1 => # 32 bit 273 b[0] = byte (a[0] >> 24); 274 b[1] = byte (a[0] >> 16); 275 b[2] = byte (a[0] >> 8); 276 b[3] = byte a[0]; 277 2 => 278 if(a[0] < 256){ # 8/24 279 b[0] = byte a[0]; 280 b[1] = byte (a[1]>>16); 281 b[2] = byte (a[1]>>8); 282 }else if(a[0] < 65536){ # 16/16 283 b[0] = byte (a[0]>>8); 284 b[1] = byte a[0]; 285 b[2] = byte (a[1]>>16); 286 }else{ # 24/8 287 b[0] = byte (a[0]>>16); 288 b[1] = byte (a[0]>>8); 289 b[2] = byte a[0]; 290 } 291 b[3] = byte a[1]; 292 3 => # 8/8/16 293 b[0] = byte a[0]; 294 b[1] = byte a[1]; 295 b[2] = byte (a[2]>>16); 296 b[3] = byte a[2]; 297 } 298 return 0; 299} 300 301parsemask(s: string, abits: int): (int, IPaddr) 302{ 303 m := allbits.copy(); 304 if(s == nil) 305 return (0, m); 306 if(s[0] != '/'){ 307 (ok, a) := IPaddr.parse(s); 308 if(ok < 0) 309 return (0, m); 310 if(a.isv4()) 311 a.a[0:] = m.a[0:IPv4off]; 312 return (0, a); 313 } 314 if(len s == 1) 315 return (0, m); 316 nbit := int s[1:]; 317 if(nbit < 0) 318 return (-1, m); 319 if(nbit > abits) 320 return (0, m); 321 nbit = abits-nbit; 322 i := IPaddrlen; 323 for(; nbit >= 8; nbit -= 8) 324 m.a[--i] = byte 0; 325 if(nbit > 0) 326 m.a[i-1] &= byte (~0<<nbit); 327 return (0, m); 328} 329 330IPaddr.text(a: self IPaddr): string 331{ 332 b := a.a; 333 if(b == nil) 334 return "::"; 335 if(a.isv4()) 336 return sys->sprint("%d.%d.%d.%d", int b[IPv4off], int b[IPv4off+1], int b[IPv4off+2], int b[IPv4off+3]); 337 cs := -1; 338 nc := 0; 339 for(i:=0; i<IPaddrlen; i+=2) 340 if(int b[i] == 0 && int b[i+1] == 0){ 341 for(j:=i+2; j<IPaddrlen; j+=2) 342 if(int b[j] != 0 || int b[j+1] != 0) 343 break; 344 if(j-i > nc){ 345 nc = j-i; 346 cs = i; 347 } 348 } 349 if(nc <= 2) 350 cs = -1; 351 s := ""; 352 for(i=0; i<IPaddrlen; ){ 353 if(i == cs){ 354 s += "::"; 355 i += nc; 356 }else{ 357 if(s != "" && s[len s-1]!=':') 358 s[len s] = ':'; 359 v := (int a.a[i] << 8) | int a.a[i+1]; 360 s += sys->sprint("%ux", v); 361 i += 2; 362 } 363 } 364 return s; 365} 366 367IPaddr.masktext(a: self IPaddr): string 368{ 369 b := a.a; 370 if(b == nil) 371 return "/0"; 372 for(i:=0; i<IPaddrlen; i++) 373 if(i == IPv4off) 374 return sys->sprint("%d.%d.%d.%d", int b[IPv4off], int b[IPv4off+1], int b[IPv4off+2], int b[IPv4off+3]); 375 else if(b[i] != byte 16rFF) 376 break; 377 for(j:=i+1; j<IPaddrlen; j++) 378 if(b[j] != byte 0) 379 return a.text(); 380 nbit := 8*i; 381 if(i < IPaddrlen){ 382 v := int b[i]; 383 for(m := 16r80; m != 0; m >>= 1){ 384 if((v & m) == 0) 385 break; 386 v &= ~m; 387 nbit++; 388 } 389 if(v != 0) 390 return a.text(); 391 } 392 return sys->sprint("/%d", nbit); 393} 394 395addressesof(ifcs: list of ref Ipifc, all: int): list of IPaddr 396{ 397 ra: list of IPaddr; 398 runi: list of IPaddr; 399 for(; ifcs != nil; ifcs = tl ifcs){ 400 for(ifcas :=(hd ifcs).addrs; ifcs != nil; ifcs = tl ifcs){ 401 a := (hd ifcas).ip; 402 if(all || !(a.eq(noaddr) || a.eq(v4noaddr))){ # ignore unspecified and loopback 403 if(a.ismulticast() || a.eq(selfv4) || a.eq(selfv6)) 404 ra = a :: ra; 405 else 406 runi = a :: runi; 407 } 408 } 409 } 410 # unicast first, then others, both sets in order as found 411 # for ipv6, might want to give priority to unicast other than link- and site-local 412 al: list of IPaddr; 413 for(; ra != nil; ra = tl ra) 414 al = hd ra :: al; 415 for(; runi != nil; runi = tl runi) 416 al = hd runi :: al; 417 return al; 418} 419 420interfaceof(l: list of ref Ipifc, ip: IPaddr): (ref Ipifc, ref Ifcaddr) 421{ 422 for(; l != nil; l = tl l){ 423 ifc := hd l; 424 for(addrs := ifc.addrs; addrs != nil; addrs = tl addrs){ 425 a := hd addrs; 426 if(ip.mask(a.mask).eq(a.net)) 427 return (ifc, a); 428 } 429 } 430 return (nil, nil); 431} 432 433ownerof(l: list of ref Ipifc, ip: IPaddr): (ref Ipifc, ref Ifcaddr) 434{ 435 for(; l != nil; l = tl l){ 436 ifc := hd l; 437 for(addrs := ifc.addrs; addrs != nil; addrs = tl addrs){ 438 a := hd addrs; 439 if(ip.eq(a.ip)) 440 return (ifc, a); 441 } 442 } 443 return (nil, nil); 444} 445 446readipifc(net: string, index: int): (list of ref Ipifc, string) 447{ 448 if(net == nil) 449 net = "/net"; 450 if(index < 0){ 451 ifcs: list of ref Ipifc; 452 dirfd := sys->open(net+"/ipifc", Sys->OREAD); 453 if(dirfd == nil) 454 return (nil, sys->sprint("%r")); 455 err: string; 456 for(;;){ 457 (nd, dirs) := sys->dirread(dirfd); 458 if(nd <= 0){ 459 if(nd < 0) 460 err = sys->sprint("%r"); 461 break; 462 } 463 for(i:=0; i<nd; i++) 464 if((dn := dirs[i].name) != nil && dn[0]>='0' && dn[0]<='9'){ 465 index = int dn; 466 ifc := readstatus(net+"/ipifc/"+dn+"/status", index); 467 if(ifc != nil) 468 ifcs = ifc :: ifcs; 469 } 470 } 471 l := ifcs; 472 for(ifcs = nil; l != nil; l = tl l) 473 ifcs = hd l :: ifcs; 474 return (ifcs, err); 475 } 476 ifc := readstatus(net+"/ipifc/"+string index+"/status", index); 477 if(ifc == nil) 478 return (nil, sys->sprint("%r")); 479 return (ifc :: nil, nil); 480} 481 482# 483# return data structure containing values read from status file: 484# 485# device /net/ether0 maxtu 1514 sendra 0 recvra 0 mflag 0 oflag 0 maxraint 600000 minraint 200000 linkmtu 0 reachtime 0 rxmitra 0 ttl 255 routerlt 1800000 pktin 47609 pktout 42322 errin 0 errout 0 486# 144.32.112.83 /119 144.32.112.0 4294967295 4294967295 487# ... 488# 489 490readstatus(file: string, index: int): ref Ipifc 491{ 492 fd := sys->open(file, Sys->OREAD); 493 if(fd == nil) 494 return nil; 495 contents := slurp(fd); 496 fd = nil; 497 (nline, lines) := sys->tokenize(contents, "\n"); 498 if(nline <= 0){ 499 sys->werrstr("unexpected ipifc status file format"); 500 return nil; 501 } 502 (nil, details) := sys->tokenize(hd lines, " \t\n"); 503 lines = tl lines; 504 ifc := ref Ipifc; 505 ifc.index = index; 506 ifc.dev = valof(details, "device"); 507 ifc.mtu = int valof(details, "maxtu"); 508 ifc.pktin = big valof(details, "pktin"); 509 ifc.pktout = big valof(details, "pktout"); 510 ifc.errin = big valof(details, "errin"); 511 ifc.errout = big valof(details, "errout"); 512 ifc.sendra = int valof(details, "sendra"); 513 ifc.recvra = int valof(details, "recvra"); 514 ifc.rp.mflag = int valof(details, "mflag"); 515 ifc.rp.oflag = int valof(details, "oflag"); 516 ifc.rp.maxraint = int valof(details, "maxraint"); 517 ifc.rp.minraint = int valof(details, "minraint"); 518 ifc.rp.linkmtu = int valof(details, "linkmtu"); 519 ifc.rp.reachtime = int valof(details, "reachtime"); 520 ifc.rp.rxmitra = int valof(details, "rxmitra"); 521 ifc.rp.ttl = int valof(details, "ttl"); 522 ifc.rp.routerlt = int valof(details, "routerlt"); 523 addrs: list of ref Ifcaddr; 524 for(; lines != nil; lines = tl lines){ 525 (nf, fields) := sys->tokenize(hd lines, " \t\n"); 526 if(nf >= 3){ 527 addr := ref Ifcaddr; 528 (nil, addr.ip) = IPaddr.parse(hd fields); fields = tl fields; 529 (nil, addr.mask) = IPaddr.parsemask(hd fields); fields = tl fields; 530 (nil, addr.net) = IPaddr.parse(hd fields); fields = tl fields; 531 if(nf >= 5){ 532 addr.preflt = big hd fields; fields = tl fields; 533 addr.validlt = big hd fields; fields = tl fields; 534 }else{ 535 addr.preflt = big 0; 536 addr.validlt = big 0; 537 } 538 addrs = addr :: addrs; 539 } 540 } 541 for(; addrs != nil; addrs = tl addrs) 542 ifc.addrs = hd addrs :: ifc.addrs; 543 return ifc; 544} 545 546slurp(fd: ref Sys->FD): string 547{ 548 buf := array[2048] of byte; 549 s := ""; 550 while((n := sys->read(fd, buf, len buf)) > 0) 551 s += string buf[0:n]; 552 return s; 553} 554 555valof(l: list of string, attr: string): string 556{ 557 while(l != nil){ 558 label := hd l; 559 l = tl l; 560 if(label == attr){ 561 if(l == nil) 562 return nil; 563 return hd l; 564 } 565 if(l != nil) 566 l = tl l; 567 } 568 return nil; 569} 570 571Udphdr.new(): ref Udphdr 572{ 573 return ref Udphdr(noaddr, noaddr, noaddr, 0, 0); 574} 575 576Udphdr.unpack(a: array of byte, n: int): ref Udphdr 577{ 578 case n { 579 Udp4hdrlen => 580 u := ref Udphdr; 581 u.raddr = IPaddr.newv4(a[0:]); 582 u.laddr = IPaddr.newv4(a[IPv4addrlen:]); 583 u.rport = get2(a, 2*IPv4addrlen); 584 u.lport = get2(a, 2*IPv4addrlen+2); 585 u.ifcaddr = u.laddr.copy(); 586 return u; 587 OUdphdrlen => 588 u := ref Udphdr; 589 u.raddr = IPaddr.newv6(a[0:]); 590 u.laddr = IPaddr.newv6(a[IPaddrlen:]); 591 u.rport = get2(a, 2*IPaddrlen); 592 u.lport = get2(a, 2*IPaddrlen+2); 593 u.ifcaddr = u.laddr.copy(); 594 return u; 595 Udphdrlen => 596 u := ref Udphdr; 597 u.raddr = IPaddr.newv6(a[0:]); 598 u.laddr = IPaddr.newv6(a[IPaddrlen:]); 599 u.ifcaddr = IPaddr.newv6(a[2*IPaddrlen:]); 600 u.rport = get2(a, 3*IPaddrlen); 601 u.lport = get2(a, 3*IPaddrlen+2); 602 return u; 603 * => 604 raise "Udphdr.unpack: bad length"; 605 } 606} 607 608Udphdr.pack(u: self ref Udphdr, a: array of byte, n: int) 609{ 610 case n { 611 Udp4hdrlen => 612 a[0:] = u.raddr.v4(); 613 a[IPv4addrlen:] = u.laddr.v4(); 614 put2(a, 2*IPv4addrlen, u.rport); 615 put2(a, 2*IPv4addrlen+2, u.lport); 616 OUdphdrlen => 617 a[0:] = u.raddr.v6(); 618 a[IPaddrlen:] = u.laddr.v6(); 619 put2(a, 2*IPaddrlen, u.rport); 620 put2(a, 2*IPaddrlen+2, u.lport); 621 Udphdrlen => 622 a[0:] = u.raddr.v6(); 623 a[IPaddrlen:] = u.laddr.v6(); 624 a[2*IPaddrlen:] = u.ifcaddr.v6(); 625 put2(a, 3*IPaddrlen, u.rport); 626 put2(a, 3*IPaddrlen+2, u.lport); 627 * => 628 raise "Udphdr.pack: bad length"; 629 } 630} 631 632get2(a: array of byte, o: int): int 633{ 634 return (int a[o] << 8) | int a[o+1]; 635} 636 637put2(a: array of byte, o: int, val: int): int 638{ 639 a[o] = byte (val>>8); 640 a[o+1] = byte val; 641 return o+2; 642} 643 644get4(a: array of byte, o: int): int 645{ 646 return (((((int a[o] << 8)| int a[o+1]) << 8) | int a[o+2]) << 8) | int a[o+3]; 647} 648 649put4(a: array of byte, o: int, val: int): int 650{ 651 a[o] = byte (val>>24); 652 a[o+1] = byte (val>>16); 653 a[o+2] = byte (val>>8); 654 a[o+3] = byte val; 655 return o+4; 656} 657