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;}
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;
}