diff --git a/.gitignore b/.gitignore index edd58e5..26f2096 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,10 @@ *.crt *.certbot +*.build +*.egg-info +*.__pycache__ + # Kompilierte Dateien __pycache__ *.py[cod] diff --git a/README.md b/README.md index 68c677e..e51af7f 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ # opnsense-helper -assign lan interfaces, create vlans, vlan-interfaces and setup dhcp in a single script. +assign lan interfaces, create vlans, vlan-interfaces and setup dhcp in a single script using the opnsense backend. ## install ## pip ```bash @@ -10,52 +10,78 @@ pip install opnsense-helper - rn i try to find out how to reconfigure the vlans using the backend, but this is on todo list ```python -from opnsense_helper.classes import Opnsense_Helper - -filepath = '/home/ji/confignew.xml' +ffrom opnsense_helper.classes import Opnsense_Helper output="./config.xml" conf_path="/conf/config.xml" +host= "192.168.1.103" vlans=[ - {'if': 'vtnet1', 'tag': '1', 'pcp': '0', 'proto': None, 'descr': 'vlan1', 'vlanif': 'vlan0.1'}, - {'if': 'vtnet1', 'tag': '2', 'pcp': '0', 'proto': None, 'descr': 'vlan2', 'vlanif': 'vlan0.2'} - ] -dhcp={ -"opt2": {'enable': '1', 'ddnsdomainalgorithm': 'hmac-md', "range":{'from': '200.0.3.10', '_to': '200.0.3.100'}}, -"opt3": {'enable': '1', 'ddnsdomainalgorithm': 'hmac-md', "range":{'from': '200.0.4.10', '_to': '200.0.4.100'}} -} -interfaces={ -"opt1": {'descr': 'router', 'enable': '1', 'ipaddr': None, 'subnet': None, 'type': None, 'virtual': None, 'spoofmac': '00:00:00:00:02:01',"interface":"vtnet1"}, -"opt2": {'descr': 'vlan1', 'enable': '1', 'ipaddr': '200.0.3.1', 'subnet': '24', 'type': None, 'virtual': None, 'spoofmac': '00:00:00:00:00:01',"interface":"vlan0.1"}, -"opt3": {'descr': 'vlan2', 'enable': '1', 'ipaddr': '200.0.4.1', 'subnet': '24', 'type': None, 'virtual': None, 'spoofmac': '00:00:00:00:00:02', "interface":"vlan0.2"} -} -ssh_auth={ +{"id":"vlan1",'parent': 'vtnet1', 'tag': '1', 'pcp': '0', 'proto': None, 'descr': 'vlan1', 'vlanif': 'vlan0.1'}, +{"id":"vlan2",'parent': 'vtnet1', 'tag': '2', 'pcp': '0', 'proto': None, 'descr': 'vlan2', 'vlanif': 'vlan0.2'}, +{"id":"vlan3",'parent': 'vtnet1', 'tag': '3', 'pcp': '0', 'proto': None, 'descr': 'vlan3', 'vlanif': 'vlan0.3'} + +] +dhcp=[ +{"id":"opt2",'enable': '1', 'ddnsdomainalgorithm': 'hmac-md', "range":{'from': '200.0.3.10', '_to': '200.0.3.100'}}, +{"id":"opt3",'enable': '1', 'ddnsdomainalgorithm': 'hmac-md', "range":{'from': '200.0.4.10', '_to': '200.0.4.100'}} +] +interfaces=[ +{"id":"opt1",'descr': 'router', 'enable': '1', 'ipaddr': None, 'subnet': None, 'type': None, 'virtual': None, 'spoofmac': '00:00:00:00:02:01',"interface":"vtnet1"}, +{"id":"opt2",'descr': 'vlan1', 'enable': '1', 'ipaddr': '200.0.3.1', 'subnet': '24', 'type': None, 'virtual': None, 'spoofmac': '00:00:00:00:00:01',"interface":"vlan0.1"}, +{"id":"opt3",'descr': 'vlan2', 'enable': '1', 'ipaddr': '200.0.4.1', 'subnet': '24', 'type': None, 'virtual': None, 'spoofmac': '00:00:00:00:00:02', "interface":"vlan0.2"}, +{"id":"opt4",'descr': 'vlan3', 'enable': '1', 'ipaddr': '200.0.5.1', 'subnet': '24', 'type': None, 'virtual': None, 'spoofmac': '00:00:00:00:00:03', "interface":"vlan0.3"} + +] +auth={ "user":"root", "passw":"opnsense", } -api_auth={ -# ONLY NEED WHEN YOU USE THE API -"api_key" :'ejl4fIU9yfNk+gaQmPk/rqIa15f1yX1snIKgcIEl2QNoJwhbekraWIE0ANRYceh9hey5IFGzlf3da4yJ', -"api_secret" : '5JVVGoatPbaAA+FozLDQY92/T6sRlmKD1+aRNl/YI8KA9/0TNiTDboLveqvd9FU8wFeDo3D3DY5wrUtF', -"ssl": True, -"verify": False -} -host= "192.168.1.103" -def test(): - helper=Opnsense_Helper(host=host,ssh_auth=ssh_auth,api_auth=api_auth,filepath=output, verbose=False) - helper.add_vlans(vlans) - #helper.set_vlans(vlans) - helper.get_conf(conf_path) - helper.initialize() - helper.add_Items("interfaces",interfaces) - helper.add_Items("dhcpd",dhcp) - helper.save(output) - helper.put_file(output,conf_path) - helper.close_con() - -if __name__ == "__main__": - test() +helper=Opnsense_Helper(host=host,ssh_auth=auth,filepath=output, verbose=False) +#helper.set_vlans(vlans) +helper.get_conf(conf_path) +helper.initialize() +helper.add_Items("interfaces",interfaces) +helper.add_Items("dhcpd",dhcp) +helper.add_Items("vlans",vlans) +helper.save(output) +helper.put_file(output,conf_path) +helper.close_con() ``` +### Frontend Api +```python +def using_api(): + vlans_api=[ + {'if': 'vtnet1', 'tag': '1', 'pcp': '0', 'proto': None, 'descr': 'vlan1', 'vlanif': 'vlan0.1'}, + {'if': 'vtnet1', 'tag': '2', 'pcp': '0', 'proto': None, 'descr': 'vlan2', 'vlanif': 'vlan0.2'} + ] + api_auth={ + "api_key" :'ejl4fIU9yfNk+gaQmPk/rqIa15f1yX1snIKgcIEl2QNoJwhbekraWIE0ANRYceh9hey5IFGzlf3da4yJ', + "api_secret":'5JVVGoatPbaAA+FozLDQY92/T6sRlmKD1+aRNl/YI8KA9/0TNiTDboLveqvd9FU8wFeDo3D3DY5wrUtF', + "ssl": True, + "verify": False + } + helper=Opnsense_Helper(host=host,api_auth=api_auth,filepath=output, verbose=False) + helper.vlans_api(vlans_api,"add") +``` +### Variables +#### Opnsense_Helper +(host=host,ssh_auth=auth,filepath=output, verbose=False) +| var | type | description | +| --- | --- | --- | +| host| str | ip or hostname | +| auth | dict {user: str, passw: str} | SSH authentication dictionary | + + + +#### Module Args +| var | type | elements | +| --- | --- | --- | +| vlans | list[dict] | {id: str, parent: str, tag: int, pcp: str, proto: str } | None, descr: str, vlanif: str} | +| interfaces | list[dict] | {id: str, descr: str, enable: int, ipaddr: str, subnet: str, type: str, virtual: bool, spoofmac: str, interface: str} | +| dhcp | list[dict] | {id: str, enable: str, ddnsdomainalgorithm: str, range: {from: str, _to: str}} | + + + ### contribute - clone, or fork `git@github.com:the-pod-shop/opnsense-helper.git` - build when made changes diff --git a/examples/add_vlans.py b/examples/add_vlans.py deleted file mode 100644 index 2ef696a..0000000 --- a/examples/add_vlans.py +++ /dev/null @@ -1,45 +0,0 @@ -from opnsense_helper.classes import Opnsense_Helper - -filepath = '/home/ji/confignew.xml' -output="./config.xml" -conf_path="/conf/config.xml" -vlans=[ - {'if': 'vtnet1', 'tag': '1', 'pcp': '0', 'proto': None, 'descr': 'vlan1', 'vlanif': 'vlan0.1'}, - {'if': 'vtnet1', 'tag': '2', 'pcp': '0', 'proto': None, 'descr': 'vlan2', 'vlanif': 'vlan0.2'} - ] -dhcp={ -"opt2": {'enable': '1', 'ddnsdomainalgorithm': 'hmac-md', "range":{'from': '200.0.3.10', '_to': '200.0.3.100'}}, -"opt3": {'enable': '1', 'ddnsdomainalgorithm': 'hmac-md', "range":{'from': '200.0.4.10', '_to': '200.0.4.100'}} -} -interfaces={ -"opt1": {'descr': 'router', 'enable': '1', 'ipaddr': None, 'subnet': None, 'type': None, 'virtual': None, 'spoofmac': '00:00:00:00:02:01',"interface":"vtnet1"}, -"opt2": {'descr': 'vlan1', 'enable': '1', 'ipaddr': '200.0.3.1', 'subnet': '24', 'type': None, 'virtual': None, 'spoofmac': '00:00:00:00:00:01',"interface":"vlan0.1"}, -"opt3": {'descr': 'vlan2', 'enable': '1', 'ipaddr': '200.0.4.1', 'subnet': '24', 'type': None, 'virtual': None, 'spoofmac': '00:00:00:00:00:02', "interface":"vlan0.2"} -} - -ssh_auth={ -"user":"root", -"passw":"opnsense", -} -api_auth={ -# ONLY NEED WHEN YOU USE THE API -"api_key" :'ejl4fIU9yfNk+gaQmPk/rqIa15f1yX1snIKgcIEl2QNoJwhbekraWIE0ANRYceh9hey5IFGzlf3da4yJ', -"api_secret" : '5JVVGoatPbaAA+FozLDQY92/T6sRlmKD1+aRNl/YI8KA9/0TNiTDboLveqvd9FU8wFeDo3D3DY5wrUtF', -"ssl": True, -"verify": False -} -host= "192.168.1.103" -def test(): - helper=Opnsense_Helper(host=host,ssh_auth=ssh_auth,api_auth=api_auth,filepath=output, verbose=False) - helper.add_vlans(vlans) - #helper.set_vlans(vlans) - helper.get_conf(conf_path) - helper.initialize() - helper.add_Items("interfaces",interfaces) - helper.add_Items("dhcpd",dhcp) - helper.save(output) - helper.put_file(output,conf_path) - helper.close_con() - -if __name__ == "__main__": - test() \ No newline at end of file diff --git a/python/README.md b/python/README.md index 68c677e..e51af7f 100644 --- a/python/README.md +++ b/python/README.md @@ -1,5 +1,5 @@ # opnsense-helper -assign lan interfaces, create vlans, vlan-interfaces and setup dhcp in a single script. +assign lan interfaces, create vlans, vlan-interfaces and setup dhcp in a single script using the opnsense backend. ## install ## pip ```bash @@ -10,52 +10,78 @@ pip install opnsense-helper - rn i try to find out how to reconfigure the vlans using the backend, but this is on todo list ```python -from opnsense_helper.classes import Opnsense_Helper - -filepath = '/home/ji/confignew.xml' +ffrom opnsense_helper.classes import Opnsense_Helper output="./config.xml" conf_path="/conf/config.xml" +host= "192.168.1.103" vlans=[ - {'if': 'vtnet1', 'tag': '1', 'pcp': '0', 'proto': None, 'descr': 'vlan1', 'vlanif': 'vlan0.1'}, - {'if': 'vtnet1', 'tag': '2', 'pcp': '0', 'proto': None, 'descr': 'vlan2', 'vlanif': 'vlan0.2'} - ] -dhcp={ -"opt2": {'enable': '1', 'ddnsdomainalgorithm': 'hmac-md', "range":{'from': '200.0.3.10', '_to': '200.0.3.100'}}, -"opt3": {'enable': '1', 'ddnsdomainalgorithm': 'hmac-md', "range":{'from': '200.0.4.10', '_to': '200.0.4.100'}} -} -interfaces={ -"opt1": {'descr': 'router', 'enable': '1', 'ipaddr': None, 'subnet': None, 'type': None, 'virtual': None, 'spoofmac': '00:00:00:00:02:01',"interface":"vtnet1"}, -"opt2": {'descr': 'vlan1', 'enable': '1', 'ipaddr': '200.0.3.1', 'subnet': '24', 'type': None, 'virtual': None, 'spoofmac': '00:00:00:00:00:01',"interface":"vlan0.1"}, -"opt3": {'descr': 'vlan2', 'enable': '1', 'ipaddr': '200.0.4.1', 'subnet': '24', 'type': None, 'virtual': None, 'spoofmac': '00:00:00:00:00:02', "interface":"vlan0.2"} -} -ssh_auth={ +{"id":"vlan1",'parent': 'vtnet1', 'tag': '1', 'pcp': '0', 'proto': None, 'descr': 'vlan1', 'vlanif': 'vlan0.1'}, +{"id":"vlan2",'parent': 'vtnet1', 'tag': '2', 'pcp': '0', 'proto': None, 'descr': 'vlan2', 'vlanif': 'vlan0.2'}, +{"id":"vlan3",'parent': 'vtnet1', 'tag': '3', 'pcp': '0', 'proto': None, 'descr': 'vlan3', 'vlanif': 'vlan0.3'} + +] +dhcp=[ +{"id":"opt2",'enable': '1', 'ddnsdomainalgorithm': 'hmac-md', "range":{'from': '200.0.3.10', '_to': '200.0.3.100'}}, +{"id":"opt3",'enable': '1', 'ddnsdomainalgorithm': 'hmac-md', "range":{'from': '200.0.4.10', '_to': '200.0.4.100'}} +] +interfaces=[ +{"id":"opt1",'descr': 'router', 'enable': '1', 'ipaddr': None, 'subnet': None, 'type': None, 'virtual': None, 'spoofmac': '00:00:00:00:02:01',"interface":"vtnet1"}, +{"id":"opt2",'descr': 'vlan1', 'enable': '1', 'ipaddr': '200.0.3.1', 'subnet': '24', 'type': None, 'virtual': None, 'spoofmac': '00:00:00:00:00:01',"interface":"vlan0.1"}, +{"id":"opt3",'descr': 'vlan2', 'enable': '1', 'ipaddr': '200.0.4.1', 'subnet': '24', 'type': None, 'virtual': None, 'spoofmac': '00:00:00:00:00:02', "interface":"vlan0.2"}, +{"id":"opt4",'descr': 'vlan3', 'enable': '1', 'ipaddr': '200.0.5.1', 'subnet': '24', 'type': None, 'virtual': None, 'spoofmac': '00:00:00:00:00:03', "interface":"vlan0.3"} + +] +auth={ "user":"root", "passw":"opnsense", } -api_auth={ -# ONLY NEED WHEN YOU USE THE API -"api_key" :'ejl4fIU9yfNk+gaQmPk/rqIa15f1yX1snIKgcIEl2QNoJwhbekraWIE0ANRYceh9hey5IFGzlf3da4yJ', -"api_secret" : '5JVVGoatPbaAA+FozLDQY92/T6sRlmKD1+aRNl/YI8KA9/0TNiTDboLveqvd9FU8wFeDo3D3DY5wrUtF', -"ssl": True, -"verify": False -} -host= "192.168.1.103" -def test(): - helper=Opnsense_Helper(host=host,ssh_auth=ssh_auth,api_auth=api_auth,filepath=output, verbose=False) - helper.add_vlans(vlans) - #helper.set_vlans(vlans) - helper.get_conf(conf_path) - helper.initialize() - helper.add_Items("interfaces",interfaces) - helper.add_Items("dhcpd",dhcp) - helper.save(output) - helper.put_file(output,conf_path) - helper.close_con() - -if __name__ == "__main__": - test() +helper=Opnsense_Helper(host=host,ssh_auth=auth,filepath=output, verbose=False) +#helper.set_vlans(vlans) +helper.get_conf(conf_path) +helper.initialize() +helper.add_Items("interfaces",interfaces) +helper.add_Items("dhcpd",dhcp) +helper.add_Items("vlans",vlans) +helper.save(output) +helper.put_file(output,conf_path) +helper.close_con() ``` +### Frontend Api +```python +def using_api(): + vlans_api=[ + {'if': 'vtnet1', 'tag': '1', 'pcp': '0', 'proto': None, 'descr': 'vlan1', 'vlanif': 'vlan0.1'}, + {'if': 'vtnet1', 'tag': '2', 'pcp': '0', 'proto': None, 'descr': 'vlan2', 'vlanif': 'vlan0.2'} + ] + api_auth={ + "api_key" :'ejl4fIU9yfNk+gaQmPk/rqIa15f1yX1snIKgcIEl2QNoJwhbekraWIE0ANRYceh9hey5IFGzlf3da4yJ', + "api_secret":'5JVVGoatPbaAA+FozLDQY92/T6sRlmKD1+aRNl/YI8KA9/0TNiTDboLveqvd9FU8wFeDo3D3DY5wrUtF', + "ssl": True, + "verify": False + } + helper=Opnsense_Helper(host=host,api_auth=api_auth,filepath=output, verbose=False) + helper.vlans_api(vlans_api,"add") +``` +### Variables +#### Opnsense_Helper +(host=host,ssh_auth=auth,filepath=output, verbose=False) +| var | type | description | +| --- | --- | --- | +| host| str | ip or hostname | +| auth | dict {user: str, passw: str} | SSH authentication dictionary | + + + +#### Module Args +| var | type | elements | +| --- | --- | --- | +| vlans | list[dict] | {id: str, parent: str, tag: int, pcp: str, proto: str } | None, descr: str, vlanif: str} | +| interfaces | list[dict] | {id: str, descr: str, enable: int, ipaddr: str, subnet: str, type: str, virtual: bool, spoofmac: str, interface: str} | +| dhcp | list[dict] | {id: str, enable: str, ddnsdomainalgorithm: str, range: {from: str, _to: str}} | + + + ### contribute - clone, or fork `git@github.com:the-pod-shop/opnsense-helper.git` - build when made changes diff --git a/python/build.sh b/python/build.sh index df332fe..5960819 100644 --- a/python/build.sh +++ b/python/build.sh @@ -1,4 +1,5 @@ #!/bin/sh python setup.py bdist_wheel pip install --upgrade . -pip install --upgrade build --force \ No newline at end of file +pip install --upgrade build --force +python /home/ji/Dokumente/podshop-org/opnsense-helper/python/opnsense_helper/examples/add_vlans.py \ No newline at end of file diff --git a/python/build/lib/opnsense_helper/classes.py b/python/build/lib/opnsense_helper/classes.py index 8cff2cd..4c1e16f 100644 --- a/python/build/lib/opnsense_helper/classes.py +++ b/python/build/lib/opnsense_helper/classes.py @@ -3,9 +3,10 @@ import xml.etree.ElementTree as ET import logging -from opnsense_helper.utils import parseChild, update_xml_file, get_element, api_get, api_post, aliases +from opnsense_helper.utils import parseChild, update_xml_file, aliases, reconfigure_vlans +from opnsense_helper.frontend_utils import api_get,api_post class Interface: - def __init__(self, name, parent): + def __init__(self, parent): self.descr = parseChild(parent, "descr") self.enable = parseChild(parent, "enable") self.ipaddr = parseChild(parent, "ipaddr") @@ -16,7 +17,7 @@ def __init__(self, name, parent): self.attr={} class Vlan: - def __init__(self,name, parent): + def __init__(self,parent): self.parentinterface =parseChild(parent, "if") self.tag = parseChild(parent,"tag") self.pcp = parseChild(parent,"pcp") @@ -26,14 +27,18 @@ def __init__(self,name, parent): self.attr={} class Dhcpd: - def __init__(self, name, parent): + def __init__(self, parent,tag): self.enable = parseChild(parent, "enable") self.ddnsdomainalgorithm = parseChild(parent, "ddnsdomainalgorithm") - self.range={ - "_from":"", - "_to":"" - } self.attr={} + self._range={ + "_from": parent.find("range/from"), + "_to":parent.find("range/to") + } + if self._range["_from"] is not None: + self._range["_from"]=self._range["_from"].text + self._range["_to"]=self._range["_to"].text + class Opnsense_Helper(): def __init__(self, host=None, ssh_auth=None, api_auth=None, filepath="./config.xml", verbose=False): if(verbose): @@ -43,13 +48,15 @@ def __init__(self, host=None, ssh_auth=None, api_auth=None, filepath="./config.x "dhcpd":{}, "interfaces":{} } - self.filepath= filepath - self.ssh = paramiko.SSHClient() - self.ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) - self.ssh.connect(host, username=ssh_auth["user"], password=ssh_auth["passw"]) - if("api_key" in api_auth): + self.url = host + if(ssh_auth!=None): + self.filepath= filepath + self.ssh = paramiko.SSHClient() + self.ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) + self.ssh.connect(host, username=ssh_auth["user"], password=ssh_auth["passw"]) self.sftp = self.ssh.open_sftp() - self.url = host + + if(api_auth!=None): self.api_key = api_auth["api_key"] self.api_secret = api_auth["api_secret"] self.ssl=api_auth["ssl"] @@ -70,6 +77,7 @@ def initialize(self): self.get_all("dhcpd") self.get_all("vlans") self.get_all("interfaces") + def save(self,output): """ Save the current configuration to a file. @@ -83,11 +91,15 @@ def save(self,output): output : str The path to the file to which the configuration should be written. """ - update_xml_file(self.objects["dhcpd"],self.root,"dhcpd") - update_xml_file(self.objects["interfaces"],self.root,"interfaces") - #update_xml_file(self.objects["vlans"],self.root,"vlans") + if len(self.objects["dhcpd"]) > 0: + update_xml_file(self.objects["dhcpd"],self.root,"dhcpd") + if len(self.objects["interfaces"]) > 0: + update_xml_file(self.objects["interfaces"],self.root,"interfaces") + if len(self.objects["vlans"]) > 0: + update_xml_file(self.objects["vlans"],self.root,"vlans") with open(output, 'w') as f: f.write(ET.tostring(self.root, encoding='unicode', method='xml')) + def get_all(self,element): """ Get all objects of a given type from the in-memory xml data. @@ -110,36 +122,32 @@ def get_all(self,element): print(f''' ----------------------------- {element}''') for parent in self.root.findall(element): - for key in parent: + for child in parent: + if element== "dhcpd": - child = Dhcpd(key.tag,parent) + child_object = Dhcpd(child,child.tag) elif element== "interfaces": - child = Interface(key.tag,parent) + child_object = Interface(child) elif element== "vlans": - child = Vlan(key.tag,parent) - - child=get_element(parent, key.tag, child) - if element== "dhcpd": - _range={"_from": parent.find(key.tag).find("range/from"), - "_to":parent.find(key.tag).find("range/to")} - if _range["_from"] is not None: - _range["_from"]=_range["_from"].text - _range["_to"]=_range["_to"].text - child.range =_range + child_object = Vlan(child) - child.attr=key.attrib if key.attrib is not None else None - print(child.attr) if element != "vlans": - name = key.tag + name = child.tag else: - name = child.descr - self.objects[element][name]=child.__dict__ - print(f'''{key.tag} : {child.__dict__} + name = child_object.descr + + child_object.attr=child.attrib if child.attrib is not None else None + print(child_object.attr) + + self.objects[element][name]=child_object.__dict__ + print(f'''{child.tag} : {child_object.__dict__} -------------------''') return(self.objects[element]) + def close_con(self): self.sftp.close() self.ssh.close() + def put_file(self, _from,_to): """ Apply the configuration. @@ -153,6 +161,10 @@ def put_file(self, _from,_to): The destination path on the remote host where the file should be stored. """ self.sftp.put(_from, _to) + if len(self.objects["vlans"]) > 0: + reconfigure_vlans(self) + + def add_Items(self,type, data): """ Add objects of a given type to the in-memory xml data. @@ -184,31 +196,15 @@ def replace(item): else: Data[key] = value return Data - print(type) - print(data) - print(self.objects) # if( type== "vlans"): # vlans= api_get(self,"interfaces/vlan_settings/get") - for name, value in data.items(): + for value in data: value["attr"]={} - self.objects[type][name] = value - def set_vlans(self,vlans): - for value in vlans: - print("---------set vlan-----------------") - payload={"vlan":value} - r=api_post(self,"interfaces/vlan_settings/set",payload) - print(r) - def add_vlans(self,vlans): - for value in vlans: - print("---------add vlan-----------------") - print(value) - payload={"vlan":value} - r=api_post(self,"interfaces/vlan_settings/addItem",payload) - print(r) - r=api_post(self,"interfaces/vlan_settings/reconfigure",{}) - print(r) - # please use the get_backup function to avoid losing data - + id=value["id"] + value.pop("id") + self.objects[type][id] = value + + def get_conf(self,_from,_to=None): """ Get the config file from the remote host and save it to a file. @@ -226,6 +222,8 @@ def get_conf(self,_from,_to=None): self.sftp.get(_from,_to) self.tree = ET.parse(_to) self.root = self.tree.getroot() + +# deprecated def get_backup(self,output=None): """ this function is currently deprecated @@ -244,6 +242,22 @@ def get_backup(self,output=None): # with open(path, 'w') as f: # f.write(ET.tostring(backup, encoding='unicode', method='xml')) - # getRes(self.host, command, self.api_key, self.api_secret, timeout) - +# deprecated + def vlans_api(self,vlans, command="add"): + if command == "add": + for value in vlans: + print("---------add vlan-----------------") + print(value) + payload={"vlan":value} + r=api_post(self,"interfaces/vlan_settings/addItem",payload) + print(r) + r=api_post(self,"interfaces/vlan_settings/reconfigure",{}) + print(r) + elif command == "set": + for value in vlans: + print("---------set vlan-----------------") + payload={"vlan":value} + r=api_post(self,"interfaces/vlan_settings/set",payload) + print(r) + \ No newline at end of file diff --git a/python/build/lib/opnsense_helper/utils.py b/python/build/lib/opnsense_helper/utils.py index b0d9fee..23dddfc 100644 --- a/python/build/lib/opnsense_helper/utils.py +++ b/python/build/lib/opnsense_helper/utils.py @@ -6,36 +6,16 @@ import os aliases={ -"parentinterface": "if", +"parent": "if", "_from":"from", "_to":"to", "interface":"if" } -#curl -k -u $OPNS_KEY:$OPNS_SECRET https://$IPFW/api/diagnostics/interface/getinterfaceconfig - -def parseChild(parent, tag): - result=parent.find(tag) - - element=result.text if result is not None else None - return element - -def get_child(root,element, id, keys): - elements=[] - for parent in root.findall(element): - child= {} - for y in keys: - child[y]=None - for x in parent.findall(id): - for key in keys: - child[key]=parseChild(x, key) - elements.append(child) - return elements -def parseChild(parent, tag): - result=parent.find(tag) - - element=result.text if result is not None else None - return element +def parseChild(child, tag): + result=child.find(tag) + element=result.text if result is not None else None + return element def ping(helper): response = os.system(f"ping -c 1 {helper.host}") @@ -43,54 +23,15 @@ def ping(helper): print(f"IP {helper.host} is reachable") return 0 else: return 1 -def api_get(helper, command,params=None): - #url= "https://192.168.1.103/api/interfaces/vlan_settings/get" - s="s" if helper.ssl is True else "" - url = f"http{s}://{helper.host}/api/{command}" - r = requests.get(url, verify=helper.verify, params=params, auth=(helper.api_key, helper.api_secret)) +def reconfigure_vlans(helper): + stdin, stdout, stderr = helper.ssh.exec_command('/usr/local/opnsense/scripts/interfaces/reconfigure_vlans.php') + output = stdout.read().decode('utf-8') + print(output) + error = stderr.read().decode('utf-8') + if error: + print(f"Fehler: {error}") - if r.status_code == 200: - if 'application/json' in r.headers['Content-Type']: - # Verwenden Sie json.dump - response = json.loads(r.content) - else: - # Verwenden Sie ET.fromstring - response = ET.fromstring(r.content) - return (response) - else: - print ('Connection / Authentication issue, response received:') - print (r.text) -def api_post(helper, command, Data): - def post(Data,url): - return requests.post(url, verify=helper.verify, allow_redirects=False, headers={'Content-Type': 'application/json'}, auth=(helper.api_key, helper.api_secret), data=Data) - def fail(error): - print ('Connection / Authentication issue, response received:') - print (error) - def success(response): - response = json.loads(r.text) - return (response) - Data=json.dumps(Data) - s="s" if helper.ssl is True else "" - url = f"http{s}://{helper.host}/api/{command}" - r = post(Data,url) - if r.status_code == 200: - return success(r) - # if we fail because of redirect we start a new request - # if we allow redirect in the first place, our post request will get turned in a get request - elif r.status_code == 301: - new_url = r.headers['Location'] - r = post(Data,new_url) - if r.status_code == 200: - return success(r) - else: - fail(r.text) - else: - fail(r.text) -def get_vlans(helper): - command="interfaces/vlan_settings/get" - vlans=api_get(helper,command) - print(vlans) def get_element(root,id, obj): for x in root.findall(id): @@ -121,7 +62,6 @@ def update_xml_file(objects,root,type): el = root.find(type) el.clear() for key, value in objects.items(): - print(objects) if(type=="vlans"): key="vlan" @@ -130,3 +70,26 @@ def update_xml_file(objects,root,type): else: e=ET.SubElement(el,key) recoursion(e,value) + +# deprecated due to a logic fail +def get_child(root,element, id, keys): + elements=[] + for parent in root.findall(element): + child= {} + for y in keys: + child[y]=None + for x in parent.findall(id): + for key in keys: + child[key]=parseChild(x, key) + elements.append(child) + return elements + +def replace(item): + Data = {} + #data='{"vlan": {"descr": "example2", "if": "vtnet1", "tag": 110, "pcp": 0, "vlanif": "vlan0.110"}}' + for key, value in item.items(): + if key in aliases.keys(): + Data[aliases[key]] = value + else: + Data[key] = value + return Data diff --git a/python/examples/add_vlans.py b/python/examples/add_vlans.py new file mode 100644 index 0000000..79640a8 --- /dev/null +++ b/python/examples/add_vlans.py @@ -0,0 +1,52 @@ +from opnsense_helper.classes import Opnsense_Helper +output="./config.xml" +conf_path="/conf/config.xml" +host= "192.168.1.103" +def using_api(): + vlans_api=[ + {'if': 'vtnet1', 'tag': '1', 'pcp': '0', 'proto': None, 'descr': 'vlan1', 'vlanif': 'vlan0.1'}, + {'if': 'vtnet1', 'tag': '2', 'pcp': '0', 'proto': None, 'descr': 'vlan2', 'vlanif': 'vlan0.2'} + ] + api_auth={ + "api_key" :'ejl4fIU9yfNk+gaQmPk/rqIa15f1yX1snIKgcIEl2QNoJwhbekraWIE0ANRYceh9hey5IFGzlf3da4yJ', + "api_secret":'5JVVGoatPbaAA+FozLDQY92/T6sRlmKD1+aRNl/YI8KA9/0TNiTDboLveqvd9FU8wFeDo3D3DY5wrUtF', + "ssl": True, + "verify": False + } + helper=Opnsense_Helper(host=host,api_auth=api_auth,filepath=output, verbose=False) + helper.vlans_api(vlans_api,"add") + +def backend(): + vlans=[ + {"id":"vlan1",'parent': 'vtnet1', 'tag': '1', 'pcp': '0', 'proto': None, 'descr': 'vlan1', 'vlanif': 'vlan0.1'}, + {"id":"vlan2",'parent': 'vtnet1', 'tag': '2', 'pcp': '0', 'proto': None, 'descr': 'vlan2', 'vlanif': 'vlan0.2'}, + {"id":"vlan3",'parent': 'vtnet1', 'tag': '3', 'pcp': '0', 'proto': None, 'descr': 'vlan3', 'vlanif': 'vlan0.3'} + + ] + dhcp=[ + {"id":"opt2",'enable': '1', 'ddnsdomainalgorithm': 'hmac-md', "range":{'from': '200.0.3.10', '_to': '200.0.3.100'}}, + {"id":"opt3",'enable': '1', 'ddnsdomainalgorithm': 'hmac-md', "range":{'from': '200.0.4.10', '_to': '200.0.4.100'}} + ] + interfaces=[ + {"id":"opt1",'descr': 'router', 'enable': '1', 'ipaddr': None, 'subnet': None, 'type': None, 'virtual': None, 'spoofmac': '00:00:00:00:02:01',"interface":"vtnet1"}, + {"id":"opt2",'descr': 'vlan1', 'enable': '1', 'ipaddr': '200.0.3.1', 'subnet': '24', 'type': None, 'virtual': None, 'spoofmac': '00:00:00:00:00:01',"interface":"vlan0.1"}, + {"id":"opt3",'descr': 'vlan2', 'enable': '1', 'ipaddr': '200.0.4.1', 'subnet': '24', 'type': None, 'virtual': None, 'spoofmac': '00:00:00:00:00:02', "interface":"vlan0.2"}, + {"id":"opt4",'descr': 'vlan3', 'enable': '1', 'ipaddr': '200.0.5.1', 'subnet': '24', 'type': None, 'virtual': None, 'spoofmac': '00:00:00:00:00:03', "interface":"vlan0.3"} + + ] + auth={ + "user":"root", + "passw":"opnsense", + } + helper=Opnsense_Helper(host=host,ssh_auth=auth,filepath=output, verbose=False) + #helper.set_vlans(vlans) + helper.get_conf(conf_path) + helper.initialize() + helper.add_Items("interfaces",interfaces) + helper.add_Items("dhcpd",dhcp) + helper.add_Items("vlans",vlans) + helper.save(output) + helper.put_file(output,conf_path) + helper.close_con() +if __name__ == "__main__": + backend() \ No newline at end of file diff --git a/python/opnsense_helper.egg-info/PKG-INFO b/python/opnsense_helper.egg-info/PKG-INFO index b62df0c..ccd7f0f 100644 --- a/python/opnsense_helper.egg-info/PKG-INFO +++ b/python/opnsense_helper.egg-info/PKG-INFO @@ -1,6 +1,6 @@ Metadata-Version: 2.1 Name: opnsense_helper -Version: 0.1.9 +Version: 0.1.10 Summary: assign lan interfaces, create vlans, vlan-interfaces and setup dhcp in a single script. Home-page: https://github.com/the-pod-shop/opnsense-helper/ Author: ji-podhdead diff --git a/python/opnsense_helper.egg-info/SOURCES.txt b/python/opnsense_helper.egg-info/SOURCES.txt index 7e5315f..b3adb48 100644 --- a/python/opnsense_helper.egg-info/SOURCES.txt +++ b/python/opnsense_helper.egg-info/SOURCES.txt @@ -2,6 +2,7 @@ README.md setup.py opnsense_helper/__init__.py opnsense_helper/classes.py +opnsense_helper/frontend_utils.py opnsense_helper/utils.py opnsense_helper.egg-info/PKG-INFO opnsense_helper.egg-info/SOURCES.txt diff --git a/python/opnsense_helper/README.md b/python/opnsense_helper/README.md deleted file mode 120000 index 42061c0..0000000 --- a/python/opnsense_helper/README.md +++ /dev/null @@ -1 +0,0 @@ -README.md \ No newline at end of file diff --git a/python/opnsense_helper/README.md b/python/opnsense_helper/README.md new file mode 100644 index 0000000..e51af7f --- /dev/null +++ b/python/opnsense_helper/README.md @@ -0,0 +1,109 @@ +# opnsense-helper +assign lan interfaces, create vlans, vlan-interfaces and setup dhcp in a single script using the opnsense backend. +## install +## pip +```bash +pip install opnsense-helper +``` +## usage +- before you create Vlan-Interfaces you need to add them first using the add_vlan method +- rn i try to find out how to reconfigure the vlans using the backend, but this is on todo list + +```python +ffrom opnsense_helper.classes import Opnsense_Helper +output="./config.xml" +conf_path="/conf/config.xml" +host= "192.168.1.103" +vlans=[ +{"id":"vlan1",'parent': 'vtnet1', 'tag': '1', 'pcp': '0', 'proto': None, 'descr': 'vlan1', 'vlanif': 'vlan0.1'}, +{"id":"vlan2",'parent': 'vtnet1', 'tag': '2', 'pcp': '0', 'proto': None, 'descr': 'vlan2', 'vlanif': 'vlan0.2'}, +{"id":"vlan3",'parent': 'vtnet1', 'tag': '3', 'pcp': '0', 'proto': None, 'descr': 'vlan3', 'vlanif': 'vlan0.3'} + +] +dhcp=[ +{"id":"opt2",'enable': '1', 'ddnsdomainalgorithm': 'hmac-md', "range":{'from': '200.0.3.10', '_to': '200.0.3.100'}}, +{"id":"opt3",'enable': '1', 'ddnsdomainalgorithm': 'hmac-md', "range":{'from': '200.0.4.10', '_to': '200.0.4.100'}} +] +interfaces=[ +{"id":"opt1",'descr': 'router', 'enable': '1', 'ipaddr': None, 'subnet': None, 'type': None, 'virtual': None, 'spoofmac': '00:00:00:00:02:01',"interface":"vtnet1"}, +{"id":"opt2",'descr': 'vlan1', 'enable': '1', 'ipaddr': '200.0.3.1', 'subnet': '24', 'type': None, 'virtual': None, 'spoofmac': '00:00:00:00:00:01',"interface":"vlan0.1"}, +{"id":"opt3",'descr': 'vlan2', 'enable': '1', 'ipaddr': '200.0.4.1', 'subnet': '24', 'type': None, 'virtual': None, 'spoofmac': '00:00:00:00:00:02', "interface":"vlan0.2"}, +{"id":"opt4",'descr': 'vlan3', 'enable': '1', 'ipaddr': '200.0.5.1', 'subnet': '24', 'type': None, 'virtual': None, 'spoofmac': '00:00:00:00:00:03', "interface":"vlan0.3"} + +] +auth={ +"user":"root", +"passw":"opnsense", +} +helper=Opnsense_Helper(host=host,ssh_auth=auth,filepath=output, verbose=False) +#helper.set_vlans(vlans) +helper.get_conf(conf_path) +helper.initialize() +helper.add_Items("interfaces",interfaces) +helper.add_Items("dhcpd",dhcp) +helper.add_Items("vlans",vlans) +helper.save(output) +helper.put_file(output,conf_path) +helper.close_con() +``` + +### Frontend Api +```python +def using_api(): + vlans_api=[ + {'if': 'vtnet1', 'tag': '1', 'pcp': '0', 'proto': None, 'descr': 'vlan1', 'vlanif': 'vlan0.1'}, + {'if': 'vtnet1', 'tag': '2', 'pcp': '0', 'proto': None, 'descr': 'vlan2', 'vlanif': 'vlan0.2'} + ] + api_auth={ + "api_key" :'ejl4fIU9yfNk+gaQmPk/rqIa15f1yX1snIKgcIEl2QNoJwhbekraWIE0ANRYceh9hey5IFGzlf3da4yJ', + "api_secret":'5JVVGoatPbaAA+FozLDQY92/T6sRlmKD1+aRNl/YI8KA9/0TNiTDboLveqvd9FU8wFeDo3D3DY5wrUtF', + "ssl": True, + "verify": False + } + helper=Opnsense_Helper(host=host,api_auth=api_auth,filepath=output, verbose=False) + helper.vlans_api(vlans_api,"add") +``` +### Variables +#### Opnsense_Helper +(host=host,ssh_auth=auth,filepath=output, verbose=False) +| var | type | description | +| --- | --- | --- | +| host| str | ip or hostname | +| auth | dict {user: str, passw: str} | SSH authentication dictionary | + + + +#### Module Args +| var | type | elements | +| --- | --- | --- | +| vlans | list[dict] | {id: str, parent: str, tag: int, pcp: str, proto: str } | None, descr: str, vlanif: str} | +| interfaces | list[dict] | {id: str, descr: str, enable: int, ipaddr: str, subnet: str, type: str, virtual: bool, spoofmac: str, interface: str} | +| dhcp | list[dict] | {id: str, enable: str, ddnsdomainalgorithm: str, range: {from: str, _to: str}} | + + + +### contribute +- clone, or fork `git@github.com:the-pod-shop/opnsense-helper.git` +- build when made changes +- make sure to use the right user +```bash +cd python +python setup.py bdist_wheel \ +&& pip install --upgrade . \ +&& python3 -m pip install --upgrade build #--force +``` +- you can also use the build.sh script +- create pull request + +## motivation +- i couldnt find a single repo/collection/terraform provider/api that let me assign and enable lan interfaces +- i decided to create one mself +- opnsense api does not let me do it, it just replies with: controller not found +- but /conf/config.xml has the answer. +- however for phisical interfaces its the god damn conf.rc +- my opnsense runs in a vm, so it really doesnt matter for me +- i just add the interfaces via libvirt and all i need to do is to enable them, given the /conf/config.xml method +xml has the answer. +- however for phisical interfaces its the god damn conf.rc +- my opnsense runs in a vm, so it really doesnt matter for me +- i just add the interfaces via libvirt and all i need to do is to enable them, given the /conf/config.xml method diff --git a/python/opnsense_helper/classes.py b/python/opnsense_helper/classes.py index 8cff2cd..4c1e16f 100644 --- a/python/opnsense_helper/classes.py +++ b/python/opnsense_helper/classes.py @@ -3,9 +3,10 @@ import xml.etree.ElementTree as ET import logging -from opnsense_helper.utils import parseChild, update_xml_file, get_element, api_get, api_post, aliases +from opnsense_helper.utils import parseChild, update_xml_file, aliases, reconfigure_vlans +from opnsense_helper.frontend_utils import api_get,api_post class Interface: - def __init__(self, name, parent): + def __init__(self, parent): self.descr = parseChild(parent, "descr") self.enable = parseChild(parent, "enable") self.ipaddr = parseChild(parent, "ipaddr") @@ -16,7 +17,7 @@ def __init__(self, name, parent): self.attr={} class Vlan: - def __init__(self,name, parent): + def __init__(self,parent): self.parentinterface =parseChild(parent, "if") self.tag = parseChild(parent,"tag") self.pcp = parseChild(parent,"pcp") @@ -26,14 +27,18 @@ def __init__(self,name, parent): self.attr={} class Dhcpd: - def __init__(self, name, parent): + def __init__(self, parent,tag): self.enable = parseChild(parent, "enable") self.ddnsdomainalgorithm = parseChild(parent, "ddnsdomainalgorithm") - self.range={ - "_from":"", - "_to":"" - } self.attr={} + self._range={ + "_from": parent.find("range/from"), + "_to":parent.find("range/to") + } + if self._range["_from"] is not None: + self._range["_from"]=self._range["_from"].text + self._range["_to"]=self._range["_to"].text + class Opnsense_Helper(): def __init__(self, host=None, ssh_auth=None, api_auth=None, filepath="./config.xml", verbose=False): if(verbose): @@ -43,13 +48,15 @@ def __init__(self, host=None, ssh_auth=None, api_auth=None, filepath="./config.x "dhcpd":{}, "interfaces":{} } - self.filepath= filepath - self.ssh = paramiko.SSHClient() - self.ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) - self.ssh.connect(host, username=ssh_auth["user"], password=ssh_auth["passw"]) - if("api_key" in api_auth): + self.url = host + if(ssh_auth!=None): + self.filepath= filepath + self.ssh = paramiko.SSHClient() + self.ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) + self.ssh.connect(host, username=ssh_auth["user"], password=ssh_auth["passw"]) self.sftp = self.ssh.open_sftp() - self.url = host + + if(api_auth!=None): self.api_key = api_auth["api_key"] self.api_secret = api_auth["api_secret"] self.ssl=api_auth["ssl"] @@ -70,6 +77,7 @@ def initialize(self): self.get_all("dhcpd") self.get_all("vlans") self.get_all("interfaces") + def save(self,output): """ Save the current configuration to a file. @@ -83,11 +91,15 @@ def save(self,output): output : str The path to the file to which the configuration should be written. """ - update_xml_file(self.objects["dhcpd"],self.root,"dhcpd") - update_xml_file(self.objects["interfaces"],self.root,"interfaces") - #update_xml_file(self.objects["vlans"],self.root,"vlans") + if len(self.objects["dhcpd"]) > 0: + update_xml_file(self.objects["dhcpd"],self.root,"dhcpd") + if len(self.objects["interfaces"]) > 0: + update_xml_file(self.objects["interfaces"],self.root,"interfaces") + if len(self.objects["vlans"]) > 0: + update_xml_file(self.objects["vlans"],self.root,"vlans") with open(output, 'w') as f: f.write(ET.tostring(self.root, encoding='unicode', method='xml')) + def get_all(self,element): """ Get all objects of a given type from the in-memory xml data. @@ -110,36 +122,32 @@ def get_all(self,element): print(f''' ----------------------------- {element}''') for parent in self.root.findall(element): - for key in parent: + for child in parent: + if element== "dhcpd": - child = Dhcpd(key.tag,parent) + child_object = Dhcpd(child,child.tag) elif element== "interfaces": - child = Interface(key.tag,parent) + child_object = Interface(child) elif element== "vlans": - child = Vlan(key.tag,parent) - - child=get_element(parent, key.tag, child) - if element== "dhcpd": - _range={"_from": parent.find(key.tag).find("range/from"), - "_to":parent.find(key.tag).find("range/to")} - if _range["_from"] is not None: - _range["_from"]=_range["_from"].text - _range["_to"]=_range["_to"].text - child.range =_range + child_object = Vlan(child) - child.attr=key.attrib if key.attrib is not None else None - print(child.attr) if element != "vlans": - name = key.tag + name = child.tag else: - name = child.descr - self.objects[element][name]=child.__dict__ - print(f'''{key.tag} : {child.__dict__} + name = child_object.descr + + child_object.attr=child.attrib if child.attrib is not None else None + print(child_object.attr) + + self.objects[element][name]=child_object.__dict__ + print(f'''{child.tag} : {child_object.__dict__} -------------------''') return(self.objects[element]) + def close_con(self): self.sftp.close() self.ssh.close() + def put_file(self, _from,_to): """ Apply the configuration. @@ -153,6 +161,10 @@ def put_file(self, _from,_to): The destination path on the remote host where the file should be stored. """ self.sftp.put(_from, _to) + if len(self.objects["vlans"]) > 0: + reconfigure_vlans(self) + + def add_Items(self,type, data): """ Add objects of a given type to the in-memory xml data. @@ -184,31 +196,15 @@ def replace(item): else: Data[key] = value return Data - print(type) - print(data) - print(self.objects) # if( type== "vlans"): # vlans= api_get(self,"interfaces/vlan_settings/get") - for name, value in data.items(): + for value in data: value["attr"]={} - self.objects[type][name] = value - def set_vlans(self,vlans): - for value in vlans: - print("---------set vlan-----------------") - payload={"vlan":value} - r=api_post(self,"interfaces/vlan_settings/set",payload) - print(r) - def add_vlans(self,vlans): - for value in vlans: - print("---------add vlan-----------------") - print(value) - payload={"vlan":value} - r=api_post(self,"interfaces/vlan_settings/addItem",payload) - print(r) - r=api_post(self,"interfaces/vlan_settings/reconfigure",{}) - print(r) - # please use the get_backup function to avoid losing data - + id=value["id"] + value.pop("id") + self.objects[type][id] = value + + def get_conf(self,_from,_to=None): """ Get the config file from the remote host and save it to a file. @@ -226,6 +222,8 @@ def get_conf(self,_from,_to=None): self.sftp.get(_from,_to) self.tree = ET.parse(_to) self.root = self.tree.getroot() + +# deprecated def get_backup(self,output=None): """ this function is currently deprecated @@ -244,6 +242,22 @@ def get_backup(self,output=None): # with open(path, 'w') as f: # f.write(ET.tostring(backup, encoding='unicode', method='xml')) - # getRes(self.host, command, self.api_key, self.api_secret, timeout) - +# deprecated + def vlans_api(self,vlans, command="add"): + if command == "add": + for value in vlans: + print("---------add vlan-----------------") + print(value) + payload={"vlan":value} + r=api_post(self,"interfaces/vlan_settings/addItem",payload) + print(r) + r=api_post(self,"interfaces/vlan_settings/reconfigure",{}) + print(r) + elif command == "set": + for value in vlans: + print("---------set vlan-----------------") + payload={"vlan":value} + r=api_post(self,"interfaces/vlan_settings/set",payload) + print(r) + \ No newline at end of file diff --git a/python/opnsense_helper/frontend_utils.py b/python/opnsense_helper/frontend_utils.py new file mode 100644 index 0000000..9fd9e2e --- /dev/null +++ b/python/opnsense_helper/frontend_utils.py @@ -0,0 +1,62 @@ +import xml.etree.ElementTree as ET +# import libraries +import json +import xml.etree.ElementTree as ET +import requests +import os + + +def ping(helper): + response = os.system(f"ping -c 1 {helper.host}") + if response == 0: + print(f"IP {helper.host} is reachable") + return 0 + else: return 1 +def api_get(helper, command,params=None): + #url= "https://192.168.1.103/api/interfaces/vlan_settings/get" + s="s" if helper.ssl is True else "" + url = f"http{s}://{helper.host}/api/{command}" + r = requests.get(url, verify=helper.verify, params=params, auth=(helper.api_key, helper.api_secret)) + + + if r.status_code == 200: + if 'application/json' in r.headers['Content-Type']: + # Verwenden Sie json.dump + response = json.loads(r.content) + else: + # Verwenden Sie ET.fromstring + response = ET.fromstring(r.content) + return (response) + else: + print ('Connection / Authentication issue, response received:') + print (r.text) +def api_post(helper, command, Data): + def post(Data,url): + return requests.post(url, verify=helper.verify, allow_redirects=False, headers={'Content-Type': 'application/json'}, auth=(helper.api_key, helper.api_secret), data=Data) + def fail(error): + print ('Connection / Authentication issue, response received:') + print (error) + def success(response): + response = json.loads(r.text) + return (response) + Data=json.dumps(Data) + s="s" if helper.ssl is True else "" + url = f"http{s}://{helper.host}/api/{command}" + r = post(Data,url) + if r.status_code == 200: + return success(r) + # if we fail because of redirect we start a new request + # if we allow redirect in the first place, our post request will get turned in a get request + elif r.status_code == 301: + new_url = r.headers['Location'] + r = post(Data,new_url) + if r.status_code == 200: + return success(r) + else: + fail(r.text) + else: + fail(r.text) +def get_vlans(helper): + command="interfaces/vlan_settings/get" + vlans=api_get(helper,command) + print(vlans) diff --git a/python/opnsense_helper/utils.py b/python/opnsense_helper/utils.py index b0d9fee..23dddfc 100644 --- a/python/opnsense_helper/utils.py +++ b/python/opnsense_helper/utils.py @@ -6,36 +6,16 @@ import os aliases={ -"parentinterface": "if", +"parent": "if", "_from":"from", "_to":"to", "interface":"if" } -#curl -k -u $OPNS_KEY:$OPNS_SECRET https://$IPFW/api/diagnostics/interface/getinterfaceconfig - -def parseChild(parent, tag): - result=parent.find(tag) - - element=result.text if result is not None else None - return element - -def get_child(root,element, id, keys): - elements=[] - for parent in root.findall(element): - child= {} - for y in keys: - child[y]=None - for x in parent.findall(id): - for key in keys: - child[key]=parseChild(x, key) - elements.append(child) - return elements -def parseChild(parent, tag): - result=parent.find(tag) - - element=result.text if result is not None else None - return element +def parseChild(child, tag): + result=child.find(tag) + element=result.text if result is not None else None + return element def ping(helper): response = os.system(f"ping -c 1 {helper.host}") @@ -43,54 +23,15 @@ def ping(helper): print(f"IP {helper.host} is reachable") return 0 else: return 1 -def api_get(helper, command,params=None): - #url= "https://192.168.1.103/api/interfaces/vlan_settings/get" - s="s" if helper.ssl is True else "" - url = f"http{s}://{helper.host}/api/{command}" - r = requests.get(url, verify=helper.verify, params=params, auth=(helper.api_key, helper.api_secret)) +def reconfigure_vlans(helper): + stdin, stdout, stderr = helper.ssh.exec_command('/usr/local/opnsense/scripts/interfaces/reconfigure_vlans.php') + output = stdout.read().decode('utf-8') + print(output) + error = stderr.read().decode('utf-8') + if error: + print(f"Fehler: {error}") - if r.status_code == 200: - if 'application/json' in r.headers['Content-Type']: - # Verwenden Sie json.dump - response = json.loads(r.content) - else: - # Verwenden Sie ET.fromstring - response = ET.fromstring(r.content) - return (response) - else: - print ('Connection / Authentication issue, response received:') - print (r.text) -def api_post(helper, command, Data): - def post(Data,url): - return requests.post(url, verify=helper.verify, allow_redirects=False, headers={'Content-Type': 'application/json'}, auth=(helper.api_key, helper.api_secret), data=Data) - def fail(error): - print ('Connection / Authentication issue, response received:') - print (error) - def success(response): - response = json.loads(r.text) - return (response) - Data=json.dumps(Data) - s="s" if helper.ssl is True else "" - url = f"http{s}://{helper.host}/api/{command}" - r = post(Data,url) - if r.status_code == 200: - return success(r) - # if we fail because of redirect we start a new request - # if we allow redirect in the first place, our post request will get turned in a get request - elif r.status_code == 301: - new_url = r.headers['Location'] - r = post(Data,new_url) - if r.status_code == 200: - return success(r) - else: - fail(r.text) - else: - fail(r.text) -def get_vlans(helper): - command="interfaces/vlan_settings/get" - vlans=api_get(helper,command) - print(vlans) def get_element(root,id, obj): for x in root.findall(id): @@ -121,7 +62,6 @@ def update_xml_file(objects,root,type): el = root.find(type) el.clear() for key, value in objects.items(): - print(objects) if(type=="vlans"): key="vlan" @@ -130,3 +70,26 @@ def update_xml_file(objects,root,type): else: e=ET.SubElement(el,key) recoursion(e,value) + +# deprecated due to a logic fail +def get_child(root,element, id, keys): + elements=[] + for parent in root.findall(element): + child= {} + for y in keys: + child[y]=None + for x in parent.findall(id): + for key in keys: + child[key]=parseChild(x, key) + elements.append(child) + return elements + +def replace(item): + Data = {} + #data='{"vlan": {"descr": "example2", "if": "vtnet1", "tag": 110, "pcp": 0, "vlanif": "vlan0.110"}}' + for key, value in item.items(): + if key in aliases.keys(): + Data[aliases[key]] = value + else: + Data[key] = value + return Data diff --git a/python/setup.py b/python/setup.py index 41a4a33..e2a9a37 100644 --- a/python/setup.py +++ b/python/setup.py @@ -2,7 +2,7 @@ setup( name='opnsense_helper', - version='0.1.9', + version='0.1.10', description='assign lan interfaces, create vlans, vlan-interfaces and setup dhcp in a single script.', url='https://github.com/the-pod-shop/opnsense-helper/', author='ji-podhdead',