137da2899SCharles.Forsythimplement IP; 237da2899SCharles.Forsyth 337da2899SCharles.Forsyth# 437da2899SCharles.Forsyth# Copyright © 2003,2004 Vita Nuova Holdings Limited. All rights reserved. 537da2899SCharles.Forsyth# 637da2899SCharles.Forsyth 737da2899SCharles.Forsythinclude "sys.m"; 837da2899SCharles.Forsyth sys: Sys; 937da2899SCharles.Forsyth 1037da2899SCharles.Forsythinclude "ip.m"; 1137da2899SCharles.Forsyth 1237da2899SCharles.Forsythinit() 1337da2899SCharles.Forsyth{ 1437da2899SCharles.Forsyth sys = load Sys Sys->PATH; 1537da2899SCharles.Forsyth v4prefix = array[] of { 1637da2899SCharles.Forsyth byte 0, byte 0, byte 0, byte 0, 1737da2899SCharles.Forsyth byte 0, byte 0, byte 0, byte 0, 1837da2899SCharles.Forsyth byte 0, byte 0, byte 16rFF, byte 16rFF, 1937da2899SCharles.Forsyth }; 2037da2899SCharles.Forsyth 2137da2899SCharles.Forsyth v4bcast = IPaddr(array[] of { 2237da2899SCharles.Forsyth byte 0, byte 0, byte 0, byte 0, 2337da2899SCharles.Forsyth byte 0, byte 0, byte 0, byte 0, 2437da2899SCharles.Forsyth byte 0, byte 0, byte 16rFF, byte 16rFF, 2537da2899SCharles.Forsyth byte 16rFF, byte 16rFF, byte 16rFF, byte 16rFF, 2637da2899SCharles.Forsyth }); 2737da2899SCharles.Forsyth 2837da2899SCharles.Forsyth v4allsys = IPaddr(array[] of { 2937da2899SCharles.Forsyth byte 0, byte 0, byte 0, byte 0, 3037da2899SCharles.Forsyth byte 0, byte 0, byte 0, byte 0, 3137da2899SCharles.Forsyth byte 0, byte 0, byte 16rFF, byte 16rFF, 3237da2899SCharles.Forsyth byte 16rE0, byte 0, byte 0, byte 16r01, 3337da2899SCharles.Forsyth }); 3437da2899SCharles.Forsyth 3537da2899SCharles.Forsyth v4allrouter = IPaddr(array[] of { 3637da2899SCharles.Forsyth byte 0, byte 0, byte 0, byte 0, 3737da2899SCharles.Forsyth byte 0, byte 0, byte 0, byte 0, 3837da2899SCharles.Forsyth byte 0, byte 0, byte 16rFF, byte 16rFF, 3937da2899SCharles.Forsyth byte 16rE0, byte 0, byte 0, byte 16r02, 4037da2899SCharles.Forsyth }); 4137da2899SCharles.Forsyth 4237da2899SCharles.Forsyth v4noaddr = IPaddr(array[] of { 4337da2899SCharles.Forsyth byte 0, byte 0, byte 0, byte 0, 4437da2899SCharles.Forsyth byte 0, byte 0, byte 0, byte 0, 4537da2899SCharles.Forsyth byte 0, byte 0, byte 16rFF, byte 16rFF, 4637da2899SCharles.Forsyth byte 0, byte 0, byte 0, byte 0, 4737da2899SCharles.Forsyth }); 4837da2899SCharles.Forsyth 4937da2899SCharles.Forsyth selfv6 = IPaddr(array[] of { 5037da2899SCharles.Forsyth byte 0, byte 0, byte 0, byte 0, 5137da2899SCharles.Forsyth byte 0, byte 0, byte 0, byte 0, 5237da2899SCharles.Forsyth byte 0, byte 0, byte 0, byte 0, 5337da2899SCharles.Forsyth byte 0, byte 0, byte 0, byte 1, 5437da2899SCharles.Forsyth }); 5537da2899SCharles.Forsyth 5637da2899SCharles.Forsyth selfv4 = IPaddr(array[] of { 5737da2899SCharles.Forsyth byte 0, byte 0, byte 0, byte 0, 5837da2899SCharles.Forsyth byte 0, byte 0, byte 0, byte 0, 5937da2899SCharles.Forsyth byte 0, byte 0, byte 16rFF, byte 16rFF, 6037da2899SCharles.Forsyth byte 127, byte 0, byte 0, byte 1, 6137da2899SCharles.Forsyth }); 6237da2899SCharles.Forsyth 6337da2899SCharles.Forsyth noaddr = IPaddr(array[] of {0 to IPaddrlen-1 => byte 0}); 6437da2899SCharles.Forsyth allbits = IPaddr(array[] of {0 to IPaddrlen-1 => byte 16rFF}); 6537da2899SCharles.Forsyth} 6637da2899SCharles.Forsyth 6737da2899SCharles.ForsythIPaddr.newv6(a: array of byte): IPaddr 6837da2899SCharles.Forsyth{ 69*3293d124Sforsyth b := array[IPaddrlen] of byte; 7037da2899SCharles.Forsyth b[0:] = a[0:IPaddrlen]; 7137da2899SCharles.Forsyth return IPaddr(b); 7237da2899SCharles.Forsyth} 7337da2899SCharles.Forsyth 7437da2899SCharles.ForsythIPaddr.newv4(a: array of byte): IPaddr 7537da2899SCharles.Forsyth{ 7637da2899SCharles.Forsyth b := array[IPaddrlen] of byte; 7737da2899SCharles.Forsyth b[0:] = v4prefix; 7837da2899SCharles.Forsyth b[IPv4off:] = a[0:IPv4addrlen]; 7937da2899SCharles.Forsyth return IPaddr(b); 8037da2899SCharles.Forsyth} 8137da2899SCharles.Forsyth 8237da2899SCharles.ForsythIPaddr.copy(ip: self IPaddr): IPaddr 8337da2899SCharles.Forsyth{ 8437da2899SCharles.Forsyth if(ip.a == nil) 8537da2899SCharles.Forsyth return noaddr.copy(); 86*3293d124Sforsyth a := array[IPaddrlen] of byte; 8737da2899SCharles.Forsyth a[0:] = ip.a; 8837da2899SCharles.Forsyth return IPaddr(a); 8937da2899SCharles.Forsyth} 9037da2899SCharles.Forsyth 9137da2899SCharles.ForsythIPaddr.eq(ip: self IPaddr, v: IPaddr): int 9237da2899SCharles.Forsyth{ 9337da2899SCharles.Forsyth a := ip.a; 9437da2899SCharles.Forsyth if(a == nil) 9537da2899SCharles.Forsyth a = noaddr.a; 9637da2899SCharles.Forsyth b := v.a; 9737da2899SCharles.Forsyth if(b == nil) 9837da2899SCharles.Forsyth b = noaddr.a; 9937da2899SCharles.Forsyth for(i := 0; i < IPaddrlen; i++) 10037da2899SCharles.Forsyth if(a[i] != b[i]) 10137da2899SCharles.Forsyth return 0; 10237da2899SCharles.Forsyth return 1; 10337da2899SCharles.Forsyth} 10437da2899SCharles.Forsyth 10537da2899SCharles.ForsythIPaddr.mask(a1: self IPaddr, a2: IPaddr): IPaddr 10637da2899SCharles.Forsyth{ 10737da2899SCharles.Forsyth c := array[IPaddrlen] of byte; 10837da2899SCharles.Forsyth for(i := 0; i < IPaddrlen; i++) 10937da2899SCharles.Forsyth c[i] = a1.a[i] & a2.a[i]; 11037da2899SCharles.Forsyth return IPaddr(c); 11137da2899SCharles.Forsyth} 11237da2899SCharles.Forsyth 11337da2899SCharles.ForsythIPaddr.maskn(a1: self IPaddr, a2: IPaddr): IPaddr 11437da2899SCharles.Forsyth{ 11537da2899SCharles.Forsyth c := array[IPaddrlen] of byte; 11637da2899SCharles.Forsyth for(i := 0; i < IPaddrlen; i++) 11737da2899SCharles.Forsyth c[i] = a1.a[i] & ~a2.a[i]; 11837da2899SCharles.Forsyth return IPaddr(c); 11937da2899SCharles.Forsyth} 12037da2899SCharles.Forsyth 12137da2899SCharles.ForsythIPaddr.isv4(ip: self IPaddr): int 12237da2899SCharles.Forsyth{ 12337da2899SCharles.Forsyth for(i := 0; i < IPv4off; i++) 12437da2899SCharles.Forsyth if(ip.a[i] != v4prefix[i]) 12537da2899SCharles.Forsyth return 0; 12637da2899SCharles.Forsyth return 1; 12737da2899SCharles.Forsyth} 12837da2899SCharles.Forsyth 12937da2899SCharles.ForsythIPaddr.ismulticast(ip: self IPaddr): int 13037da2899SCharles.Forsyth{ 13137da2899SCharles.Forsyth if(ip.isv4()){ 13237da2899SCharles.Forsyth v := int ip.a[IPv4off]; 13337da2899SCharles.Forsyth return v >= 16rE0 && v < 16rF0 || ip.eq(v4bcast); # rfc1112 13437da2899SCharles.Forsyth } 13537da2899SCharles.Forsyth return ip.a[0] == byte 16rFF; 13637da2899SCharles.Forsyth} 13737da2899SCharles.Forsyth 13837da2899SCharles.ForsythIPaddr.isvalid(ip: self IPaddr): int 13937da2899SCharles.Forsyth{ 14037da2899SCharles.Forsyth return !ip.eq(noaddr) && !ip.eq(v4noaddr); 14137da2899SCharles.Forsyth} 14237da2899SCharles.Forsyth 14337da2899SCharles.ForsythIPaddr.v4(ip: self IPaddr): array of byte 14437da2899SCharles.Forsyth{ 14537da2899SCharles.Forsyth if(!ip.isv4() && !ip.eq(noaddr)) 14637da2899SCharles.Forsyth return nil; 14737da2899SCharles.Forsyth a := array[4] of byte; 14837da2899SCharles.Forsyth for(i := 0; i < 4; i++) 14937da2899SCharles.Forsyth a[i] = ip.a[IPv4off+i]; 15037da2899SCharles.Forsyth return a; 15137da2899SCharles.Forsyth} 15237da2899SCharles.Forsyth 15337da2899SCharles.ForsythIPaddr.v6(ip: self IPaddr): array of byte 15437da2899SCharles.Forsyth{ 15537da2899SCharles.Forsyth a := array[IPaddrlen] of byte; 15637da2899SCharles.Forsyth a[0:] = ip.a; 15737da2899SCharles.Forsyth return a; 15837da2899SCharles.Forsyth} 15937da2899SCharles.Forsyth 16037da2899SCharles.ForsythIPaddr.class(ip: self IPaddr): int 16137da2899SCharles.Forsyth{ 16237da2899SCharles.Forsyth if(!ip.isv4()) 16337da2899SCharles.Forsyth return 6; 16437da2899SCharles.Forsyth return int ip.a[IPv4off]>>6; 16537da2899SCharles.Forsyth} 16637da2899SCharles.Forsyth 16737da2899SCharles.ForsythIPaddr.classmask(ip: self IPaddr): IPaddr 16837da2899SCharles.Forsyth{ 16937da2899SCharles.Forsyth m := allbits.copy(); 17037da2899SCharles.Forsyth if(!ip.isv4()) 17137da2899SCharles.Forsyth return m; 17237da2899SCharles.Forsyth if((n := ip.class()) == 0) 17337da2899SCharles.Forsyth n = 1; 17437da2899SCharles.Forsyth for(i := IPaddrlen-4+n; i < IPaddrlen; i++) 17537da2899SCharles.Forsyth m.a[i] = byte 0; 17637da2899SCharles.Forsyth return m; 17737da2899SCharles.Forsyth} 17837da2899SCharles.Forsyth 17937da2899SCharles.Forsyth# 18037da2899SCharles.Forsyth# rfc2373 18137da2899SCharles.Forsyth# 18237da2899SCharles.Forsyth 18337da2899SCharles.ForsythIPaddr.parse(s: string): (int, IPaddr) 18437da2899SCharles.Forsyth{ 18537da2899SCharles.Forsyth a := noaddr.copy(); 18637da2899SCharles.Forsyth col := 0; 18737da2899SCharles.Forsyth gap := 0; 18837da2899SCharles.Forsyth for(i:=0; i<IPaddrlen && s != ""; i+=2){ 18937da2899SCharles.Forsyth c := 'x'; 19037da2899SCharles.Forsyth v := 0; 19137da2899SCharles.Forsyth for(m := 0; m < len s && (c = s[m]) != '.' && c != ':'; m++){ 19237da2899SCharles.Forsyth d := 0; 19337da2899SCharles.Forsyth if(c >= '0' && c <= '9') 19437da2899SCharles.Forsyth d = c-'0'; 19537da2899SCharles.Forsyth else if(c >= 'a' && c <= 'f') 19637da2899SCharles.Forsyth d = c-'a'+10; 19737da2899SCharles.Forsyth else if(c >= 'A' && c <= 'F') 19837da2899SCharles.Forsyth d = c-'A'+10; 19937da2899SCharles.Forsyth else 20037da2899SCharles.Forsyth return (-1, a); 20137da2899SCharles.Forsyth v = (v<<4) | d; 20237da2899SCharles.Forsyth } 20337da2899SCharles.Forsyth if(c == '.'){ 20437da2899SCharles.Forsyth if(parseipv4(a.a[i:], s) < 0) 20537da2899SCharles.Forsyth return (-1, noaddr.copy()); 20637da2899SCharles.Forsyth i += IPv4addrlen; 20737da2899SCharles.Forsyth break; 20837da2899SCharles.Forsyth } 20937da2899SCharles.Forsyth if(v > 16rFFFF) 21037da2899SCharles.Forsyth return (-1, a); 21137da2899SCharles.Forsyth a.a[i] = byte (v>>8); 21237da2899SCharles.Forsyth a.a[i+1] = byte v; 21337da2899SCharles.Forsyth if(c == ':'){ 21437da2899SCharles.Forsyth col = 1; 21537da2899SCharles.Forsyth if(++m < len s && s[m] == ':'){ 21637da2899SCharles.Forsyth if(gap > 0) 21737da2899SCharles.Forsyth return (-1, a); 21837da2899SCharles.Forsyth gap = i+2; 21937da2899SCharles.Forsyth m++; 22037da2899SCharles.Forsyth } 22137da2899SCharles.Forsyth } 22237da2899SCharles.Forsyth s = s[m:]; 22337da2899SCharles.Forsyth } 22437da2899SCharles.Forsyth if(i < IPaddrlen){ # mind the gap 22537da2899SCharles.Forsyth ns := i-gap; 22637da2899SCharles.Forsyth for(j := 1; j <= ns; j++){ 22737da2899SCharles.Forsyth a.a[IPaddrlen-j] = a.a[i-j]; 22837da2899SCharles.Forsyth a.a[i-j] = byte 0; 22937da2899SCharles.Forsyth } 23037da2899SCharles.Forsyth } 23137da2899SCharles.Forsyth if(!col) 23237da2899SCharles.Forsyth a.a[0:] = v4prefix; 23337da2899SCharles.Forsyth return (0, IPaddr(a)); 23437da2899SCharles.Forsyth} 23537da2899SCharles.Forsyth 23637da2899SCharles.ForsythIPaddr.parsemask(s: string): (int, IPaddr) 23737da2899SCharles.Forsyth{ 23837da2899SCharles.Forsyth return parsemask(s, 128); 23937da2899SCharles.Forsyth} 24037da2899SCharles.Forsyth 24137da2899SCharles.ForsythIPaddr.parsecidr(s: string): (int, IPaddr, IPaddr) 24237da2899SCharles.Forsyth{ 24337da2899SCharles.Forsyth for(i := 0; i < len s && s[i] != '/'; i++) 24437da2899SCharles.Forsyth ; 24537da2899SCharles.Forsyth (ok, a) := IPaddr.parse(s[0:i]); 24637da2899SCharles.Forsyth if(i < len s){ 24737da2899SCharles.Forsyth (ok2, m) := IPaddr.parsemask(s[i:]); 24837da2899SCharles.Forsyth if(ok < 0 || ok2 < 0) 24937da2899SCharles.Forsyth return (-1, a, m); 25037da2899SCharles.Forsyth return (0, a, m); 25137da2899SCharles.Forsyth } 25237da2899SCharles.Forsyth return (ok, a, allbits.copy()); 25337da2899SCharles.Forsyth} 25437da2899SCharles.Forsyth 25537da2899SCharles.Forsythparseipv4(b: array of byte, s: string): int 25637da2899SCharles.Forsyth{ 25737da2899SCharles.Forsyth a := array[4] of {* => 0}; 25837da2899SCharles.Forsyth o := 0; 25937da2899SCharles.Forsyth for(i := 0; i < 4 && o < len s; i++){ 26037da2899SCharles.Forsyth for(m := o; m < len s && (c := s[m]) != '.'; m++) 26137da2899SCharles.Forsyth if(!(c >= '0' && c <= '9')) 26237da2899SCharles.Forsyth return -1; 26337da2899SCharles.Forsyth if(m == o) 26437da2899SCharles.Forsyth return -1; 26537da2899SCharles.Forsyth a[i] = int big s[o:m]; 26637da2899SCharles.Forsyth b[i] = byte a[i]; 26737da2899SCharles.Forsyth if(m < len s && s[m] == '.') 26837da2899SCharles.Forsyth m++; 26937da2899SCharles.Forsyth o = m; 27037da2899SCharles.Forsyth } 27137da2899SCharles.Forsyth case i { 27237da2899SCharles.Forsyth 1 => # 32 bit 27337da2899SCharles.Forsyth b[0] = byte (a[0] >> 24); 27437da2899SCharles.Forsyth b[1] = byte (a[0] >> 16); 27537da2899SCharles.Forsyth b[2] = byte (a[0] >> 8); 27637da2899SCharles.Forsyth b[3] = byte a[0]; 27737da2899SCharles.Forsyth 2 => 27837da2899SCharles.Forsyth if(a[0] < 256){ # 8/24 27937da2899SCharles.Forsyth b[0] = byte a[0]; 28037da2899SCharles.Forsyth b[1] = byte (a[1]>>16); 28137da2899SCharles.Forsyth b[2] = byte (a[1]>>8); 28237da2899SCharles.Forsyth }else if(a[0] < 65536){ # 16/16 28337da2899SCharles.Forsyth b[0] = byte (a[0]>>8); 28437da2899SCharles.Forsyth b[1] = byte a[0]; 28537da2899SCharles.Forsyth b[2] = byte (a[1]>>16); 28637da2899SCharles.Forsyth }else{ # 24/8 28737da2899SCharles.Forsyth b[0] = byte (a[0]>>16); 28837da2899SCharles.Forsyth b[1] = byte (a[0]>>8); 28937da2899SCharles.Forsyth b[2] = byte a[0]; 29037da2899SCharles.Forsyth } 29137da2899SCharles.Forsyth b[3] = byte a[1]; 29237da2899SCharles.Forsyth 3 => # 8/8/16 29337da2899SCharles.Forsyth b[0] = byte a[0]; 29437da2899SCharles.Forsyth b[1] = byte a[1]; 29537da2899SCharles.Forsyth b[2] = byte (a[2]>>16); 29637da2899SCharles.Forsyth b[3] = byte a[2]; 29737da2899SCharles.Forsyth } 29837da2899SCharles.Forsyth return 0; 29937da2899SCharles.Forsyth} 30037da2899SCharles.Forsyth 30137da2899SCharles.Forsythparsemask(s: string, abits: int): (int, IPaddr) 30237da2899SCharles.Forsyth{ 30337da2899SCharles.Forsyth m := allbits.copy(); 30437da2899SCharles.Forsyth if(s == nil) 30537da2899SCharles.Forsyth return (0, m); 30637da2899SCharles.Forsyth if(s[0] != '/'){ 30737da2899SCharles.Forsyth (ok, a) := IPaddr.parse(s); 30837da2899SCharles.Forsyth if(ok < 0) 30937da2899SCharles.Forsyth return (0, m); 31037da2899SCharles.Forsyth if(a.isv4()) 31137da2899SCharles.Forsyth a.a[0:] = m.a[0:IPv4off]; 31237da2899SCharles.Forsyth return (0, a); 31337da2899SCharles.Forsyth } 31437da2899SCharles.Forsyth if(len s == 1) 31537da2899SCharles.Forsyth return (0, m); 31637da2899SCharles.Forsyth nbit := int s[1:]; 31737da2899SCharles.Forsyth if(nbit < 0) 31837da2899SCharles.Forsyth return (-1, m); 31937da2899SCharles.Forsyth if(nbit > abits) 32037da2899SCharles.Forsyth return (0, m); 32137da2899SCharles.Forsyth nbit = abits-nbit; 32237da2899SCharles.Forsyth i := IPaddrlen; 32337da2899SCharles.Forsyth for(; nbit >= 8; nbit -= 8) 32437da2899SCharles.Forsyth m.a[--i] = byte 0; 32537da2899SCharles.Forsyth if(nbit > 0) 32637da2899SCharles.Forsyth m.a[i-1] &= byte (~0<<nbit); 32737da2899SCharles.Forsyth return (0, m); 32837da2899SCharles.Forsyth} 32937da2899SCharles.Forsyth 33037da2899SCharles.ForsythIPaddr.text(a: self IPaddr): string 33137da2899SCharles.Forsyth{ 33237da2899SCharles.Forsyth b := a.a; 33337da2899SCharles.Forsyth if(b == nil) 33437da2899SCharles.Forsyth return "::"; 33537da2899SCharles.Forsyth if(a.isv4()) 33637da2899SCharles.Forsyth return sys->sprint("%d.%d.%d.%d", int b[IPv4off], int b[IPv4off+1], int b[IPv4off+2], int b[IPv4off+3]); 33737da2899SCharles.Forsyth cs := -1; 33837da2899SCharles.Forsyth nc := 0; 33937da2899SCharles.Forsyth for(i:=0; i<IPaddrlen; i+=2) 34037da2899SCharles.Forsyth if(int b[i] == 0 && int b[i+1] == 0){ 34137da2899SCharles.Forsyth for(j:=i+2; j<IPaddrlen; j+=2) 34237da2899SCharles.Forsyth if(int b[j] != 0 || int b[j+1] != 0) 34337da2899SCharles.Forsyth break; 34437da2899SCharles.Forsyth if(j-i > nc){ 34537da2899SCharles.Forsyth nc = j-i; 34637da2899SCharles.Forsyth cs = i; 34737da2899SCharles.Forsyth } 34837da2899SCharles.Forsyth } 34937da2899SCharles.Forsyth if(nc <= 2) 35037da2899SCharles.Forsyth cs = -1; 35137da2899SCharles.Forsyth s := ""; 35237da2899SCharles.Forsyth for(i=0; i<IPaddrlen; ){ 35337da2899SCharles.Forsyth if(i == cs){ 35437da2899SCharles.Forsyth s += "::"; 35537da2899SCharles.Forsyth i += nc; 35637da2899SCharles.Forsyth }else{ 35737da2899SCharles.Forsyth if(s != "" && s[len s-1]!=':') 35837da2899SCharles.Forsyth s[len s] = ':'; 35937da2899SCharles.Forsyth v := (int a.a[i] << 8) | int a.a[i+1]; 36037da2899SCharles.Forsyth s += sys->sprint("%ux", v); 36137da2899SCharles.Forsyth i += 2; 36237da2899SCharles.Forsyth } 36337da2899SCharles.Forsyth } 36437da2899SCharles.Forsyth return s; 36537da2899SCharles.Forsyth} 36637da2899SCharles.Forsyth 36737da2899SCharles.ForsythIPaddr.masktext(a: self IPaddr): string 36837da2899SCharles.Forsyth{ 36937da2899SCharles.Forsyth b := a.a; 37037da2899SCharles.Forsyth if(b == nil) 37137da2899SCharles.Forsyth return "/0"; 37237da2899SCharles.Forsyth for(i:=0; i<IPaddrlen; i++) 37337da2899SCharles.Forsyth if(i == IPv4off) 37437da2899SCharles.Forsyth return sys->sprint("%d.%d.%d.%d", int b[IPv4off], int b[IPv4off+1], int b[IPv4off+2], int b[IPv4off+3]); 37537da2899SCharles.Forsyth else if(b[i] != byte 16rFF) 37637da2899SCharles.Forsyth break; 37737da2899SCharles.Forsyth for(j:=i+1; j<IPaddrlen; j++) 37837da2899SCharles.Forsyth if(b[j] != byte 0) 37937da2899SCharles.Forsyth return a.text(); 38037da2899SCharles.Forsyth nbit := 8*i; 38137da2899SCharles.Forsyth if(i < IPaddrlen){ 38237da2899SCharles.Forsyth v := int b[i]; 38337da2899SCharles.Forsyth for(m := 16r80; m != 0; m >>= 1){ 38437da2899SCharles.Forsyth if((v & m) == 0) 38537da2899SCharles.Forsyth break; 38637da2899SCharles.Forsyth v &= ~m; 38737da2899SCharles.Forsyth nbit++; 38837da2899SCharles.Forsyth } 38937da2899SCharles.Forsyth if(v != 0) 39037da2899SCharles.Forsyth return a.text(); 39137da2899SCharles.Forsyth } 39237da2899SCharles.Forsyth return sys->sprint("/%d", nbit); 39337da2899SCharles.Forsyth} 39437da2899SCharles.Forsyth 39537da2899SCharles.Forsythaddressesof(ifcs: list of ref Ipifc, all: int): list of IPaddr 39637da2899SCharles.Forsyth{ 39737da2899SCharles.Forsyth ra: list of IPaddr; 39837da2899SCharles.Forsyth runi: list of IPaddr; 39937da2899SCharles.Forsyth for(; ifcs != nil; ifcs = tl ifcs){ 40037da2899SCharles.Forsyth for(ifcas :=(hd ifcs).addrs; ifcs != nil; ifcs = tl ifcs){ 40137da2899SCharles.Forsyth a := (hd ifcas).ip; 40237da2899SCharles.Forsyth if(all || !(a.eq(noaddr) || a.eq(v4noaddr))){ # ignore unspecified and loopback 40337da2899SCharles.Forsyth if(a.ismulticast() || a.eq(selfv4) || a.eq(selfv6)) 40437da2899SCharles.Forsyth ra = a :: ra; 40537da2899SCharles.Forsyth else 40637da2899SCharles.Forsyth runi = a :: runi; 40737da2899SCharles.Forsyth } 40837da2899SCharles.Forsyth } 40937da2899SCharles.Forsyth } 41037da2899SCharles.Forsyth # unicast first, then others, both sets in order as found 41137da2899SCharles.Forsyth # for ipv6, might want to give priority to unicast other than link- and site-local 41237da2899SCharles.Forsyth al: list of IPaddr; 41337da2899SCharles.Forsyth for(; ra != nil; ra = tl ra) 41437da2899SCharles.Forsyth al = hd ra :: al; 41537da2899SCharles.Forsyth for(; runi != nil; runi = tl runi) 41637da2899SCharles.Forsyth al = hd runi :: al; 41737da2899SCharles.Forsyth return al; 41837da2899SCharles.Forsyth} 41937da2899SCharles.Forsyth 42037da2899SCharles.Forsythinterfaceof(l: list of ref Ipifc, ip: IPaddr): (ref Ipifc, ref Ifcaddr) 42137da2899SCharles.Forsyth{ 42237da2899SCharles.Forsyth for(; l != nil; l = tl l){ 42337da2899SCharles.Forsyth ifc := hd l; 42437da2899SCharles.Forsyth for(addrs := ifc.addrs; addrs != nil; addrs = tl addrs){ 42537da2899SCharles.Forsyth a := hd addrs; 42637da2899SCharles.Forsyth if(ip.mask(a.mask).eq(a.net)) 42737da2899SCharles.Forsyth return (ifc, a); 42837da2899SCharles.Forsyth } 42937da2899SCharles.Forsyth } 43037da2899SCharles.Forsyth return (nil, nil); 43137da2899SCharles.Forsyth} 43237da2899SCharles.Forsyth 43337da2899SCharles.Forsythownerof(l: list of ref Ipifc, ip: IPaddr): (ref Ipifc, ref Ifcaddr) 43437da2899SCharles.Forsyth{ 43537da2899SCharles.Forsyth for(; l != nil; l = tl l){ 43637da2899SCharles.Forsyth ifc := hd l; 43737da2899SCharles.Forsyth for(addrs := ifc.addrs; addrs != nil; addrs = tl addrs){ 43837da2899SCharles.Forsyth a := hd addrs; 43937da2899SCharles.Forsyth if(ip.eq(a.ip)) 44037da2899SCharles.Forsyth return (ifc, a); 44137da2899SCharles.Forsyth } 44237da2899SCharles.Forsyth } 44337da2899SCharles.Forsyth return (nil, nil); 44437da2899SCharles.Forsyth} 44537da2899SCharles.Forsyth 44637da2899SCharles.Forsythreadipifc(net: string, index: int): (list of ref Ipifc, string) 44737da2899SCharles.Forsyth{ 44837da2899SCharles.Forsyth if(net == nil) 44937da2899SCharles.Forsyth net = "/net"; 45037da2899SCharles.Forsyth if(index < 0){ 45137da2899SCharles.Forsyth ifcs: list of ref Ipifc; 45237da2899SCharles.Forsyth dirfd := sys->open(net+"/ipifc", Sys->OREAD); 45337da2899SCharles.Forsyth if(dirfd == nil) 45437da2899SCharles.Forsyth return (nil, sys->sprint("%r")); 45537da2899SCharles.Forsyth err: string; 45637da2899SCharles.Forsyth for(;;){ 45737da2899SCharles.Forsyth (nd, dirs) := sys->dirread(dirfd); 45837da2899SCharles.Forsyth if(nd <= 0){ 45937da2899SCharles.Forsyth if(nd < 0) 46037da2899SCharles.Forsyth err = sys->sprint("%r"); 46137da2899SCharles.Forsyth break; 46237da2899SCharles.Forsyth } 46337da2899SCharles.Forsyth for(i:=0; i<nd; i++) 46437da2899SCharles.Forsyth if((dn := dirs[i].name) != nil && dn[0]>='0' && dn[0]<='9'){ 46537da2899SCharles.Forsyth index = int dn; 46637da2899SCharles.Forsyth ifc := readstatus(net+"/ipifc/"+dn+"/status", index); 46737da2899SCharles.Forsyth if(ifc != nil) 46837da2899SCharles.Forsyth ifcs = ifc :: ifcs; 46937da2899SCharles.Forsyth } 47037da2899SCharles.Forsyth } 47137da2899SCharles.Forsyth l := ifcs; 47237da2899SCharles.Forsyth for(ifcs = nil; l != nil; l = tl l) 47337da2899SCharles.Forsyth ifcs = hd l :: ifcs; 47437da2899SCharles.Forsyth return (ifcs, err); 47537da2899SCharles.Forsyth } 47637da2899SCharles.Forsyth ifc := readstatus(net+"/ipifc/"+string index+"/status", index); 47737da2899SCharles.Forsyth if(ifc == nil) 47837da2899SCharles.Forsyth return (nil, sys->sprint("%r")); 47937da2899SCharles.Forsyth return (ifc :: nil, nil); 48037da2899SCharles.Forsyth} 48137da2899SCharles.Forsyth 48237da2899SCharles.Forsyth# 48337da2899SCharles.Forsyth# return data structure containing values read from status file: 48437da2899SCharles.Forsyth# 48537da2899SCharles.Forsyth# 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 48637da2899SCharles.Forsyth# 144.32.112.83 /119 144.32.112.0 4294967295 4294967295 48737da2899SCharles.Forsyth# ... 48837da2899SCharles.Forsyth# 48937da2899SCharles.Forsyth 49037da2899SCharles.Forsythreadstatus(file: string, index: int): ref Ipifc 49137da2899SCharles.Forsyth{ 49237da2899SCharles.Forsyth fd := sys->open(file, Sys->OREAD); 49337da2899SCharles.Forsyth if(fd == nil) 49437da2899SCharles.Forsyth return nil; 49537da2899SCharles.Forsyth contents := slurp(fd); 49637da2899SCharles.Forsyth fd = nil; 49737da2899SCharles.Forsyth (nline, lines) := sys->tokenize(contents, "\n"); 49837da2899SCharles.Forsyth if(nline <= 0){ 49937da2899SCharles.Forsyth sys->werrstr("unexpected ipifc status file format"); 50037da2899SCharles.Forsyth return nil; 50137da2899SCharles.Forsyth } 50237da2899SCharles.Forsyth (nil, details) := sys->tokenize(hd lines, " \t\n"); 50337da2899SCharles.Forsyth lines = tl lines; 50437da2899SCharles.Forsyth ifc := ref Ipifc; 50537da2899SCharles.Forsyth ifc.index = index; 50637da2899SCharles.Forsyth ifc.dev = valof(details, "device"); 50737da2899SCharles.Forsyth ifc.mtu = int valof(details, "maxtu"); 50837da2899SCharles.Forsyth ifc.pktin = big valof(details, "pktin"); 50937da2899SCharles.Forsyth ifc.pktout = big valof(details, "pktout"); 51037da2899SCharles.Forsyth ifc.errin = big valof(details, "errin"); 51137da2899SCharles.Forsyth ifc.errout = big valof(details, "errout"); 51237da2899SCharles.Forsyth ifc.sendra = int valof(details, "sendra"); 51337da2899SCharles.Forsyth ifc.recvra = int valof(details, "recvra"); 51437da2899SCharles.Forsyth ifc.rp.mflag = int valof(details, "mflag"); 51537da2899SCharles.Forsyth ifc.rp.oflag = int valof(details, "oflag"); 51637da2899SCharles.Forsyth ifc.rp.maxraint = int valof(details, "maxraint"); 51737da2899SCharles.Forsyth ifc.rp.minraint = int valof(details, "minraint"); 51837da2899SCharles.Forsyth ifc.rp.linkmtu = int valof(details, "linkmtu"); 51937da2899SCharles.Forsyth ifc.rp.reachtime = int valof(details, "reachtime"); 52037da2899SCharles.Forsyth ifc.rp.rxmitra = int valof(details, "rxmitra"); 52137da2899SCharles.Forsyth ifc.rp.ttl = int valof(details, "ttl"); 52237da2899SCharles.Forsyth ifc.rp.routerlt = int valof(details, "routerlt"); 52337da2899SCharles.Forsyth addrs: list of ref Ifcaddr; 52437da2899SCharles.Forsyth for(; lines != nil; lines = tl lines){ 52537da2899SCharles.Forsyth (nf, fields) := sys->tokenize(hd lines, " \t\n"); 52637da2899SCharles.Forsyth if(nf >= 3){ 52737da2899SCharles.Forsyth addr := ref Ifcaddr; 52837da2899SCharles.Forsyth (nil, addr.ip) = IPaddr.parse(hd fields); fields = tl fields; 52937da2899SCharles.Forsyth (nil, addr.mask) = IPaddr.parsemask(hd fields); fields = tl fields; 53037da2899SCharles.Forsyth (nil, addr.net) = IPaddr.parse(hd fields); fields = tl fields; 53137da2899SCharles.Forsyth if(nf >= 5){ 53237da2899SCharles.Forsyth addr.preflt = big hd fields; fields = tl fields; 53337da2899SCharles.Forsyth addr.validlt = big hd fields; fields = tl fields; 53437da2899SCharles.Forsyth }else{ 53537da2899SCharles.Forsyth addr.preflt = big 0; 53637da2899SCharles.Forsyth addr.validlt = big 0; 53737da2899SCharles.Forsyth } 53837da2899SCharles.Forsyth addrs = addr :: addrs; 53937da2899SCharles.Forsyth } 54037da2899SCharles.Forsyth } 54137da2899SCharles.Forsyth for(; addrs != nil; addrs = tl addrs) 54237da2899SCharles.Forsyth ifc.addrs = hd addrs :: ifc.addrs; 54337da2899SCharles.Forsyth return ifc; 54437da2899SCharles.Forsyth} 54537da2899SCharles.Forsyth 54637da2899SCharles.Forsythslurp(fd: ref Sys->FD): string 54737da2899SCharles.Forsyth{ 54837da2899SCharles.Forsyth buf := array[2048] of byte; 54937da2899SCharles.Forsyth s := ""; 55037da2899SCharles.Forsyth while((n := sys->read(fd, buf, len buf)) > 0) 55137da2899SCharles.Forsyth s += string buf[0:n]; 55237da2899SCharles.Forsyth return s; 55337da2899SCharles.Forsyth} 55437da2899SCharles.Forsyth 55537da2899SCharles.Forsythvalof(l: list of string, attr: string): string 55637da2899SCharles.Forsyth{ 55737da2899SCharles.Forsyth while(l != nil){ 55837da2899SCharles.Forsyth label := hd l; 55937da2899SCharles.Forsyth l = tl l; 56037da2899SCharles.Forsyth if(label == attr){ 56137da2899SCharles.Forsyth if(l == nil) 56237da2899SCharles.Forsyth return nil; 56337da2899SCharles.Forsyth return hd l; 56437da2899SCharles.Forsyth } 56537da2899SCharles.Forsyth if(l != nil) 56637da2899SCharles.Forsyth l = tl l; 56737da2899SCharles.Forsyth } 56837da2899SCharles.Forsyth return nil; 56937da2899SCharles.Forsyth} 57037da2899SCharles.Forsyth 57137da2899SCharles.ForsythUdphdr.new(): ref Udphdr 57237da2899SCharles.Forsyth{ 57337da2899SCharles.Forsyth return ref Udphdr(noaddr, noaddr, noaddr, 0, 0); 57437da2899SCharles.Forsyth} 57537da2899SCharles.Forsyth 57637da2899SCharles.ForsythUdphdr.unpack(a: array of byte, n: int): ref Udphdr 57737da2899SCharles.Forsyth{ 57837da2899SCharles.Forsyth case n { 57937da2899SCharles.Forsyth Udp4hdrlen => 58037da2899SCharles.Forsyth u := ref Udphdr; 58137da2899SCharles.Forsyth u.raddr = IPaddr.newv4(a[0:]); 58237da2899SCharles.Forsyth u.laddr = IPaddr.newv4(a[IPv4addrlen:]); 58337da2899SCharles.Forsyth u.rport = get2(a, 2*IPv4addrlen); 58437da2899SCharles.Forsyth u.lport = get2(a, 2*IPv4addrlen+2); 58537da2899SCharles.Forsyth u.ifcaddr = u.laddr.copy(); 58637da2899SCharles.Forsyth return u; 58737da2899SCharles.Forsyth OUdphdrlen => 58837da2899SCharles.Forsyth u := ref Udphdr; 58937da2899SCharles.Forsyth u.raddr = IPaddr.newv6(a[0:]); 59037da2899SCharles.Forsyth u.laddr = IPaddr.newv6(a[IPaddrlen:]); 59137da2899SCharles.Forsyth u.rport = get2(a, 2*IPaddrlen); 59237da2899SCharles.Forsyth u.lport = get2(a, 2*IPaddrlen+2); 59337da2899SCharles.Forsyth u.ifcaddr = u.laddr.copy(); 59437da2899SCharles.Forsyth return u; 59537da2899SCharles.Forsyth Udphdrlen => 59637da2899SCharles.Forsyth u := ref Udphdr; 59737da2899SCharles.Forsyth u.raddr = IPaddr.newv6(a[0:]); 59837da2899SCharles.Forsyth u.laddr = IPaddr.newv6(a[IPaddrlen:]); 59937da2899SCharles.Forsyth u.ifcaddr = IPaddr.newv6(a[2*IPaddrlen:]); 60037da2899SCharles.Forsyth u.rport = get2(a, 3*IPaddrlen); 60137da2899SCharles.Forsyth u.lport = get2(a, 3*IPaddrlen+2); 60237da2899SCharles.Forsyth return u; 60337da2899SCharles.Forsyth * => 60437da2899SCharles.Forsyth raise "Udphdr.unpack: bad length"; 60537da2899SCharles.Forsyth } 60637da2899SCharles.Forsyth} 60737da2899SCharles.Forsyth 60837da2899SCharles.ForsythUdphdr.pack(u: self ref Udphdr, a: array of byte, n: int) 60937da2899SCharles.Forsyth{ 61037da2899SCharles.Forsyth case n { 61137da2899SCharles.Forsyth Udp4hdrlen => 61237da2899SCharles.Forsyth a[0:] = u.raddr.v4(); 61337da2899SCharles.Forsyth a[IPv4addrlen:] = u.laddr.v4(); 61437da2899SCharles.Forsyth put2(a, 2*IPv4addrlen, u.rport); 61537da2899SCharles.Forsyth put2(a, 2*IPv4addrlen+2, u.lport); 61637da2899SCharles.Forsyth OUdphdrlen => 61737da2899SCharles.Forsyth a[0:] = u.raddr.v6(); 61837da2899SCharles.Forsyth a[IPaddrlen:] = u.laddr.v6(); 61937da2899SCharles.Forsyth put2(a, 2*IPaddrlen, u.rport); 62037da2899SCharles.Forsyth put2(a, 2*IPaddrlen+2, u.lport); 62137da2899SCharles.Forsyth Udphdrlen => 62237da2899SCharles.Forsyth a[0:] = u.raddr.v6(); 62337da2899SCharles.Forsyth a[IPaddrlen:] = u.laddr.v6(); 62437da2899SCharles.Forsyth a[2*IPaddrlen:] = u.ifcaddr.v6(); 62537da2899SCharles.Forsyth put2(a, 3*IPaddrlen, u.rport); 62637da2899SCharles.Forsyth put2(a, 3*IPaddrlen+2, u.lport); 62737da2899SCharles.Forsyth * => 62837da2899SCharles.Forsyth raise "Udphdr.pack: bad length"; 62937da2899SCharles.Forsyth } 63037da2899SCharles.Forsyth} 63137da2899SCharles.Forsyth 63237da2899SCharles.Forsythget2(a: array of byte, o: int): int 63337da2899SCharles.Forsyth{ 63437da2899SCharles.Forsyth return (int a[o] << 8) | int a[o+1]; 63537da2899SCharles.Forsyth} 63637da2899SCharles.Forsyth 63737da2899SCharles.Forsythput2(a: array of byte, o: int, val: int): int 63837da2899SCharles.Forsyth{ 63937da2899SCharles.Forsyth a[o] = byte (val>>8); 64037da2899SCharles.Forsyth a[o+1] = byte val; 64137da2899SCharles.Forsyth return o+2; 64237da2899SCharles.Forsyth} 64337da2899SCharles.Forsyth 64437da2899SCharles.Forsythget4(a: array of byte, o: int): int 64537da2899SCharles.Forsyth{ 64637da2899SCharles.Forsyth return (((((int a[o] << 8)| int a[o+1]) << 8) | int a[o+2]) << 8) | int a[o+3]; 64737da2899SCharles.Forsyth} 64837da2899SCharles.Forsyth 64937da2899SCharles.Forsythput4(a: array of byte, o: int, val: int): int 65037da2899SCharles.Forsyth{ 65137da2899SCharles.Forsyth a[o] = byte (val>>24); 65237da2899SCharles.Forsyth a[o+1] = byte (val>>16); 65337da2899SCharles.Forsyth a[o+2] = byte (val>>8); 65437da2899SCharles.Forsyth a[o+3] = byte val; 65537da2899SCharles.Forsyth return o+4; 65637da2899SCharles.Forsyth} 657