Package: wgconfig
wgconfigParsing and writing WireGuard configuration files (comment preserving)WireGuard config files are ini-style. Since all "Peer" sections have the same name, these files cannot be parsed and modified by most libraries handling configuration files. Most existing libraries are not able to preserve or even add comments when modifying a config file. "wgconfig" was created to work with WireGuard configuration files and to preserve comments.FeaturesRead and parse WireGuard configuration files and make the data available as Python dictionaries.Create new WireGuard configuration files.Add peers to WireGuard configuration files and delete peers from WireGuard configuration files.Save and clone WireGuard configuration files.Comments are preserved when reading and writing WireGuard configuration files.Leading comments may be added when creating sections or attributes.Such comments may be deleted when removing sections or attributes.No other libraries are needed, i.e. no dependencies.InstallationInstall using PyPi:pip3installwgconfigQuickstartReading and parsing an existing WireGuard configuration fileRead and parse the existing WireGuard configuration file 'wg0.conf' located in '/etc/wireguard':importwgconfigwc=wgconfig.WGConfig('wg0')wc.read_file()print('INTERFACE DATA:',,wc.get_interface())print('LIST OF PEERS:',wc.get_peers())print('ALL PEER DATA:',wc.get_peers(keys_only=False))Add a new peer with a comment line before the peer section:wc.add_peer('801mgm2JhjTOCxfihEknzFJGYxDvi+8oVYBrWe3hOWM=','# Newly added peer')Add an attribute to that peer:wc.add_attr('801mgm2JhjTOCxfihEknzFJGYxDvi+8oVYBrWe3hOWM=','Endpoint','wg.example.com:51820','# Added for demonstration purposes')Write the changes to disk. Comments that were present when reading the file are preserved.wc.write_file()Please see below for more detailed usage information.Creating a new WireGuard configuration fileCreate a new WireGuard configuration file as '/root/wgtest.conf':importwgconfigwc=wgconfig.WGConfig('/root/wgtest.conf')# Add attribute to Interface section (denoted by 'None')wc.add_attr(None,'PrivateKey','6FYKQKEtGFAb5HSwyj5cQl3wgS1E9d6SqVjdVksOn2s=')# Save to diskwc.write_file()# Access the dataprint('INTERFACE DATA:',wc.get_interface())print('LIST OF PEERS (there are no peers yet):',wc.get_peers())print('ALL PEER DATA (there are no peers yet):',wc.get_peers(keys_only=False))The module also contains simple wrappers around the wg command (contained in WireGuard tools) to generate and manage keys:importwgconfig.wgexecaswgexec# Create a new WireGuard private keyprivate_key=wgexec.generate_privatekey()More information and examples can be found here:Detailed example for reading WireGuard config filesPlease see the section below for detailed API description.Detailed API descriptionPropertiesinterfaceReturns attributes and values (including wgconfig-internal ones) of the Interface section as a dictionaryNotes:You might want to use the more flexibleget_interface()method (see further below) instead.peersReturns attributes and values (including wgconfig-internal ones) of all peers as a nested dictionaryNotes:You might want to use the more flexibleget_peers()method (see further below) instead.Methods for interaction__init__(file)Initializes the instanceParameters:"file" (str): Path of the WireGuard configuration file
You may also just provide the interface name. In this case, the path '/etc/wireguard' is assumed along with a file extension '.conf'.Examples:wc = wgconfig.WGConfig('wg0')wc = wgconfig.WGConfig('/etc/wireguard/wg0.conf')read_file()Reads the WireGuard config file from disk into memorywrite_file(file)Writes a WireGuard config file from memory to fileParameters:"file" (str, optional, default: None): Path of the WireGuard configuration file
You may also just provide the interface name. In this case the path '/etc/wireguard' is assumed along with a file extension '.conf'.
In case the parameter is missing, the config file defined on object initialization is used.Examples:wc.write_file()wc.write_file('wg0')wc.write_file('/etc/wireguard/wg0.conf')initialize_file(leading_comment)Empties the file and adds the interface section headerParameters:"leading_comment" (str, optional, default: None): Comment line to be added before the Interface section. Must start with a '#' to indicate a comment.Examples:wc.initialize_file()wc.initialize_file('# Here comes the Interface section:')get_interface(include_details)Returns a dictionary of the attributes and values of the interface sectionParameters:"include_details" (boolean, optional, default: False): Also include attributes with a leading underscore (e.g. the disabled state or the raw data).Examples:ifdata = wc.get_interface()get_peers(keys_only, include_disabled, include_details)Returns a list of peers or - if selected - a dictionary including peers' dataParameters:"keys_only" (boolean, optional, default: True): Return only the public keys as a list or return keys and corresponding data as a dictionary."include_disabled" (boolean, optional, default: False): Also return data of disabled peers."include_details" (boolean, optional, default: False): Also include attributes with a leading underscore (e.g. the disabled state or the raw data).Examples:peers = wc.get_peers()peerdata = wc.get_peers(keys_only=False)get_peer(key, include_details)Returns the data of the peer with the given (public) keyParameters:"key" (str): Public key of the peer"include_details" (boolean, optional, default: False): Also include attributes with a leading underscore (e.g. the disabled state or the raw data).Examples:peerdata = wc.get_peer('801mgm2JhjTOCxfihEknzFJGYxDvi+8oVYBrWe3hOWM=')peerdata = wc.get_peer('801mgm2JhjTOCxfihEknzFJGYxDvi+8oVYBrWe3hOWM=', include_details=True)Notes:Don't forget to callread_file()before attempting to get data out of a fileAccess thepeersproperty if you want to retrieve the data of all peersadd_peer(key, leading_comment)Adds a new peer with the given (public) keyParameters:"key" (str): Public key of the new peer"leading_comment" (str, optional, default: None): Comment line to be added before the Peer section. Must start with a '#' to indicate a comment.Examples:wc.add_peer('801mgm2JhjTOCxfihEknzFJGYxDvi+8oVYBrWe3hOWM=')wc.add_peer('801mgm2JhjTOCxfihEknzFJGYxDvi+8oVYBrWe3hOWM=', '# Here comes the Interface section:')del_peer(key)Removes the peer with the given (public) keyNote: Comment lines immediately before the Peer section are removed, too.Parameters:"key" (str): Public key of the peerExamples:wc.del_peer('801mgm2JhjTOCxfihEknzFJGYxDvi+8oVYBrWe3hOWM=')add_attr(key, attr, value, leading_comment, append_as_line)Adds an attribute/value pair to the given peer ('None' for adding an interface attribute)Parameters:"key" (str): Key of the peer. Set to 'None' to denote the Interface section"attr" (str) Name of the attribute to add"value" (str or int) Value of the attribute to add"leading_comment" (str, optional, default: None): Comment line to be added before the Peer section. Must start with a '#' to indicate a comment."append_as_line" (bool, optional, default: False): Whether to add the attribute as a new line if another attribute with the same name already exists. If "False", adding an attribute that already exists results in comma-separated attribute values. This way, "AllowedIPs" can be added one by one.Examples:wc.add_attr(None, 'ListenPort', '51820')wc.add_attr('801mgm2JhjTOCxfihEknzFJGYxDvi+8oVYBrWe3hOWM=', 'AllowedIPs', '0.0.0.0/0')wc.add_attr('801mgm2JhjTOCxfihEknzFJGYxDvi+8oVYBrWe3hOWM=', 'AllowedIPs', '0.0.0.0/0', '# Allow all IPv4 addresses', append_as_line=True)del_attr(self, key, attr, value, remove_leading_comments)Removes an attribute/value pair from the given peer ('None' for adding an interface attribute); set 'value' to 'None' to remove all valuesParameters:"key" (str): Key of the peer. Set to 'None' to denote the Interface section"attr" (str) Name of the attribute to remove"value" (str or int, optional, default: None) Value of the attribute to remove
Set to 'None' if all values (either comma-separated or is multiple attribute lines) shall be removed. Otherwise specify the specific value to be removed."remove_leading_comments" (bool, optional, default: True): Indicates whether comment lines before the attribute line(s) shall be removed, tooExamples:wc.del_attr(None, 'ListenPort')wc.del_attr('801mgm2JhjTOCxfihEknzFJGYxDvi+8oVYBrWe3hOWM=', 'AllowedIPs')wc.del_attr('801mgm2JhjTOCxfihEknzFJGYxDvi+8oVYBrWe3hOWM=', 'AllowedIPs', '0.0.0.0/0')wc.del_attr('801mgm2JhjTOCxfihEknzFJGYxDvi+8oVYBrWe3hOWM=', 'AllowedIPs', '0.0.0.0/0', remove_leading_comments=False)disable_peer(self, key)Disables the peer with the given (public) key by prepending#!to all lines in a peer sectionParameters:"key" (str): Public key of the peerExamples:wc.disable_peer('801mgm2JhjTOCxfihEknzFJGYxDvi+8oVYBrWe3hOWM=')enable_peer(self, key)Enables the peer with the given (public) key by removing#!from all lines in a peer sectionParameters:"key" (str): Public key of the peerExamples:wc.enable_peer('801mgm2JhjTOCxfihEknzFJGYxDvi+8oVYBrWe3hOWM=')get_peer_enabled(self, key)Checks whether the peer with the given (public) key is enabledParameters:"key" (str): Public key of the peerExamples:wc.get_peer_enabled('801mgm2JhjTOCxfihEknzFJGYxDvi+8oVYBrWe3hOWM=')Reporting bugsIn case you encounter any bugs, please report the expected behavior and the actual behavior so that the issue can be reproduced and fixed.DevelopersClone repositoryClone this repo to your local machine usinghttps://github.com/towalink/wgconfig.gitInstall the module temporarily to make it available in your Python installation:pip3install-e<pathtorootof"src"directory>Run unit testsCall "pytest" to run the unit tests:pytest<pathtorootof"test"directory>LicenseAGPL3 licenseCopyright 2020-2023 ©Dirk Henrici.WireGuardis a registered trademark of Jason A. Donenfeld.