X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ian/git?p=secnet.git;a=blobdiff_plain;f=make-secnet-sites;h=c49467a19f687c5f1fb78dfb15ebe44a5790c9ae;hp=8024c16d000b99ade42a7490b1b633d205f75820;hb=26f727b913e16936c8f319fde9d7e06b677345f6;hpb=3b83c93292fbf6c4e859ce513bdf54ad90733f96 diff --git a/make-secnet-sites b/make-secnet-sites index 8024c16..c49467a 100755 --- a/make-secnet-sites +++ b/make-secnet-sites @@ -54,13 +54,14 @@ import time import sys import os import getopt +import re # The ipaddr library is installed as part of secnet sys.path.append("/usr/local/share/secnet") sys.path.append("/usr/share/secnet") import ipaddr -VERSION="0.1.16" +VERSION="0.1.18" # Classes describing possible datatypes in the configuration file @@ -108,6 +109,18 @@ class email: def __str__(self): return '<%s>'%(self.addr) +class boolean: + "A boolean" + def __init__(self,w): + if re.match('[TtYy1]',w[1]): + self.b=True + elif re.match('[FfNn0]',w[1]): + self.b=False + else: + complain("invalid boolean value"); + def __str__(self): + return ['False','True'][self.b] + class num: "A decimal number" def __init__(self,w): @@ -148,7 +161,8 @@ keywords={ 'networks':(networks,"Claimed networks"), 'pubkey':(rsakey,"RSA public site key"), 'peer':(single_ipaddr,"Tunnel peer IP address"), - 'address':(address,"External contact address and port") + 'address':(address,"External contact address and port"), + 'mobile':(boolean,"Site is mobile"), } def sp(name,value): @@ -165,7 +179,7 @@ global_properties={ 'setup-retries':sp, 'wait-time':sp, 'renegotiate-time':sp, - 'restrict-nets':(lambda name,value:"# restrict-nets %s\n"%value) + 'restrict-nets':(lambda name,value:"# restrict-nets %s\n"%value), } class level: @@ -252,16 +266,17 @@ class sitelevel(level): 'address':sp, 'networks':None, 'peer':None, - 'pubkey':(lambda n,v:"key %s;\n"%v) + 'pubkey':(lambda n,v:"key %s;\n"%v), + 'address':None, + 'mobile':sp, }) require_properties={ 'dh':"Diffie-Hellman group", 'contact':"Site admin contact address", - 'address':"Site external access address", 'networks':"Networks claimed by the site", 'hash':"hash function", 'peer':"Gateway address of the site", - 'pubkey':"RSA public key of the site" + 'pubkey':"RSA public key of the site", } def __init__(self,w): level.__init__(self,w) @@ -305,6 +320,7 @@ def moan(msg): root=level(['root','root']) # All vpns are children of this node obstack=[root] allow_defs=0 # Level above which new definitions are permitted +prefix='' def set_property(obj,w): "Set a property on a configuration node" @@ -314,7 +330,7 @@ def set_property(obj,w): else: obj.properties[w[0]]=keywords[w[0]][0](w) -def pline(i): +def pline(i,allow_include=False): "Process a configuration file line" global allow_defs, obstack, root w=string.split(i) @@ -325,6 +341,16 @@ def pline(i): allow_defs=sitelevel.depth obstack=[root] return + if keyword=='include': + if not allow_include: + complain("include not permitted here") + return + if len(w) != 2: + complain("include requires one argument") + return + newfile=os.path.join(os.path.dirname(file),w[1]) + pfilepath(newfile,allow_include=allow_include) + return if levels.has_key(keyword): # We may go up any number of levels, but only down by one newdepth=levels[keyword].depth @@ -364,7 +390,14 @@ def pline(i): complain("unknown keyword '%s'"%(keyword)) -def pfile(name,lines): +def pfilepath(pathname,allow_include=False): + f=open(pathname) + lines=f.readlines() + pfile(pathname,lines,allow_include=allow_include) + f.close() + return lines + +def pfile(name,lines,allow_include=False): "Process a file" global file,line file=name @@ -373,7 +406,7 @@ def pfile(name,lines): line=line+1 if (i[0]=='#'): continue if (i[len(i)-1]=='\n'): i=i[:len(i)-1] # strip trailing LF - pline(i) + pline(i,allow_include=allow_include) def outputsites(w): "Output include file for secnet configuration" @@ -383,20 +416,21 @@ def outputsites(w): w.write("# Command line: %s\n\n"%string.join(sys.argv)) # Raw VPN data section of file - w.write("vpn-data {\n") + w.write(prefix+"vpn-data {\n") for i in root.children.values(): i.output_data(w,2,"") w.write("};\n") # Per-VPN flattened lists - w.write("vpn {\n") + w.write(prefix+"vpn {\n") for i in root.children.values(): - i.output_vpnflat(w,2,"vpn-data") + i.output_vpnflat(w,2,prefix+"vpn-data") w.write("};\n") # Flattened list of sites - w.write("all-sites %s;\n"%string.join(map(lambda x:"vpn/%s/all-sites"% - x,root.children.keys()),",")) + w.write(prefix+"all-sites %s;\n"%string.join( + map(lambda x:"%svpn/%s/all-sites"%(prefix,x), + root.children.keys()),",")) # Are we being invoked from userv? service=0 @@ -435,19 +469,17 @@ else: if not ok: print "caller not in group %s"%group sys.exit(1) - f=open(header) - headerinput=f.readlines() - f.close() - pfile(header,headerinput) + headerinput=pfilepath(header,allow_include=True) userinput=sys.stdin.readlines() pfile("user input",userinput) else: + if sys.argv[1]=='-P': + prefix=sys.argv[2] + sys.argv[1:3]=[] if len(sys.argv)>3: print "Too many arguments" sys.exit(1) - f=open(sys.argv[1]) - pfile(sys.argv[1],f.readlines()) - f.close() + pfilepath(sys.argv[1],allow_include=True) of=sys.stdout if len(sys.argv)>2: of=open(sys.argv[2],'w')