{"id":22116359,"url":"https://github.com/c0m4r/neatplan","last_synced_at":"2025-03-24T05:43:19.324Z","repository":{"id":218440823,"uuid":"746408004","full_name":"c0m4r/neatplan","owner":"c0m4r","description":"nginx-style network configuration","archived":false,"fork":false,"pushed_at":"2024-02-06T05:54:34.000Z","size":154,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-03-18T06:45:52.139Z","etag":null,"topics":["neatplan","network-configuration","network-tools"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/c0m4r.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG","contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null},"funding":{"custom":["https://en.wosp.org.pl/fundacja/jak-wspierac-wosp/wesprzyj-online"]}},"created_at":"2024-01-21T23:09:55.000Z","updated_at":"2024-06-09T06:13:04.000Z","dependencies_parsed_at":"2024-02-06T06:26:25.172Z","dependency_job_id":"5f8e71f1-b302-4b7b-9978-9af4f7211af7","html_url":"https://github.com/c0m4r/neatplan","commit_stats":null,"previous_names":["c0m4r/neatplan"],"tags_count":3,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/c0m4r%2Fneatplan","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/c0m4r%2Fneatplan/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/c0m4r%2Fneatplan/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/c0m4r%2Fneatplan/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/c0m4r","download_url":"https://codeload.github.com/c0m4r/neatplan/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245217791,"owners_count":20579297,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["neatplan","network-configuration","network-tools"],"created_at":"2024-12-01T12:43:00.608Z","updated_at":"2025-03-24T05:43:19.296Z","avatar_url":"https://github.com/c0m4r.png","language":"Python","funding_links":["https://en.wosp.org.pl/fundacja/jak-wspierac-wosp/wesprzyj-online"],"categories":[],"sub_categories":[],"readme":"# neatplan\n\n[![Python](https://img.shields.io/badge/made%20with-python-blue?logo=python\u0026logoColor=ffffff)](https://www.python.org/)\n[![Python](https://img.shields.io/badge/pypi-neatplan-blue?logo=pypi\u0026logoColor=ffffff)](https://pypi.org/project/neatplan/)\n[![License: GPL v3](https://img.shields.io/badge/License-GPLv3-blue.svg)](https://www.gnu.org/licenses/gpl-3.0)\n[![CodeFactor](https://www.codefactor.io/repository/github/c0m4r/neatplan/badge)](https://www.codefactor.io/repository/github/c0m4r/neatplan)\n\nnginx-style network configuration\n\n...pretty neat, huh?\n\nWhy, for the love of integrated circuits why you ask? Because I can.\n\n## Dependencies\n\n* Python \u003e= 3.6\n* [crossplane](https://github.com/nginxinc/crossplane)\n* iproute2\n* dhclient (optional)\n\n## Features\n\n- Boot-time configuration\n- IPv4/IPv6 support\n- Loopback interface up by default (`ip link set lo up`)\n- Set link up for a given interface (`ip link set \u003ciface\u003e up`)\n- Set IP address for a given interface (`ip addr add \u003cip/mask\u003e dev \u003ciface\u003e`)\n- Set IP route for a given interface (`ip ro add \u003cip\u003e dev \u003ciface\u003e`)\n- Set default IP route for a given interface (`ip ro add default via \u003cip\u003e dev \u003ciface\u003e`)\n- Set via IP route for a given interface (`ip ro add \u003cip\u003e via \u003cip\u003e dev \u003ciface\u003e`)\n- Set nameservers (/etc/resolv.conf)\n- DHCP configuration (dhclient)\n- Firewall configuration (`iptables-restore`, `ip6tables-restore`)\n- Custom commands to run before and after for advanced and custom configuration\n- Configured interfaces are being stored in `/run/neatplan`\n\n## Installation\n\nNeatplan is intended for people who know what they are doing, \nor at least for those aware that this may result \nin the loss of access to the server over the network. \nIf you're afraid of breaking things, pick something else. \nAlthough, returning to the previous network configuration method is trivial \nbecause neatplan does not introduce any invasive changes to the system. \nBut before you start destroying your network configuration, \nhowever enjoyable it is, make sure you have access to some kind \nof remote (or local) console that will allow you to debug without direct SSH access.\n\nAll the scripts must be run with root privileges, \nas it is necessary to interact with network configuration.\n\n### PyPI\n\n```bash\npip install neatplan\n```\n\n### Github\n\n```bash\ngit clone https://github.com/c0m4r/neatplan.git /opt/neatplan\ncd /opt/neatplan\n./deploy.sh\n```\n\nThe script will:\n\n* create the Python venv\n* create a symlink to the wrapper in `/usr/local/bin/neatplan`\n* copy the respective init script if it's available\n* create a config file in `/etc/neatplan/default.conf`\n\n#### Alpine Linux\n\nTo replace networking with neatplan at boot time:\n\n```bash\nrc-update del networking boot\nrc-update add neatplan boot\n```\n\n#### Void Linux\n\nTo start neatplan as a runit service:\n\n```bash\nln -s /etc/sv/neatplan /var/service/\n```\n\n## Usage\n\nSimply running `neatplan` will immediately set the network using default config (if present).\n\n### Dry-run\n\nIf you would like to test your configuration before actually executing it, use the dry-run mode:\n\n```\nneatplan --dry-run\n```\n\nNeatplan will only print a parsed configuration, so you can verify it before execution.\n\n### Custom config path\n\nYou can also point neatplan to a different config file using `--config` option:\n\n```\nneatplan --config /path/to/file.conf\n```\n\n### Help\n\nRun with `--help` to see this help message:\n\n```\nusage: neatplan [-h] [-c CONFIG] [-v] [--dry-run]\n\nnginx-style network configuration\n\noptions:\n  -h, --help            show this help message and exit\n  -c CONFIG, --config CONFIG\n                        Config file absolute path\n  -v, --version         Show version and exit\n  --dry-run             Don't execute, only show what you've got\n```\n\n## Configuration\n\n#### Config path\n\n`/etc/neatplan/default.conf`\n\n#### Quick example\n\n* IPv4 using DHCP\n* Static IPv6 address\n* IPv6-only CloudFlare DNS\n\n```nginx\nnetwork {\n    backend iproute2;\n    ethernet {\n        eth0 {\n            dhcp4 {\n                enable true;\n            }\n            addresses {\n                address fe80:ffff:eeee:dddd::1/64;\n            }\n            routes {\n                route fe80::1 default;\n            }\n        }\n    }\n    dns {\n        nameserver 2606:4700:4700::1111;\n        nameserver 2606:4700:4700::1001;\n    }\n}\n```\n\nNote that \n\n#### Full feature showcase\n\n```nginx\nnetwork {\n    backend iproute2;\n    before {\n        command \"touch /tmp/neatplan\";\n    }\n    firewall {\n        iptables /etc/iptables/iptables.rules;\n        ip6tables /etc/iptables/ip6tables.rules;\n    }\n    ethernet {\n        eth0 {\n            dhcp4 {\n                enable true;\n            }\n            dhcp6 {\n                enable false;\n            }\n            addresses {\n                address fe80:ffff:eeee:dddd::1/64;\n                address fe80:ffff:eeee:dddd::2/64;\n                address 192.168.0.10;\n                address 192.168.100.50/24;\n            }\n            routes {\n                route fe80::1 default;\n                route 192.168.0.1;\n                route 1.1.1.1 via 192.168.0.1;\n            }\n        }\n    }\n    dns {\n        nameserver 2606:4700:4700::1111;\n        nameserver 2606:4700:4700::1001;\n    }\n    after {\n        command \"echo I\\'m so custom, wow\";\n        command \"ip link add link eth0 name eth0.1337 type vlan id 1337\";\n    }\n}\n```\n\nNote that `dhcp6 { enable: false; }` isn't actually necessary. It's not being run by default if not enabled explicitly.\n\nAdditionally, the ability to execute custom commands within the `before` and `after` contexts \ncan be used to run arbitrary code. Make sure only root has write access to the configuration.\n\n## Writing init scripts\n\n* Neatplan saves all configured interfaces (including `lo`) at boot time to `/run/neatplan`.\n  You can iterate through them or do whatever the hell you want with that information.\n* When starting neatplan make sure it is started before services that rely on the network,\n  preferably within boot runlevel (thank you captain obvious)\n* If you're about to use IPv6 you have to make sure that\n  [tentative states](https://www.the-art-of-web.com/system/ipv6-dad-tentative/) are gone before ending a start job\n* When stopping neatplan make sure to `rm /run/neatplan` at the end.\n* Handle Python venv before executing neatplan with `. /opt/neatplan/.venv/bin/activate`\n  or set the `PATH=/opt/neatplan/.venv:$PATH`.\n\nSee example [OpenRC](https://github.com/c0m4r/neatplan/blob/main/etc/init.d/neatplan) \nand [runit](https://github.com/c0m4r/neatplan/blob/main/etc/sv/neatplan/run) init scripts.\n\n## Documentation\n\nI'm not saying it's the worst documentation I wrote, but it's the worst documentation I wrote.\n\n![image](https://github.com/c0m4r/neatplan/assets/6292788/4aec222e-fe3e-4c11-a896-44b611c8d8d8)\n\n### Contexts\n\n| name | context | description | \n| --- | --- | --- |\n| network | | root of network configuration |\n| before | network | list of commands to run before network configuration |\n| firewall | network | firewall configuration |\n| ethernet | network | ethernet configuration |\n| \\\u003ciface\\\u003e | network \u0026rarr; ethernet | network interface configuration |\n| dhcp4 | network \u0026rarr; ethernet \u0026rarr; \\\u003ciface\\\u003e | DHCP v4 settings |\n| dhcp6 | network \u0026rarr; ethernet \u0026rarr; \\\u003ciface\\\u003e | DHCP v6 settings |\n| addresses | network \u0026rarr; ethernet \u0026rarr; \\\u003ciface\\\u003e | IP addresses configuration |\n| routes | network \u0026rarr; ethernet \u0026rarr; \\\u003ciface\\\u003e | IP routes configuration |\n| dns | network | list of nameservers |\n| before | network | list of commands to run after network configuration |\n\n### Directives\n\n| name | context | syntax | description |\n| --- | --- | --- | --- |\n| backend | network | `backend \u003cname\u003e;` | IP configuration backend |\n| command | before, after | `command \"\u003ccommand\u003e \u003cargs\u003e\";` | Custom shell command |\n| iptables | firewall | `iptables \u003cfilepath\u003e;` | Path to iptables rules |\n| ip6tables | firewall | `ip6tables \u003cfilepath\u003e;` | Path to ip6tables rules |\n| enable | dhcp4, dhcp6 | `option true \\| false;` | Enable or disable option |\n| address | \\\u003ciface\\\u003e | `address \u003cip/mask\u003e;` | IPv4 or IPv6 address |\n| route | \\\u003ciface\\\u003e | `route \u003cip\u003e [default \\| via \u003cip\u003e];` | IP route |\n| nameserver | dns | `nameserver \u003cip\u003e;` | Nameserver address |\n\n## License\n\n![image](https://github.com/c0m4r/neatplan/assets/6292788/74c6156b-ffc9-434c-aeb8-5223ac229880)\n\n```\nneatplan - nginx-like network configuration\nCopyright (C) 2024 c0m4r\n\nThis program is free software: you can redistribute it and/or modify\nit under the terms of the GNU General Public License as published by\nthe Free Software Foundation, either version 3 of the License, or\n(at your option) any later version.\n\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with this program.  If not, see \u003chttps://www.gnu.org/licenses/\u003e.\n```\n\n## Funding\n\nIf you found this software somewhat useful, \nplease consider [making a donation](https://en.wosp.org.pl/fundacja/jak-wspierac-wosp/wesprzyj-online) \nto a [charity](https://en.wikipedia.org/wiki/Great_Orchestra_of_Christmas_Charity) on my behalf. \nThank you.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fc0m4r%2Fneatplan","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fc0m4r%2Fneatplan","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fc0m4r%2Fneatplan/lists"}