diff options
Diffstat (limited to 'appl/lib/ipattr.b')
| -rw-r--r-- | appl/lib/ipattr.b | 217 |
1 files changed, 217 insertions, 0 deletions
diff --git a/appl/lib/ipattr.b b/appl/lib/ipattr.b new file mode 100644 index 00000000..453545de --- /dev/null +++ b/appl/lib/ipattr.b @@ -0,0 +1,217 @@ +implement IPattr; + +include "sys.m"; + +include "bufio.m"; +include "attrdb.m"; + attrdb: Attrdb; + Db, Dbentry, Tuples: import attrdb; + +include "ip.m"; + ip: IP; + IPaddr: import ip; + +include "ipattr.m"; + +init(m: Attrdb, ipa: IP) +{ +# sys = load Sys Sys->PATH; + attrdb = m; + ip = ipa; +} + +dbattr(s: string): string +{ + digit := 0; + dot := 0; + alpha := 0; + hex := 0; + colon := 0; + for(i := 0; i < len s; i++){ + case c := s[i] { + '0' to '9' => + digit = 1; + 'a' to 'f' or 'A' to 'F' => + hex = 1; + '.' => + dot = 1; + ':' => + colon = 1; + * => + if(c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z' || c == '-' || c == '&') + alpha = 1; + } + } + if(alpha){ + if(dot) + return "dom"; + return "sys"; + } + if(colon) + return "ip"; + if(dot){ + if(!hex) + return "ip"; + return "dom"; + } + return "sys"; +} + +findnetattr(ndb: ref Db, attr: string, val: string, rattr: string): (string, string) +{ + (matches, err) := findnetattrs(ndb, attr, val, rattr::nil); + if(matches == nil) + return (nil, err); + (nil, nattr) := hd matches; + na := hd nattr; +#{sys := load Sys Sys->PATH; sys->print("%q=%q->%q ::", attr, val, rattr);for(al:=na.pairs; al != nil; al = tl al)sys->print(" %q=%q", (hd al).attr, (hd al).val); sys->print("\n");} + if(na.name == rattr && na.pairs != nil) + return ((hd na.pairs).val, nil); + return (nil, nil); +} + +reverse(l: list of string): list of string +{ + rl: list of string; + for(; l != nil; l = tl l) + rl = hd l :: rl; + return rl; +} + +valueof(l: list of ref Netattr, attr: string): list of string +{ + rl: list of string; + for(; l != nil; l = tl l){ + na := hd l; + if(na.name == attr){ + for(p := na.pairs; p != nil; p = tl p) + rl = (hd p).val :: rl; + } + } + return reverse(rl); +} + +netvalueof(l: list of ref Netattr, attr: string, a: IP->IPaddr): list of string +{ + rl: list of string; + for(; l != nil; l = tl l){ + na := hd l; + if(na.name == attr && a.mask(na.mask).eq(na.net)){ + for(p := na.pairs; p != nil; p = tl p) + rl = (hd p).val :: rl; + } + } + return reverse(rl); +} + +findnetattrs(ndb: ref Db, attr: string, val: string, rattrs: list of string): (list of (IPaddr, list of ref Netattr), string) +{ + rl: list of (IPaddr, list of ref Netattr); + if(ndb == nil) + return (nil, "no database"); + (e, ptr) := ndb.findbyattr(nil, attr, val, "ip"); + if(e == nil){ + if(attr != "ip") + return (nil, "ip attribute not found"); + # look for attributes associated with networks that include `a' + (ok, a) := IPaddr.parse(val); + if(ok < 0) + return (nil, "invalid ip address in db"); + netattrs := mkattrlist(rattrs); + netattributes(ndb, a, netattrs); + rl = (a, netattrs) :: nil; + }else{ + netattrs: list of ref Netattr; + for(matches := e.findbyattr(attr, val, "ip"); matches != nil; matches = tl matches){ + for((nil, allip) := hd matches; allip != nil; allip = tl allip){ + ipa := (hd allip).val; + (ok, a) := IPaddr.parse(ipa); + if(ok < 0) + return (nil, "invalid ip address in db"); + netattrs = mkattrlist(rattrs); + pptr := ptr; + pe := e; + for(;;){ + attribute(pe, a, ip->allbits, netattrs, 1); + (pe, pptr) = ndb.findpair(pptr, attr, val); + if(pe == nil) + break; + } + netattributes(ndb, a, netattrs); + rl = (a, netattrs) :: rl; + } + } + } + results: list of (IPaddr, list of ref Netattr); + for(; rl != nil; rl = tl rl) + results = hd rl :: results; + return (results, nil); +} + +netattributes(ndb: ref Db, a: IPaddr, nas: list of ref Netattr): string +{ + e: ref Dbentry; + ptr: ref Attrdb->Dbptr; + for(;;){ + (e, ptr) = ndb.find(ptr, "ipnet"); + if(e == nil) + break; + ipaddr := e.findfirst("ip"); + if(ipaddr == nil) + continue; + (ok, netip) := IPaddr.parse(ipaddr); + if(ok < 0) + return "bad ip address in db"; + netmask: IPaddr; + mask := e.findfirst("ipmask"); + if(mask == nil){ + if(!netip.isv4()) + continue; + netmask = netip.classmask(); + }else{ + (ok, netmask) = IPaddr.parsemask(mask); + if(ok < 0) + return "bad ipmask in db"; + } + if(a.mask(netmask).eq(netip)) + attribute(e, netip, netmask, nas, 0); + } + return nil; +} + +attribute(e: ref Dbentry, netip: IPaddr, netmask: IPaddr, nas: list of ref Netattr, ishost: int) +{ + for(; nas != nil; nas = tl nas){ + na := hd nas; + if(na.pairs != nil){ + if(!na.mask.mask(netmask).eq(na.mask)) + continue; + # new one is at least as specific + } + matches := e.find(na.name); + if(matches == nil){ + if(na.name != "ipmask" || ishost) + continue; + matches = (nil, ref Attrdb->Attr("ipmask", netmask.masktext(), 0)::nil) :: nil; + } + na.net = netip; + na.mask = netmask; + rl: list of ref Attrdb->Attr; + for(; matches != nil; matches = tl matches){ + (nil, al) := hd matches; + for(; al != nil; al = tl al) + rl = hd al :: rl; + } + na.pairs = nil; + for(; rl != nil; rl = tl rl) + na.pairs = hd rl :: na.pairs; + } +} + +mkattrlist(rattrs: list of string): list of ref Netattr +{ + netattrs: list of ref Netattr; + for(; rattrs != nil; rattrs = tl rattrs) + netattrs = ref Netattr(hd rattrs, nil, ip->noaddr, ip->noaddr) :: netattrs; + return netattrs; +} |
