+ self.name=w[1]
+ self.properties={}
+ self.children={}
+ def indent(self,w,t):
+ w.write(" "[:t])
+ def prop_out(self,n):
+ return self.allow_properties[n](n,str(self.properties[n]))
+ def output_props(self,w,ind):
+ for i in self.properties.keys():
+ if self.allow_properties[i]:
+ self.indent(w,ind)
+ w.write("%s"%self.prop_out(i))
+ def output_data(self,w,ind,np):
+ self.indent(w,ind)
+ w.write("%s {\n"%(self.name))
+ self.output_props(w,ind+2)
+ if self.depth==1: w.write("\n");
+ for c in self.children.values():
+ c.output_data(w,ind+2,np+self.name+"/")
+ self.indent(w,ind)
+ w.write("};\n")
+
+class vpnlevel(level):
+ "VPN level in the configuration hierarchy"
+ depth=1
+ leaf=0
+ type="vpn"
+ allow_properties=global_properties.copy()
+ require_properties={
+ 'contact':"VPN admin contact address"
+ }
+ def __init__(self,w):
+ level.__init__(self,w)
+ def output_vpnflat(self,w,ind,h):
+ "Output flattened list of site names for this VPN"
+ self.indent(w,ind)
+ w.write("%s {\n"%(self.name))
+ for i in self.children.keys():
+ self.children[i].output_vpnflat(w,ind+2,
+ h+"/"+self.name+"/"+i)
+ w.write("\n")
+ self.indent(w,ind+2)
+ w.write("all-sites %s;\n"%
+ string.join(self.children.keys(),','))
+ self.indent(w,ind)
+ w.write("};\n")
+
+class locationlevel(level):
+ "Location level in the configuration hierarchy"
+ depth=2
+ leaf=0
+ type="location"
+ allow_properties=global_properties.copy()
+ require_properties={
+ 'contact':"Location admin contact address",
+ }
+ def __init__(self,w):
+ level.__init__(self,w)
+ self.group=w[2]
+ def output_vpnflat(self,w,ind,h):
+ self.indent(w,ind)
+ # The "h=h,self=self" abomination below exists because
+ # Python didn't support nested_scopes until version 2.1
+ w.write("%s %s;\n"%(self.name,string.join(
+ map(lambda x,h=h,self=self:
+ h+"/"+x,self.children.keys()),',')))
+
+class sitelevel(level):
+ "Site level (i.e. a leafnode) in the configuration hierarchy"
+ depth=3
+ leaf=1
+ type="site"
+ allow_properties=global_properties.copy()
+ allow_properties.update({
+ 'address':sp,
+ 'networks':None,
+ 'peer':None,
+ 'pubkey':(lambda n,v:"key %s;\n"%v),
+ 'mobile':sp,
+ })
+ require_properties={
+ 'dh':"Diffie-Hellman group",
+ 'contact':"Site admin contact address",
+ 'networks':"Networks claimed by the site",
+ 'hash':"hash function",
+ 'peer':"Gateway address of the site",
+ 'pubkey':"RSA public key of the site",
+ }
+ def __init__(self,w):
+ level.__init__(self,w)
+ def output_data(self,w,ind,np):
+ self.indent(w,ind)
+ w.write("%s {\n"%(self.name))
+ self.indent(w,ind+2)
+ w.write("name \"%s\";\n"%(np+self.name))
+ self.output_props(w,ind+2)
+ self.indent(w,ind+2)
+ w.write("link netlink {\n");
+ self.indent(w,ind+4)
+ w.write("routes %s;\n"%str(self.properties["networks"]))
+ self.indent(w,ind+4)
+ w.write("ptp-address %s;\n"%str(self.properties["peer"]))
+ self.indent(w,ind+2)
+ w.write("};\n")
+ self.indent(w,ind)
+ w.write("};\n")
+
+# Levels in the configuration file
+# (depth,properties)
+levels={'vpn':vpnlevel, 'location':locationlevel, 'site':sitelevel}
+
+# Reserved vpn/location/site names
+reserved={'all-sites':None}
+reserved.update(keywords)
+reserved.update(levels)