Merge branch 'opnsense:master' into ipv6fb
@ -1,213 +0,0 @@
|
||||
=======
|
||||
HAProxy
|
||||
=======
|
||||
|
||||
------------
|
||||
Installation
|
||||
------------
|
||||
|
||||
First of all, you have to install the HAProxy plugin (os-haproxy) from the
|
||||
plugins view.
|
||||
|
||||
.. image:: ../images/menu_plugins.png
|
||||
|
||||
-------------------------------------
|
||||
First Step: Configure Backend Servers
|
||||
-------------------------------------
|
||||
|
||||
.. image:: images/haproxy_servers.png
|
||||
|
||||
On the "Servers" page, click `+` to open a dialog to create a new server.
|
||||
A server consist of a name, IP and port.
|
||||
Create an entry for every Server you want to load balance.
|
||||
|
||||
.. image:: images/haproxy_edit_server.png
|
||||
|
||||
For a HTTP Backend, configure like this:
|
||||
|
||||
========================== ===========================
|
||||
**Name** Name of this server
|
||||
**Description** Keep it empty
|
||||
**FQDN or IP** Enter the IP of your Server
|
||||
**Port** Port of the Server
|
||||
**SSL** Keep the default (disabled)
|
||||
**Verify SSL Certificate** Keep the default (checked)
|
||||
**SSL Verify CA** Keep the default (empty)
|
||||
========================== ===========================
|
||||
|
||||
--------------------------------
|
||||
Second Step: Configure a Backend
|
||||
--------------------------------
|
||||
|
||||
Now, as we have the backend services,
|
||||
we can build a backend by combining them to groups of
|
||||
servers, which will serve the same service.
|
||||
For example if you are hosting a Webservice and want to
|
||||
scale horizontally, every server in the cluster will be
|
||||
a "Server", but they will be combined to a so called
|
||||
"Backend", so HAProxy can load balance between them.
|
||||
|
||||
To create a new Backend, click the `+`.
|
||||
|
||||
|
||||
.. image:: images/haproxy_backends.png
|
||||
|
||||
And fill out the form:
|
||||
|
||||
.. image:: images/haproxy_edit_backend.png
|
||||
|
||||
.. Note::
|
||||
The "Balancing Algorithm" field is important to care about as many
|
||||
web applications depend on a state.
|
||||
For example, if your web application stores session data on a local
|
||||
disk, you may get some trouble when using an algorithm like Round
|
||||
Robin. In such a case, the request of the same client always needs
|
||||
to be sent to the same backend servers.
|
||||
For example by default PHP stores session data in files while Ruby
|
||||
on Rails stores session information in a cookie by default.
|
||||
Please look up your web framework documentation for information how
|
||||
this is handled. Consider writeing files as problematic as well if
|
||||
there is no shared storage.
|
||||
|
||||
======================= ===============================================
|
||||
**Enabled** Enable the Backend (checked)
|
||||
**Name** Enter a name for the Backend
|
||||
**Description** Enter an optional description
|
||||
**Mode** Select the mode HTTP as this is an HTTP backend
|
||||
**Balancing Algorithm** Select an load balancing algorithm
|
||||
**Servers** Select the previously configured servers
|
||||
======================= ===============================================
|
||||
|
||||
--------------------------------
|
||||
Third Step: Configure Conditions
|
||||
--------------------------------
|
||||
|
||||
In this step an Condition will has to be created which is later used to decide
|
||||
which traffic from a frontend belongs to which backend.
|
||||
|
||||
To create a new Condition, you have to go to "Rules & Checks -> Conditions"
|
||||
and create one by clicking the `+` button:
|
||||
|
||||
(Picture is from Previous Version but it still looks as good as the same)
|
||||
|
||||
.. image:: images/haproxy_acls.png
|
||||
|
||||
In the open modal dialog, the following form will show up:
|
||||
|
||||
.. image:: images/haproxy_edit_acl.png
|
||||
|
||||
==================== ================================================
|
||||
**Name** Choose a name for this Condition
|
||||
**Description** Keep it empty or choose one for your information
|
||||
**Expression** Select "Host contains"
|
||||
**Negate condition** Keep it unchecked
|
||||
**Value** Enter the (partial) hostname to compare
|
||||
==================== ================================================
|
||||
|
||||
Click "Save changes".
|
||||
|
||||
---------------------------------------
|
||||
Fourth Step: Configure an Rule
|
||||
---------------------------------------
|
||||
|
||||
As promised in the previous step, the Conditions will be used.
|
||||
A Rule can use multiple conditions to decide which Rule is going to be used.
|
||||
To create a new Rule, you have to go to "Rules & Checks -> Rules"
|
||||
and create one by clicking the `+` button:
|
||||
|
||||
(Picture is from Previous Version but it still looks as good as the same)
|
||||
|
||||
.. image:: images/haproxy_actions.png
|
||||
|
||||
A form dialog opens and we can fill it out like the following:
|
||||
|
||||
(Picture is from Previous Version but it still looks as good as the same)
|
||||
|
||||
.. image:: images/haproxy_edit_action.png
|
||||
|
||||
.. Note::
|
||||
You can map multiple Hostnames to the same Backend by adding multiple
|
||||
ACLs and choosing the logical operator "OR".
|
||||
|
||||
==================== ===================================
|
||||
**Name** Choose a name for this Action
|
||||
**Description** You can add an optional description
|
||||
**Test Type** Keep it at the default ("IF")
|
||||
**Select ACLs** Select the ACLs to be used
|
||||
**Logical operator** Keep the default ("AND")
|
||||
**Choose action** Choose "Use Backend"
|
||||
**Use Server** Keep the default ("none")
|
||||
==================== ===================================
|
||||
|
||||
-------------------------------
|
||||
Fifth Step Configure a frontend
|
||||
-------------------------------
|
||||
|
||||
Now its nearly done. The only thing that needs to be configured for HAProxy
|
||||
is a Public Service.
|
||||
A Public Service is a a group of bound ports which are used for incoming connections.
|
||||
From this Public Service we need to know which backend the request will routed to.
|
||||
For this, the previously configured action is needed.
|
||||
If you got multiple domains with the same port on one IP, you differentiate them with rules!
|
||||
Don't create multiple Public Services. For example, if you only want to forward example.org:80 and example.com:80, just create one Public Service. If you want to forward example.org:80, example.org:443, example.com:80, and example.com:443, create only two Public Services, one for port 80 (example.org and example.com) and one for port 443 (example.org and example.com).
|
||||
|
||||
To create a new Public Service, click the `+` button:
|
||||
|
||||
(Picture is from Previous Version but it still looks as good as the same)
|
||||
|
||||
.. image:: images/haproxy_frontends.png
|
||||
|
||||
The following modal dialog opens and the frontend can be set up:
|
||||
|
||||
.. image:: images/haproxy_edit_frontend.png
|
||||
|
||||
.. Warning::
|
||||
If you configure a port that is already in use, the configuration test
|
||||
will be successful but the start of HAProxy will fail silently.
|
||||
Please ensure that the used port is free - especially if the number
|
||||
conflicts with the web configuration of OPNsense.
|
||||
|
||||
|
||||
General Settings
|
||||
================
|
||||
|
||||
=================== ===========================================================================
|
||||
**Enabled** Checked
|
||||
**Name** Use any name
|
||||
**Description** You may keep it empty
|
||||
**Listen Address** Enter one or more host:port combinations, use 0.0.0.0:80 for HTTP via IPv4
|
||||
**Type** Choose HTTP / HTTPS
|
||||
**Default Backend** Keep the default of "None"
|
||||
=================== ===========================================================================
|
||||
|
||||
Advanced settings
|
||||
=================
|
||||
|
||||
Enbable the X-Forwarded-For-header so the backend will know the real IP of
|
||||
the client.
|
||||
|
||||
Actions (ACLs)
|
||||
==============
|
||||
|
||||
Here you have to activate the previously configured actions, so HAProxy
|
||||
is going to operate based due the rules/conditions.
|
||||
|
||||
All other Options
|
||||
=================
|
||||
|
||||
Keep all other options at the default
|
||||
|
||||
----------------------------
|
||||
Sixth step: Enable and start
|
||||
----------------------------
|
||||
|
||||
This is the last step - on the General tab, we will enable the service
|
||||
after a config test.
|
||||
|
||||
.. image:: images/haproxy_general.png
|
||||
|
||||
For that, the "Enable HAProxy" checkbox needs to be checked.
|
||||
|
||||
On this screen, check "Enable HAProxy" and click "Apply".
|
||||
If everything went OK HAProxy will start.
|
||||
Now you need to configure firewall rules for accessing your HAProxy instance.
|
@ -1,85 +0,0 @@
|
||||
HAProxy How-Tos
|
||||
===============
|
||||
|
||||
Redirect Root directory
|
||||
-----------------------
|
||||
|
||||
Create a condition:
|
||||
|
||||
.. image:: images/haproxy_root_path_condition.png
|
||||
|
||||
============== ==============
|
||||
name root
|
||||
Condition type Path matches
|
||||
Path matches /
|
||||
============== ==============
|
||||
|
||||
Create a Rule:
|
||||
|
||||
.. image:: images/haproxy_forward_to_dir_rule.png
|
||||
|
||||
======================= ===================================================
|
||||
name forward_to_dir
|
||||
Test type IF
|
||||
conditions root
|
||||
Logical ops none
|
||||
Execute function http-request redirect
|
||||
HTTP Redirect parameter code 301 location http://www.example.net/directory/
|
||||
======================= ===================================================
|
||||
|
||||
Please note that 301 is for a permanent redirect. If you want to do it teporary,
|
||||
you will have to use another status code.
|
||||
|
||||
|
||||
|
||||
Under Public Services edit your frontend and add "forward_to_dir" to Select Rules.
|
||||
|
||||
.. image:: images/haproxy_forward_to_dir_service.png
|
||||
|
||||
|
||||
Add Basic Authentication to a Service
|
||||
-------------------------------------
|
||||
|
||||
I have a Webapplication which have to be exposed to the outside and doesn't allow authentication.
|
||||
So HAProxy with basic auth would be just fine to get a mininum of security.
|
||||
|
||||
* Go to "Rules & Conditions" - "Conditions" and Add a new one:
|
||||
|
||||
.. image:: images/haproxy_condition_add_authentication.png
|
||||
|
||||
=================== =================
|
||||
name choose a name
|
||||
Condition type Custom
|
||||
option pass-through http_auth(admins)
|
||||
=================== =================
|
||||
|
||||
* Add a rule:
|
||||
|
||||
.. image:: images/haproxy_edit_rule_authentication.png
|
||||
|
||||
================ =================================
|
||||
name a name for your rule
|
||||
Test type UNLESS
|
||||
condition select the previously created one
|
||||
Logical operator none
|
||||
Execute function http-request auth"
|
||||
================ =================================
|
||||
|
||||
* Go to your frontend and add the ACL to it.
|
||||
|
||||
.. image:: images/haproxy_frontend_add_authentication.png
|
||||
|
||||
|
||||
* Go to :menuselection:`Settings --> Global Parameters`, enable the advanced mode (top left), and add your users to configuration
|
||||
via the "Custom options"
|
||||
|
||||
.. image:: images/haproxy_settings_global_params_auth.png
|
||||
|
||||
|
||||
.. code-block:: none
|
||||
|
||||
userlist admins
|
||||
user test1 insecure-password pw1
|
||||
user test2 insecure-password pw2
|
||||
|
||||
|
Before Width: | Height: | Size: 52 KiB |
Before Width: | Height: | Size: 52 KiB |
Before Width: | Height: | Size: 52 KiB |
Before Width: | Height: | Size: 35 KiB |
Before Width: | Height: | Size: 28 KiB |
Before Width: | Height: | Size: 98 KiB |
Before Width: | Height: | Size: 110 KiB |
Before Width: | Height: | Size: 106 KiB |
Before Width: | Height: | Size: 38 KiB |
Before Width: | Height: | Size: 24 KiB |
Before Width: | Height: | Size: 43 KiB |
Before Width: | Height: | Size: 5.5 KiB |
Before Width: | Height: | Size: 6.3 KiB |
Before Width: | Height: | Size: 25 KiB |
Before Width: | Height: | Size: 22 KiB |
Before Width: | Height: | Size: 28 KiB |
Before Width: | Height: | Size: 57 KiB |
Before Width: | Height: | Size: 71 KiB |
@ -0,0 +1,69 @@
|
||||
=============================================
|
||||
IPS Bypass local traffic from inspection
|
||||
=============================================
|
||||
|
||||
.. Note:: This tutorial explains how to bypass traffic between local attached networks. Following this tutorial will result in traffic only being inspected between external (WAN) networks and internal (LAN) networks. With bypass enabled, routing performance is improved significantly between local networks while IPS is used.
|
||||
.. Tip:: If you only have 1 interface selected in Intrusion Detection, you don't have to follow this tutorial. There won't be any performance benefit.
|
||||
.. Warning:: Traffic between local networks won't be inspected anymore, so use this with care!
|
||||
|
||||
-------------
|
||||
Prerequisites
|
||||
-------------
|
||||
|
||||
- Some features described on this page were added in the latest version. Always keep your system up to date.
|
||||
- Intrusion Detection should be **enabled** and **IPS mode** selected.
|
||||
- Only **internal networks** should be selected in **Interfaces** (LAN, OPT1 etc..), **not the WAN interface**.
|
||||
|
||||
-----------------
|
||||
Create new Rules
|
||||
-----------------
|
||||
|
||||
To start go to :menuselection:`Services --> Intrusion Detection --> Administration` and select the tab :menuselection:`User defined`.
|
||||
|
||||
Select **+** to add a new rule.
|
||||
|
||||
- Input the **Source IP** with CIDR-Suffix, e.g. ``10.0.0.0/8``
|
||||
- Input the **Destination IP** with CIDR-Suffix, e.g. ``10.0.0.0/8``
|
||||
- Select the **Action** as *Pass*
|
||||
- Enable the **Bypass** checkbox
|
||||
- Set the **Description** as "Bypass net 10.0.0.0 to 10.0.0.0"
|
||||
|
||||
Select **+** or **clone** to create additional new rules.
|
||||
|
||||
* Repeat the above steps to create rules between each of the RFC1918 Private IPv4 subnets, ``192.168.0.0/16``, ``172.16.0.0/12``, ``10.0.0.0/8``. Don't forget to adjust the description.
|
||||
|
||||
.. Note:: The finished ruleset for IPv4 should include the following rules:
|
||||
|
||||
================== ================== ========== ========== ======================================
|
||||
**Source IP** **Destination IP** **Action** **Bypass** **Description**
|
||||
================== ================== ========== ========== ======================================
|
||||
10.0.0.0/8 10.0.0.0/8 Pass X Bypass net 10.0.0.0 to 10.0.0.0
|
||||
10.0.0.0/8 172.16.0.0/12 Pass X Bypass net 10.0.0.0 to 172.16.0.0
|
||||
10.0.0.0/8 192.168.0.0/16 Pass X Bypass net 10.0.0.0 to 192.168.0.0
|
||||
172.16.0.0/12 10.0.0.0/8 Pass X Bypass net 172.16.0.0 to 10.0.0.0
|
||||
172.16.0.0/12 172.16.0.0/12 Pass X Bypass net 172.16.0.0 to 172.16.0.0
|
||||
172.16.0.0/12 192.168.0.0/16 Pass X Bypass net 172.16.0.0 to 192.168.0.0
|
||||
192.168.0.0/16 10.0.0.0/8 Pass X Bypass net 192.168.0.0 to 10.0.0.0
|
||||
192.168.0.0/16 172.16.0.0/12 Pass X Bypass net 192.168.0.0 to 172.16.0.0
|
||||
192.168.0.0/16 192.168.0.0/16 Pass X Bypass net 192.168.0.0 to 192.168.0.0
|
||||
================== ================== ========== ========== ======================================
|
||||
|
||||
.. Tip::
|
||||
|
||||
- If you use IPv6 - e.g. with *Track Interface* or *Static IPv6* - create an additional rule.
|
||||
- You can find your *IPv6 prefix* in :menuselection:`Interfaces --> Overview --> WAN` - e.g ``2001:db8:a:aa00::/56``.
|
||||
- You only have to create 1 rule, because all of the *Track IPv6 Interface - IPv6 Prefix ID* networks - e.g. ``2001:db8:a:aa01::/64``, ``2001:db8:a:aa02::/64`` - are already included in the ``/56`` Prefix.
|
||||
- Please note that this only works if your Prefix is static.
|
||||
|
||||
-------------------
|
||||
Apply configuration
|
||||
-------------------
|
||||
|
||||
Apply the configuration by pressing the **Apply** button at the bottom of
|
||||
the form.
|
||||
|
||||
-------------------
|
||||
External Resources
|
||||
-------------------
|
||||
- https://docs.suricata.io/en/suricata-6.0.0/rules/bypass-keyword.html
|
||||
- https://docs.suricata.io/en/suricata-6.0.0/performance/ignoring-traffic.html
|
@ -0,0 +1,177 @@
|
||||
==========================
|
||||
Wazuh Agent
|
||||
==========================
|
||||
|
||||
--------------------------------------
|
||||
Introduction
|
||||
--------------------------------------
|
||||
|
||||
`Wazuh <https://wazuh.com/>`__ is an open source unified XDR (Extended Detection and Response) and SIEM (Security Information en Event Management)
|
||||
system capable of offering protection for endpoints and cloud workloads.
|
||||
|
||||
The Wazuh architecture is based on agents, running on the monitored endpoints, which collect information and are capable of
|
||||
executing active responses directed by the manager.
|
||||
|
||||
The goal of this plugin is to offer an easily installable plugin to connect to the Wazuh manager.
|
||||
|
||||
.. Note::
|
||||
The scope of Wazuh on OPNsense is only to offer configurable agent support. We do not plan nor advise to run the Wazuh
|
||||
central components on OPNsense. Detailed information on how to install these on supported platforms are available directly from the
|
||||
`Wazuh website <https://documentation.wazuh.com/current/installation-guide/index.html>`__
|
||||
or you can use their cloud based offering available `here <https://wazuh.com/cloud/>`__
|
||||
|
||||
|
||||
.. Warning::
|
||||
This plugin is provided "as-is" and with very limited [tier 3] community support from the OPNsense team. Using a SIEM/XDR system
|
||||
requires knowledge which usually is out of the (free) community support scope.
|
||||
|
||||
|
||||
--------------------------------------
|
||||
Installation
|
||||
--------------------------------------
|
||||
|
||||
Installation of this plugin is rather easy, go to :menuselection:`System --> Firmware --> Plugins` and search for **os-wazuh-agent**,
|
||||
use the [+] button to install it.
|
||||
|
||||
Next go to :menuselection:`Services --> Wazuh Agent --> Settings` to configure the service.
|
||||
|
||||
|
||||
.. Tip::
|
||||
When the ossec log offers too limited insights when debugging issues, try to increase the debug level. You can find this setting under
|
||||
General settings when "advanced mode" is enabled.
|
||||
|
||||
--------------------------------------
|
||||
Connecting the agent
|
||||
--------------------------------------
|
||||
|
||||
To connect the agent to the manager, just fill in a hostname under **General Settings/Manager hostname**, make sure
|
||||
the agent is marked enabled and optionally specify a connect password under **Authentication/Password**.
|
||||
|
||||
Next go to the manager to see if the agent registered itself.
|
||||
|
||||
|
||||
--------------------------------------
|
||||
Selecting which logs to ingest
|
||||
--------------------------------------
|
||||
|
||||
Our Wazuh agent plugin supports syslog targets like we use in the rest of the product, so if an application sends
|
||||
its feed to syslog and registers the application name as described in our `development documentation <https://docs.opnsense.org/development/backend/legacy.html#syslog>`__
|
||||
it can be selected to send to Wazuh as well.
|
||||
|
||||
For Intrusion detection we can send the events as well using the same (eve) datafeed used in OPNsense, just mark the
|
||||
**Intrusion detection events** in the general settings.
|
||||
|
||||
.. Note::
|
||||
Wazuh only supports `rfc3164 <https://datatracker.ietf.org/doc/html/rfc3164>`__ formatted syslog messages, for that reason
|
||||
we record a copy of the requested events into a file named :code:`/var/ossec/logs/opnsense_syslog.log` using that format.
|
||||
|
||||
|
||||
--------------------------------------
|
||||
Installing custom ossec.conf entries
|
||||
--------------------------------------
|
||||
|
||||
Some Wazuh modules are directly selectable from the gui, but when a feature is needed, which is not offered in the
|
||||
plugin, it's possible to add static sections manually.
|
||||
|
||||
You can add these in :code:`/usr/local/opnsense/service/templates/OPNsense/WazuhAgent/ossec_config.d/`, for example, to
|
||||
add a custom json feed, add a file containing the following content in there:
|
||||
|
||||
.. code-block:: xml
|
||||
:linenos:
|
||||
:caption: /usr/local/opnsense/service/templates/OPNsense/WazuhAgent/ossec_config.d/099-my-feed.conf
|
||||
|
||||
<localfile>
|
||||
<log_format>json</log_format>
|
||||
<location>/path/to/my/file.json</location>
|
||||
</localfile>
|
||||
|
||||
|
||||
--------------------------------------
|
||||
Use active responses
|
||||
--------------------------------------
|
||||
|
||||
Wazuh supports `active responses <https://documentation.wazuh.com/current/user-manual/capabilities/active-response/index.html>`__
|
||||
so the manager can direct defensive actions when needed. The plugin ships with one action named :code:`opnsense-fw` to
|
||||
drop traffic from a specified source address.
|
||||
|
||||
.. Note::
|
||||
|
||||
The opnsense-fw action is stateful and can add and delete addresses from the firewall, more context on these type
|
||||
of actions can be found in the `Wazuh <https://documentation.wazuh.com/current/user-manual/capabilities/active-response/custom-active-response-scripts.html>`__
|
||||
documentation.
|
||||
|
||||
|
||||
To use this action, you need to add some configuration in the manager, starting with the definition of this action.
|
||||
|
||||
.. code-block:: xml
|
||||
:linenos:
|
||||
:caption: /var/ossec/etc/ossec.conf
|
||||
|
||||
<ossec_config>
|
||||
<command>
|
||||
<name>opnsense-fw</name>
|
||||
<executable>opnsense-fw</executable>
|
||||
<timeout_allowed>yes</timeout_allowed>
|
||||
</command>
|
||||
</ossec_config>
|
||||
|
||||
After which you can use it in active-response rules, like this:
|
||||
|
||||
.. code-block:: xml
|
||||
:linenos:
|
||||
:caption: /var/ossec/etc/ossec.conf
|
||||
|
||||
<ossec_config>
|
||||
<active-response>
|
||||
<disabled>no</disabled>
|
||||
<command>opnsense-fw</command>
|
||||
<location>defined-agent</location>
|
||||
<agent_id>001</agent_id>
|
||||
<rules_id>100201</rules_id>
|
||||
<timeout>180</timeout>
|
||||
</active-response>
|
||||
</ossec_config>
|
||||
|
||||
|
||||
The official `documentation <https://documentation.wazuh.com/current/user-manual/capabilities/active-response/how-to-configure.html>`__
|
||||
contains more information about the options available.
|
||||
|
||||
.. Tip::
|
||||
Active responses are logged into :menuselection:`Services --> Wazuh Agent --> Logfile / active-responses`, including
|
||||
the messages received from the manager.
|
||||
|
||||
|
||||
To quickly test if an active-response can be executed on the agent, we advise to use the API console under :menuselection:`Wazuh --> Tools --> API console`.
|
||||
Executing the :code:`opnsense-fw` command for address :code:`172.16.1.30` on agent :code:`001` can be done using:
|
||||
|
||||
.. code-block:: xml
|
||||
:linenos:
|
||||
|
||||
PUT /active-response?agents_list=001
|
||||
{
|
||||
"command": "!opnsense-fw",
|
||||
"custom": false,
|
||||
"alert": {
|
||||
"data": {
|
||||
"srcip": "172.16.1.30"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.. Tip::
|
||||
|
||||
Wazuh offers quite some `proof of concept <https://documentation.wazuh.com/current/proof-of-concept-guide/index.html>`__ documents and blog posts,
|
||||
like `this <https://wazuh.com/blog/responding-to-network-attacks-with-suricata-and-wazuh-xdr/>`__
|
||||
document explaining how Suricata and Wazuh can be combined to respond to detected threats.
|
||||
|
||||
--------------------------------------
|
||||
Test rule detection
|
||||
--------------------------------------
|
||||
|
||||
In case log entries are being collected in :code:`/var/ossec/logs/opnsense_syslog.log` and no events are being collected
|
||||
in the Manager, it's usually a good idea to check how Wazuh processes these lines.
|
||||
|
||||
The :menuselection:`Wazuh --> Tools --> Ruleset test` menu item in the manager offers an easy to use tool to inspect log
|
||||
events.
|
||||
|