Removed ^M

This commit is contained in:
Giulio 2021-07-13 22:29:17 +02:00
parent 23a87b96e9
commit 66568b20a6

524
Readme.md
View File

@ -1,262 +1,262 @@
# QubesOS Port Forwarding GSoC 2021 # QubesOS Port Forwarding GSoC 2021
## Proposal text ## Proposal text
### Introduction ### Introduction
Forwarding ports to Qubes VM is currently possible only though a multi step, error prone, manual process that also requires writing custom configuration in order to be persistent between reboots. Things as simple as starting a webserver or netcat for LAN file sharing canbe eventually a troublesome and time-wasting process[1][2]. Furthermore, applications thatrely on NAT traversal protocols such as those for audio and video communications do not workin direct P2P mode with STUN and always use TURN instead[3]. Forwarding ports to Qubes VM is currently possible only though a multi step, error prone, manual process that also requires writing custom configuration in order to be persistent between reboots. Things as simple as starting a webserver or netcat for LAN file sharing canbe eventually a troublesome and time-wasting process[1][2]. Furthermore, applications thatrely on NAT traversal protocols such as those for audio and video communications do not workin direct P2P mode with STUN and always use TURN instead[3].
### Project Goals ### Project Goals
Implement a GUI for automatic and persistent, eventually with a predefined timespan (ie: untilreboot), port forwarding. The idea is to split horizontally the "Firewall Rules" tab in the"Qubes Settings" window and add another area below it. It is aloready possible to forward TCP streams, however there is no GUI nor a clear dashboard and furthermore its versatility is limited. In addition, discuss and verify the possibility to implement a secure NAT traversal systemand GUI. A basic proposal could be a checkbox to enable NAT traversal requests. When thecheckbox is selected, the FirwallVM will redirect NAT traversal requests to a local pythondaemon or a dedicated VM that will negotiate the NAT traversal and configure the networkaccordingly. In this case, prompt the user in Dom0 about the NAT traversal request. Of coursethe qvm-* set of tools must e able to achieve the same tasks via CLI. Implement a GUI for automatic and persistent, eventually with a predefined timespan (ie: untilreboot), port forwarding. The idea is to split horizontally the "Firewall Rules" tab in the"Qubes Settings" window and add another area below it. It is aloready possible to forward TCP streams, however there is no GUI nor a clear dashboard and furthermore its versatility is limited. In addition, discuss and verify the possibility to implement a secure NAT traversal systemand GUI. A basic proposal could be a checkbox to enable NAT traversal requests. When thecheckbox is selected, the FirwallVM will redirect NAT traversal requests to a local pythondaemon or a dedicated VM that will negotiate the NAT traversal and configure the networkaccordingly. In this case, prompt the user in Dom0 about the NAT traversal request. Of coursethe qvm-* set of tools must e able to achieve the same tasks via CLI.
### Implementation ### Implementation
First develop and document the part related to manual port forwarding since it is both a more frequent use case and is less complicated. Depending on the problems encountered, evaluate the feasibility of secure NAT traversal. First develop and document the part related to manual port forwarding since it is both a more frequent use case and is less complicated. Depending on the problems encountered, evaluate the feasibility of secure NAT traversal.
#### Notes #### Notes
1. https://github.com/QubesOS/qubes-issues/issues/3556 1. https://github.com/QubesOS/qubes-issues/issues/3556
2. https://www.reddit.com/r/Qubes/comments/8cb57i/how_to_achieve_qube_to_qube_communication_port/ 2. https://www.reddit.com/r/Qubes/comments/8cb57i/how_to_achieve_qube_to_qube_communication_port/
3. https://github.com/QubesOS/qubes-issues/issues/6225 3. https://github.com/QubesOS/qubes-issues/issues/6225
## Development ## Development
### Background ### Background
* https://www.qubes-os.org/doc/admin-api/ * https://www.qubes-os.org/doc/admin-api/
* https://www.qubes-os.org/doc/vm-interface/#firewall-rules-in-4x * https://www.qubes-os.org/doc/vm-interface/#firewall-rules-in-4x
* https://www.qubes-os.org/doc/firewall/ * https://www.qubes-os.org/doc/firewall/
* https://www.qubes-os.org/doc/config-files/ * https://www.qubes-os.org/doc/config-files/
### Main components involved ### Main components involved
1. [Firewall GUI in "Settings" (qubes-manager)](https://github.com/QubesOS/qubes-manager/blob/master/qubesmanager/firewall.py) 1. [Firewall GUI in "Settings" (qubes-manager)](https://github.com/QubesOS/qubes-manager/blob/master/qubesmanager/firewall.py)
2. [CLI interface available via `qvm-firewall` (core-admin-client)](https://github.com/QubesOS/qubes-core-admin-client/blob/master/qubesadmin/tools/qvm_firewall.py) 2. [CLI interface available via `qvm-firewall` (core-admin-client)](https://github.com/QubesOS/qubes-core-admin-client/blob/master/qubesadmin/tools/qvm_firewall.py)
3. [Actual client logic for the Admin API (core-admin-client)](https://github.com/QubesOS/qubes-core-admin-client/blob/master/qubesadmin/firewall.py) 3. [Actual client logic for the Admin API (core-admin-client)](https://github.com/QubesOS/qubes-core-admin-client/blob/master/qubesadmin/firewall.py)
4. [Admin API interface - XML conf manager (core-admin)](https://github.com/QubesOS/qubes-core-admin/blob/master/qubes/firewall.py) 4. [Admin API interface - XML conf manager (core-admin)](https://github.com/QubesOS/qubes-core-admin/blob/master/qubes/firewall.py)
5. [Agent running in firewall vm - executes `nft` or `iptables`](https://github.com/QubesOS/qubes-core-agent-linux/blob/master/qubesagent/firewall.py) 5. [Agent running in firewall vm - executes `nft` or `iptables`](https://github.com/QubesOS/qubes-core-agent-linux/blob/master/qubesagent/firewall.py)
### Current Status ### Current Status
#### How does the GUI and `qvm-firewall` configuration work? #### How does the GUI and `qvm-firewall` configuration work?
The Qubes Manager GUI and the `qvm-firewall` both use the code imlemented in the Admi API Client library. The Client Library sends specific messages to the `qubesd` daemon. The Qubes Manager GUI and the `qvm-firewall` both use the code imlemented in the Admi API Client library. The Client Library sends specific messages to the `qubesd` daemon.
The currently supported operatins are: The currently supported operatins are:
* `admin.vm.firewall.Get` * `admin.vm.firewall.Get`
* `admin.vm.firewall.Set` * `admin.vm.firewall.Set`
* `admin.vm.firewall.Reload` * `admin.vm.firewall.Reload`
These actions can be tested by using the `qvm-firewall` utility. It is important to note that both the client and the daemon are more flexibile compared to the settings available via the GUI. These actions can be tested by using the `qvm-firewall` utility. It is important to note that both the client and the daemon are more flexibile compared to the settings available via the GUI.
##### Configuration files ##### Configuration files
If any non default configuration is set by the user, an AppVM will have a `firewall.xml` configuration file in the `var/lib/qubes/<appvm>/` path. Deleting the file will reset the firewall to the default state and any customization will be lost. If any non default configuration is set by the user, an AppVM will have a `firewall.xml` configuration file in the `var/lib/qubes/<appvm>/` path. Deleting the file will reset the firewall to the default state and any customization will be lost.
The `firewall.xml` is clearly human readable and contains rules in the form: The `firewall.xml` is clearly human readable and contains rules in the form:
``` ```
<firewall version="2"> <firewall version="2">
<rules> <rules>
<rule> <rule>
<properties> <properties>
<!-- accept outgoing to lsd.cat porto tcp port 443 --> <!-- accept outgoing to lsd.cat porto tcp port 443 -->
<property name="action">accept</property> <property name="action">accept</property>
<property name="dsthost">lsd.cat</property> <property name="dsthost">lsd.cat</property>
<property name="proto">tcp</property> <property name="proto">tcp</property>
<property name="dstports">443</property> <property name="dstports">443</property>
</properties> </properties>
</rule> </rule>
<rule> <rule>
<properties> <properties>
<!-- accept outgoing to 10.132.11.1/24 proto any --> <!-- accept outgoing to 10.132.11.1/24 proto any -->
<property name="action">accept</property> <property name="action">accept</property>
<property name="dsthost">10.132.11.1/24</property> <property name="dsthost">10.132.11.1/24</property>
</properties> </properties>
</rule> </rule>
<rule> <rule>
<properties> <properties>
<!-- allow outgoing dns queries. needed for domain based rules --> <!-- allow outgoing dns queries. needed for domain based rules -->
<property name="action">accept</property> <property name="action">accept</property>
<property name="specialtarget">dns</property> <property name="specialtarget">dns</property>
</properties> </properties>
</rule> </rule>
<rule> <rule>
<properties> <properties>
<!-- drop everything else --> <!-- drop everything else -->
<property name="action">drop</property> <property name="action">drop</property>
</properties> </properties>
</rule> </rule>
</rules> </rules>
</firewall> </firewall>
``` ```
##### Commands ##### Commands
The following command will return the firewall rules for `<vmnname>`. The following command will return the firewall rules for `<vmnname>`.
``` ```
qvm-firewall <vmname> qvm-firewall <vmname>
``` ```
As can be seen, the output will show more colums that the GUI, specifically an `EXPIRE`, `COMMENT`, and `SPECIAL TARGET` columns will be displayed. As can be seen, the output will show more colums that the GUI, specifically an `EXPIRE`, `COMMENT`, and `SPECIAL TARGET` columns will be displayed.
The following command will reload the persistent rules stored in `firewall.xml` of `<vmname>` The following command will reload the persistent rules stored in `firewall.xml` of `<vmname>`
``` ```
qvm-firewall <vmname> --reload qvm-firewall <vmname> --reload
``` ```
The following command can be used to add a rule. Not that if the GUI detects that the firewall has been edited from CLI, since it does not support all CLI settings, it will refuse to allow management again from the GUI. The following command can be used to add a rule. Not that if the GUI detects that the firewall has been edited from CLI, since it does not support all CLI settings, it will refuse to allow management again from the GUI.
``` ```
qvm-firewall <vmname> add action=accept dsthost=1.1.1.1 proto=tcp dstports=80-80 expire=+5000 comment="cloudflare http test rule" qvm-firewall <vmname> add action=accept dsthost=1.1.1.1 proto=tcp dstports=80-80 expire=+5000 comment="cloudflare http test rule"
``` ```
### Proposal ### Proposal
Currently, all firewall rules have an `action` properties which can be either `accept` or `drop`. The plan is to add a third option `forward` specifically for implementing automatic port forwarding. Such options must be supported both in the configuration file and in the Admin API (client-server). Lastly, it shall be implemented in the agent daemon. Currently, all firewall rules have an `action` properties which can be either `accept` or `drop`. The plan is to add a third option `forward` specifically for implementing automatic port forwarding. Such options must be supported both in the configuration file and in the Admin API (client-server). Lastly, it shall be implemented in the agent daemon.
The main issue however is the fact that currenly, the firewall client library is designated to operate only on the AppVM configured Firewall NetVM. However, in order to forward ports from the outside world, specific rules needs to be applied to the Firewall NetVM Networking NetVM. (ie: both is `sys-firewall` and `sys-net`, as currently done for manual port forwarding). The main issue however is the fact that currenly, the firewall client library is designated to operate only on the AppVM configured Firewall NetVM. However, in order to forward ports from the outside world, specific rules needs to be applied to the Firewall NetVM Networking NetVM. (ie: both is `sys-firewall` and `sys-net`, as currently done for manual port forwarding).
### action=forward ### action=forward
Since in the case of port forwarding the target ip address would always be the `<vmname>` IP address, users should not be asked for a `dsthost` field. Adding a forward rule could look like this: Since in the case of port forwarding the target ip address would always be the `<vmname>` IP address, users should not be asked for a `dsthost` field. Adding a forward rule could look like this:
``` ```
qvm-firewall <vmname> add action=forward proto=tcp forwardtype=external srcports=443-443 dstports=80443-80443 srchost=0.0.0.0/0 expire=+500000 comment="example https server rule" qvm-firewall <vmname> add action=forward proto=tcp forwardtype=external srcports=443-443 dstports=80443-80443 srchost=0.0.0.0/0 expire=+500000 comment="example https server rule"
qvm-firewall <vmname> add action=forward proto=tcp forwardtype=internal srcports=80-80 dstports=8000-8000 srchost=10.137.0.13 expire=+500000 comment="example internal simplehttpserver file sharing rule" qvm-firewall <vmname> add action=forward proto=tcp forwardtype=internal srcports=80-80 dstports=8000-8000 srchost=10.137.0.13 expire=+500000 comment="example internal simplehttpserver file sharing rule"
``` ```
Of course `expire=` and `comment=` are optional fields. Of course `expire=` and `comment=` are optional fields.
``` ```
<rule> <rule>
<properties> <properties>
<!-- sample syntax for port forwarding --> <!-- sample syntax for port forwarding -->
<property name="action">forward</property> <property name="action">forward</property>
<property name="proto">tcp</property> <property name="proto">tcp</property>
<property name="forwardtype">external</property> <property name="forwardtype">external</property>
<property name="srcports">443-443</property> <property name="srcports">443-443</property>
<property name="dstports">80443-80443</property> <property name="dstports">80443-80443</property>
<property name="srchost">0.0.0.0/0</property> <property name="srchost">0.0.0.0/0</property>
<property name="comment">example https server rule</property> <property name="comment">example https server rule</property>
</properties> </properties>
</rule> </rule>
``` ```
### Proposal chart ### Proposal chart
###### The main distinction between internal and external port forwarding is: ###### The main distinction between internal and external port forwarding is:
* _Internal_ resolves only `<appvm>`'s `<ntvm>` * _Internal_ resolves only `<appvm>`'s `<ntvm>`
* _External_ recursively resolves all upstream networking vm and sets forwarding rules on all of them * _External_ recursively resolves all upstream networking vm and sets forwarding rules on all of them
###### This should cover multiple scenarios: ###### This should cover multiple scenarios:
* _Standard external forwarding_ when `<appvm>` service needs to be exposed on a physical interface * _Standard external forwarding_ when `<appvm>` service needs to be exposed on a physical interface
* _Standard internal forwarding_ when `<appvm>` service needs to be exposed to other `<appvm2/3/4>` connected to the same `<netvm>` * _Standard internal forwarding_ when `<appvm>` service needs to be exposed to other `<appvm2/3/4>` connected to the same `<netvm>`
* _VPN internal port forwarding_ when `<appvm>` service needs to be exposed through a VPN * _VPN internal port forwarding_ when `<appvm>` service needs to be exposed through a VPN
It is important to note that in the last case, it is just a standard case of internal forwarding. It is important to note that in the last case, it is just a standard case of internal forwarding.
![Implementation](https://git.lsd.cat/Qubes/gsoc/raw/master/assets/implementation.png) ![Implementation](https://git.lsd.cat/Qubes/gsoc/raw/master/assets/implementation.png)
### Implementation Roadmap ### Implementation Roadmap
1. ✔️ In `core-admin-client/qubesadmin/firewall.py` firewall.py > The code 1. ✔️ In `core-admin-client/qubesadmin/firewall.py` firewall.py > The code
needs to support the new options for the rule (action=forward needs to support the new options for the rule (action=forward
frowardtype=<internal/external> srcports=443-443 srchosts=0.0.0.0/0 frowardtype=<internal/external> srcports=443-443 srchosts=0.0.0.0/0
2. ✔️ In `core-admin/qubes/firewall.py` -> The code needs to support the same 2. ✔️ In `core-admin/qubes/firewall.py` -> The code needs to support the same
options as the point above options as the point above
3. 🚧 In `core-admin/qubes/vm/mix/net.py` -> The most important logic goes 3. 🚧 In `core-admin/qubes/vm/mix/net.py` -> The most important logic goes
here. Here there is the need to resolve the full network chain for here. Here there is the need to resolve the full network chain for
external port forwarding. From here it is possible to add the respective external port forwarding. From here it is possible to add the respective
rules to the QubesDB of each NetVM in he chain and trigger a reload event. rules to the QubesDB of each NetVM in he chain and trigger a reload event.
4. ❌ In `core-agent-linux/qubesagent/firewall.py` -> Here goes the logic for 4. ❌ In `core-agent-linux/qubesagent/firewall.py` -> Here goes the logic for
building the correct syntax for iptables or nft and the actual execution building the correct syntax for iptables or nft and the actual execution
5. ❌ GUI\ 5. ❌ GUI\
\ \
\ \
### Required rules ### Required rules
#### External #### External
***srchost and srcports support yet to be written here *** ***srchost and srcports support yet to be written here ***
In `<networkvm>`: In `<networkvm>`:
``` ```
iptables -t nat -A PREROUTING -i <external_iinterface> -p tcp --dport <target_port> -d <interface_ip> -j DNAT --to-destination <firewallvm_ip> iptables -t nat -A PREROUTING -i <external_iinterface> -p tcp --dport <target_port> -d <interface_ip> -j DNAT --to-destination <firewallvm_ip>
iptables -I FORWARD 2 -i <external_iinterface> -d <firewallvm_ip> -p tcp --dport <target_port> -m conntrack --ctstate NEW -j ACCEPT iptables -I FORWARD 2 -i <external_iinterface> -d <firewallvm_ip> -p tcp --dport <target_port> -m conntrack --ctstate NEW -j ACCEPT
nft add rule ip qubes-firewall forward meta iifname <external_iinterface> ip daddr <firewallvm_ip> tcp dport <target_port> ct state new counter accept nft add rule ip qubes-firewall forward meta iifname <external_iinterface> ip daddr <firewallvm_ip> tcp dport <target_port> ct state new counter accept
``` ```
In `<firewallvm>`: In `<firewallvm>`:
``` ```
iptables -t nat -A PREROUTING -i <interface> -p tcp --dport <target_port> -d <firewallvm_ip> -j DNAT --to-destination <appvm_ip> iptables -t nat -A PREROUTING -i <interface> -p tcp --dport <target_port> -d <firewallvm_ip> -j DNAT --to-destination <appvm_ip>
iptables -I FORWARD 2 -i <interface> -d <appvm_ip> -p tcp --dport <target_port> -m conntrack --ctstate NEW -j ACCEPT iptables -I FORWARD 2 -i <interface> -d <appvm_ip> -p tcp --dport <target_port> -m conntrack --ctstate NEW -j ACCEPT
nft add rule ip qubes-firewall forward meta iifname <interface> ip daddr <appvm_ip> tcp dport <target_port> ct state new counter accept nft add rule ip qubes-firewall forward meta iifname <interface> ip daddr <appvm_ip> tcp dport <target_port> ct state new counter accept
``` ```
in `<appvm>`: in `<appvm>`:
``` ```
iptables -w -I INPUT 5 -d <appvm_ip> -p tcp --dport <target_port> -m conntrack --ctstate NEW -j ACCEPT iptables -w -I INPUT 5 -d <appvm_ip> -p tcp --dport <target_port> -m conntrack --ctstate NEW -j ACCEPT
``` ```
#### Internal #### Internal
In `<firewallvm>`: In `<firewallvm>`:
``` ```
iptables -t nat -A PREROUTING -i <interface> -p tcp --dport <target_port> -d <firewallvm_ip> -j DNAT --to-destination <appvm_ip> iptables -t nat -A PREROUTING -i <interface> -p tcp --dport <target_port> -d <firewallvm_ip> -j DNAT --to-destination <appvm_ip>
iptables -I FORWARD 2 -i <interface> -d <appvm_ip> -p tcp --dport <target_port> -m conntrack --ctstate NEW -j ACCEPT iptables -I FORWARD 2 -i <interface> -d <appvm_ip> -p tcp --dport <target_port> -m conntrack --ctstate NEW -j ACCEPT
nft add rule ip qubes-firewall forward meta iifname <interface> ip daddr <appvm_ip> tcp dport <target_port> ct state new counter accept nft add rule ip qubes-firewall forward meta iifname <interface> ip daddr <appvm_ip> tcp dport <target_port> ct state new counter accept
``` ```
in `<appvm>`: in `<appvm>`:
``` ```
iptables -w -I INPUT 5 -d <appvm_ip> -p tcp --dport <target_port> -m conntrack --ctstate NEW -j ACCEPT iptables -w -I INPUT 5 -d <appvm_ip> -p tcp --dport <target_port> -m conntrack --ctstate NEW -j ACCEPT
``` ```
## Extra ## Extra
### Useful Commands ### Useful Commands
``` ```
# #
# #
``` ```
### Flags ### Flags
Flags explanation as produced from the `qvm-ls` utility: Flags explanation as produced from the `qvm-ls` utility:
``` ```
Type of domain (When it is HVM, the letter is capital). Type of domain (When it is HVM, the letter is capital).
0 AdminVM (AKA Dom0) 0 AdminVM (AKA Dom0)
aA AppVM aA AppVM
dD DisposableVM dD DisposableVM
sS StandaloneVM sS StandaloneVM
tT TemplateVM tT TemplateVM
Current power state. Current power state.
r running r running
t transient t transient
p paused p paused
s suspended s suspended
h halting h halting
d dying d dying
c crashed c crashed
? unknown ? unknown
Extra Extra
U updateable U updateable
N provides_network N provides_network
R installed_by_rpm R installed_by_rpm
i internal i internal
D debug D debug
A autostart A autostart
``` ```
### Dev Environment ### Dev Environment
Currently developing on VMWare Workstation on Windows due to issues in virtualizing on linux on my home hardware. Currently developing on VMWare Workstation on Windows due to issues in virtualizing on linux on my home hardware.
QubesOS is virtualized behind NAT and can reach Windows Host via SSH. QubesOS is virtualized behind NAT and can reach Windows Host via SSH.
In order to the the code, I wrote some [helper scripts](https://git.lsd.cat/Qubes/tools). In order to the the code, I wrote some [helper scripts](https://git.lsd.cat/Qubes/tools).
The required setup involves: The required setup involves:
* Clone the tools on the Windows Host * Clone the tools on the Windows Host
* Generate an SSH keypair on `sys-net` * Generate an SSH keypair on `sys-net`
* Add `sys-net` SSH pubkey on Windows for non interactive authentication (`sshd` is easier using Windows Subsystem for Linux) * Add `sys-net` SSH pubkey on Windows for non interactive authentication (`sshd` is easier using Windows Subsystem for Linux)
* Via scp/sftp, copy all the bash script in the `sys-net` VM. Leve `pull.sh` in `/home/user/pull.sh` * Via scp/sftp, copy all the bash script in the `sys-net` VM. Leve `pull.sh` in `/home/user/pull.sh`
* Using `qvm-run` copy `backup.sh`, `restore.sh` and `updte.sh` in `Dom0` * Using `qvm-run` copy `backup.sh`, `restore.sh` and `updte.sh` in `Dom0`
* First, run once `backup.sh` and pay attention to never run it again in order to recover from broken states (breaking qubesd, `qvm-run` will stop working and it will be hard to recover) * First, run once `backup.sh` and pay attention to never run it again in order to recover from broken states (breaking qubesd, `qvm-run` will stop working and it will be hard to recover)
* Run `update.sh` to automatically pull changes from the Windows host. `qubesd` is restarted within the same script. * Run `update.sh` to automatically pull changes from the Windows host. `qubesd` is restarted within the same script.
* In case of issues, run `restore.sh` and investigate the previous errors * In case of issues, run `restore.sh` and investigate the previous errors