ref: babf901b4a508c3ec5d1f89655f10377bbdf9637
dir: /appl/lib/ipattr.b/
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;
}