Initial version of the freely available OPNsense documentation project, original commiters are listed in LICENSE file.

This commit is contained in:
jschellevis 2018-01-30 11:40:13 +01:00
parent ce7db8f1ae
commit 9aa470246f
417 changed files with 27530 additions and 10 deletions

26
.gitignore vendored Normal file
View File

@ -0,0 +1,26 @@
# OS generated files #
######################
.DS_Store
.DS_Store?
._*
.Spotlight-V100
.Trashes
ehthumbs.db
Thumbs.db
# Tools #
#########
update.sh
xcode_install.sh
# Non source files #
###################
build/
bower_components/
.sass-cache
*.pyc
log/
old/
.idea/

15
LICENSE
View File

@ -1,4 +1,6 @@
# docs
# OPNsense documentation
The documentation is licensed under a 2-clause BSD Licnse:
Copyright (c) Deciso B.V.
Copyright (c) 2017-2018 Fabian Franz
Copyright (c) 2017-2018 Michael Muenz
@ -28,3 +30,14 @@ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS DOCUMENTATION, EVEN IF
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
# Pictures
Some pictures are licensed under the Creative Commons Zero (CC0) license:
https://creativecommons.org/publicdomain/zero/1.0/
# Logo's
Logo's may be subject to additional copyrights, property
rights, trademarks etc. and may require the consent of a third party or the
license of these rights. Deciso B.V. does not represent or make any warranties
that it owns or licenses any of the mentioned, nor does it grant them.

219
Makefile Normal file
View File

@ -0,0 +1,219 @@
# Makefile for Sphinx documentation
#
# You can set these variables from the command line.
SPHINXOPTS =
SPHINXBUILD = sphinx-build
PAPER =
BUILDDIR = build
# User-friendly check for sphinx-build
ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1)
$(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/)
endif
# Internal variables.
PAPEROPT_a4 = -D latex_paper_size=a4
PAPEROPT_letter = -D latex_paper_size=letter
ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source
# the i18n builder cannot share the environment and doctrees with the others
I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source
.PHONY: help
help:
@echo "Please use \`make <target>' where <target> is one of"
@echo " html to make standalone HTML files"
@echo " dirhtml to make HTML files named index.html in directories"
@echo " singlehtml to make a single large HTML file"
@echo " pickle to make pickle files"
@echo " json to make JSON files"
@echo " htmlhelp to make HTML files and a HTML help project"
@echo " qthelp to make HTML files and a qthelp project"
@echo " applehelp to make an Apple Help Book"
@echo " devhelp to make HTML files and a Devhelp project"
@echo " epub to make an epub"
@echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
@echo " latexpdf to make LaTeX files and run them through pdflatex"
@echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx"
@echo " text to make text files"
@echo " man to make manual pages"
@echo " texinfo to make Texinfo files"
@echo " info to make Texinfo files and run them through makeinfo"
@echo " gettext to make PO message catalogs"
@echo " changes to make an overview of all changed/added/deprecated items"
@echo " xml to make Docutils-native XML files"
@echo " pseudoxml to make pseudoxml-XML files for display purposes"
@echo " linkcheck to check all external links for integrity"
@echo " doctest to run all doctests embedded in the documentation (if enabled)"
@echo " coverage to run coverage check of the documentation (if enabled)"
.PHONY: clean
clean:
rm -rf $(BUILDDIR)/*
.PHONY: html
html:
$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
@echo
@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
.PHONY: html-fallback
html-fallback:
python3 /usr/bin/sphinx-build -b html source build
.PHONY: dirhtml
dirhtml:
$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
@echo
@echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
.PHONY: singlehtml
singlehtml:
$(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
@echo
@echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
.PHONY: pickle
pickle:
$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
@echo
@echo "Build finished; now you can process the pickle files."
.PHONY: json
json:
$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
@echo
@echo "Build finished; now you can process the JSON files."
.PHONY: htmlhelp
htmlhelp:
$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
@echo
@echo "Build finished; now you can run HTML Help Workshop with the" \
".hhp project file in $(BUILDDIR)/htmlhelp."
.PHONY: qthelp
qthelp:
$(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
@echo
@echo "Build finished; now you can run "qcollectiongenerator" with the" \
".qhcp project file in $(BUILDDIR)/qthelp, like this:"
@echo "# qcollectiongenerator $(BUILDDIR)/qthelp/OPNsense.qhcp"
@echo "To view the help file:"
@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/OPNsense.qhc"
.PHONY: applehelp
applehelp:
$(SPHINXBUILD) -b applehelp $(ALLSPHINXOPTS) $(BUILDDIR)/applehelp
@echo
@echo "Build finished. The help book is in $(BUILDDIR)/applehelp."
@echo "N.B. You won't be able to view it unless you put it in" \
"~/Library/Documentation/Help or install it in your application" \
"bundle."
.PHONY: devhelp
devhelp:
$(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
@echo
@echo "Build finished."
@echo "To view the help file:"
@echo "# mkdir -p $$HOME/.local/share/devhelp/OPNsense"
@echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/OPNsense"
@echo "# devhelp"
.PHONY: epub
epub:
$(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
@echo
@echo "Build finished. The epub file is in $(BUILDDIR)/epub."
.PHONY: latex
latex:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo
@echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
@echo "Run \`make' in that directory to run these through (pdf)latex" \
"(use \`make latexpdf' here to do that automatically)."
.PHONY: latexpdf
latexpdf:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo "Running LaTeX files through pdflatex..."
$(MAKE) -C $(BUILDDIR)/latex all-pdf
@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
.PHONY: latexpdfja
latexpdfja:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo "Running LaTeX files through platex and dvipdfmx..."
$(MAKE) -C $(BUILDDIR)/latex all-pdf-ja
@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
.PHONY: text
text:
$(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
@echo
@echo "Build finished. The text files are in $(BUILDDIR)/text."
.PHONY: man
man:
$(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
@echo
@echo "Build finished. The manual pages are in $(BUILDDIR)/man."
.PHONY: texinfo
texinfo:
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
@echo
@echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
@echo "Run \`make' in that directory to run these through makeinfo" \
"(use \`make info' here to do that automatically)."
.PHONY: info
info:
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
@echo "Running Texinfo files through makeinfo..."
make -C $(BUILDDIR)/texinfo info
@echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
.PHONY: gettext
gettext:
$(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
@echo
@echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
.PHONY: changes
changes:
$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
@echo
@echo "The overview file is in $(BUILDDIR)/changes."
.PHONY: linkcheck
linkcheck:
$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
@echo
@echo "Link check complete; look for any errors in the above output " \
"or in $(BUILDDIR)/linkcheck/output.txt."
.PHONY: doctest
doctest:
$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
@echo "Testing of doctests in the sources finished, look at the " \
"results in $(BUILDDIR)/doctest/output.txt."
.PHONY: coverage
coverage:
$(SPHINXBUILD) -b coverage $(ALLSPHINXOPTS) $(BUILDDIR)/coverage
@echo "Testing of coverage in the sources finished, look at the " \
"results in $(BUILDDIR)/coverage/python.txt."
.PHONY: xml
xml:
$(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml
@echo
@echo "Build finished. The XML files are in $(BUILDDIR)/xml."
.PHONY: pseudoxml
pseudoxml:
$(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml
@echo
@echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml."

View File

@ -1,18 +1,15 @@
# docs
OPNsense documentation
======================
The OPNsense project invites developers and users to start
contributing to the documentation.
![alt text](https://opnsense.org/wp-content/themes/OPNsense/assets/img/opnsense.png "Logo Title Text 1")
Contribute
==========
# OPNsense documentation
Welcome to the OPNsense documentation & wiki.
The purpose of this project is to provide OPNsense users with quality documentation.
## Contribute
You can contribute to the project in many ways, e.g. testing
functionality, sending in bug reports or creating pull requests
directly via GitHub. Any help is always very welcome!
License
=======
## License
OPNsense documentation is available under the 2-Clause BSD license:
http://opensource.org/licenses/BSD-2-Clause
@ -24,3 +21,49 @@ for everybody.
Some pictures are licensed under the Creative Commons Zero (CC0) license:
https://creativecommons.org/publicdomain/zero/1.0/
Logo's may be subject to additional copyrights, property
rights, trademarks etc. and may require the consent of a third party or the
license of these rights. Deciso B.V. does not represent or make any warranties
that it owns or licenses any of the mentioned, nor does it grant them.
#### Prepare build
Install Sphinx, our default theme and contrib packages
```
pip install -r requirements.txt
```
#### Generate HTML documents
```
make html
```
(```make clean``` to flush)
#### Changing theme
* Install Sass (http://sass-lang.com/), on OSX via ```/Library/Ruby/Gems```
```
gem install --no-user-install sass
```
* Install npm (https://www.npmjs.com/get-npm)
* Install Bower (https://bower.io/)
```
npm install -g bower
```
Install required stylesheets using bower
```
bower install wyrm
bower install robotoslab-googlefont
bower install inconsolata-googlefont
bower install font-awesome
```
(for font-awesome, choose newest)
#### Build your theme:
```
sass -I bower_components/wyrm/sass/ -I bower_components/bourbon/dist/ -I bower_components/neat/app/assets/stylesheets/ -I bower_components/font-awesome/scss/ themes/opnsense/sass/theme.sass > source/_static/css/opnsense.css

8
requirements.txt Normal file
View File

@ -0,0 +1,8 @@
sphinx
sphinx_rtd_theme
sphinxcontrib-blockdiag
sphinxcontrib-nwdiag
sphinxcontrib-seqdiag
sphinxcontrib-actdiag
sphinxcontrib-inheritance
blockdiagcontrib-cisco

File diff suppressed because it is too large Load Diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

BIN
source/_static/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 361 KiB

BIN
source/_static/favicon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

382
source/conf.py Normal file
View File

@ -0,0 +1,382 @@
# -*- coding: utf-8 -*-
#
# OPNsense documentation build configuration file, created by
# sphinx-quickstart on Tue Jan 19 16:15:33 2016.
#
# This file is execfile()d with the current directory set to its
# containing dir.
#
# Note that not all possible configuration values are present in this
# autogenerated file.
#
# All configuration values have a default; values that are commented out
# serve to show the default.
import sys
import os
import sphinx_rtd_theme
html_theme_path = [sphinx_rtd_theme.get_html_theme_path()]
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
#sys.path.insert(0, os.path.abspath('.'))
# -- General configuration ------------------------------------------------
# If your documentation needs a minimal Sphinx version, state it here.
#needs_sphinx = '1.0'
# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
extensions = [
'sphinx.ext.todo',
'sphinxcontrib.blockdiag',
'sphinxcontrib.nwdiag',
'sphinxcontrib.seqdiag',
'sphinxcontrib.actdiag',
]
blockdiag_fontpath = '/Library/Fonts/Arial.ttf'
nwdiag_fontpath = '/Library/Fonts/Arial.ttf'
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
# The suffix(es) of source filenames.
# You can specify multiple suffix as a list of string:
# source_suffix = ['.rst', '.md']
source_suffix = '.rst'
# The encoding of source files.
#source_encoding = 'utf-8-sig'
# The master toctree document.
master_doc = 'index'
# General information about the project.
project = u'OPNsense'
copyright = u'2016, Deciso B.V'
author = u'Deciso B.V.'
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#
# The short X.Y version.
version = u'Wiki & Documentation'
# The full version, including alpha/beta/rc tags.
release = u'Wiki & Documentation'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
#
# This is also used if you do content translation via gettext catalogs.
# Usually you set "language" from the command line for these cases.
language = None
# There are two options for replacing |today|: either, you set today to some
# non-false value, then it is used:
#today = ''
# Else, today_fmt is used as the format for a strftime call.
#today_fmt = '%B %d, %Y'
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
exclude_patterns = []
# The reST default role (used for this markup: `text`) to use for all
# documents.
#default_role = None
# If true, '()' will be appended to :func: etc. cross-reference text.
#add_function_parentheses = True
# If true, the current module name will be prepended to all description
# unit titles (such as .. function::).
#add_module_names = True
# If true, sectionauthor and moduleauthor directives will be shown in the
# output. They are ignored by default.
#show_authors = False
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx'
# A list of ignored prefixes for module index sorting.
#modindex_common_prefix = []
# If true, keep warnings as "system message" paragraphs in the built documents.
#keep_warnings = False
# If true, `todo` and `todoList` produce output, else they produce nothing.
todo_include_todos = True
# -- Options for HTML output ----------------------------------------------
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
# html_theme = 'alabaster'
html_theme = "sphinx_rtd_theme"
html_style = 'css/opnsense.css'
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
# documentation.
#html_theme_options = {}
# Add any paths that contain custom themes here, relative to this directory.
#html_theme_path = []
html_theme_path = ["_themes", ]
# The name for this set of Sphinx documents. If None, it defaults to
# "<project> v<release> documentation".
#html_title = None
# A shorter title for the navigation bar. Default is the same as html_title.
#html_short_title = None
# The name of an image file (relative to this directory) to place at the top
# of the sidebar.
#html_logo = None
html_logo = '_static/deciso_ruit.png'
# The name of an image file (within the static path) to use as favicon of the
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
# pixels large.
html_favicon = 'favicon.ico'
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['_static']
# Add any extra paths that contain custom files (such as robots.txt or
# .htaccess) here, relative to this directory. These files are copied
# directly to the root of the documentation.
#html_extra_path = []
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
# using the given strftime format.
#html_last_updated_fmt = '%b %d, %Y'
# If true, SmartyPants will be used to convert quotes and dashes to
# typographically correct entities.
#html_use_smartypants = True
# Custom sidebar templates, maps document names to template names.
#html_sidebars = {}
# Additional templates that should be rendered to pages, maps page names to
# template names.
#html_additional_pages = {}
# If false, no module index is generated.
#html_domain_indices = True
# If false, no index is generated.
#html_use_index = True
# If true, the index is split into individual pages for each letter.
#html_split_index = False
# If true, links to the reST sources are added to the pages.
html_show_sourcelink = False
# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
#html_show_sphinx = True
# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
#html_show_copyright = True
# If true, an OpenSearch description file will be output, and all pages will
# contain a <link> tag referring to it. The value of this option must be the
# base URL from which the finished HTML is served.
#html_use_opensearch = ''
# This is the file name suffix for HTML files (e.g. ".xhtml").
#html_file_suffix = None
# Language to be used for generating the HTML full-text search index.
# Sphinx supports the following languages:
# 'da', 'de', 'en', 'es', 'fi', 'fr', 'hu', 'it', 'ja'
# 'nl', 'no', 'pt', 'ro', 'ru', 'sv', 'tr'
#html_search_language = 'en'
# A dictionary with options for the search language support, empty by default.
# Now only 'ja' uses this config value
#html_search_options = {'type': 'default'}
# The name of a javascript file (relative to the configuration directory) that
# implements a search results scorer. If empty, the default will be used.
#html_search_scorer = 'scorer.js'
# Output file base name for HTML help builder.
htmlhelp_basename = 'OPNsensedoc'
# -- Options for LaTeX output ---------------------------------------------
latex_elements = {
# The paper size ('letterpaper' or 'a4paper').
#'papersize': 'letterpaper',
# The font size ('10pt', '11pt' or '12pt').
#'pointsize': '10pt',
# Additional stuff for the LaTeX preamble.
#'preamble': '',
# Latex figure (float) alignment
#'figure_align': 'htbp',
}
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title,
# author, documentclass [howto, manual, or own class]).
latex_documents = [
(master_doc, 'OPNsense.tex', u'OPNsense Documentation',
u'Deciso B.V.', 'manual'),
]
# The name of an image file (relative to this directory) to place at the top of
# the title page.
#latex_logo = None
# For "manual" documents, if this is true, then toplevel headings are parts,
# not chapters.
#latex_use_parts = False
# If true, show page references after internal links.
#latex_show_pagerefs = False
# If true, show URL addresses after external links.
#latex_show_urls = False
# Documents to append as an appendix to all manuals.
#latex_appendices = []
# If false, no module index is generated.
#latex_domain_indices = True
# -- Options for manual page output ---------------------------------------
# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [
(master_doc, 'opnsense', u'OPNsense Documentation',
[author], 1)
]
# If true, show URL addresses after external links.
#man_show_urls = False
# -- Options for Texinfo output -------------------------------------------
# Grouping the document tree into Texinfo files. List of tuples
# (source start file, target name, title, author,
# dir menu entry, description, category)
texinfo_documents = [
(master_doc, 'OPNsense', u'OPNsense Documentation',
author, 'OPNsense', 'One line description of project.',
'Miscellaneous'),
]
# Documents to append as an appendix to all manuals.
#texinfo_appendices = []
# If false, no module index is generated.
#texinfo_domain_indices = True
# How to display URL addresses: 'footnote', 'no', or 'inline'.
#texinfo_show_urls = 'footnote'
# If true, do not generate a @detailmenu in the "Top" node's menu.
#texinfo_no_detailmenu = False
# -- Options for Epub output ----------------------------------------------
# Bibliographic Dublin Core info.
epub_title = project
epub_author = author
epub_publisher = author
epub_copyright = copyright
# The basename for the epub file. It defaults to the project name.
#epub_basename = project
# The HTML theme for the epub output. Since the default themes are not
# optimized for small screen space, using the same theme for HTML and epub
# output is usually not wise. This defaults to 'epub', a theme designed to save
# visual space.
#epub_theme = 'epub'
# The language of the text. It defaults to the language option
# or 'en' if the language is not set.
#epub_language = ''
# The scheme of the identifier. Typical schemes are ISBN or URL.
#epub_scheme = ''
# The unique identifier of the text. This can be a ISBN number
# or the project homepage.
#epub_identifier = ''
# A unique identification for the text.
#epub_uid = ''
# A tuple containing the cover image and cover page html template filenames.
#epub_cover = ()
# A sequence of (type, uri, title) tuples for the guide element of content.opf.
#epub_guide = ()
# HTML files that should be inserted before the pages created by sphinx.
# The format is a list of tuples containing the path and title.
#epub_pre_files = []
# HTML files shat should be inserted after the pages created by sphinx.
# The format is a list of tuples containing the path and title.
#epub_post_files = []
# A list of files that should not be packed into the epub file.
epub_exclude_files = ['search.html']
# The depth of the table of contents in toc.ncx.
#epub_tocdepth = 3
# Allow duplicate toc entries.
#epub_tocdup = True
# Choose between 'default' and 'includehidden'.
#epub_tocscope = 'default'
# Fix unsupported image types using the Pillow.
#epub_fix_images = False
# Scale large images.
#epub_max_image_width = 0
# How to display URL addresses: 'footnote', 'no', or 'inline'.
#epub_show_urls = 'inline'
# If false, no index is generated.
#epub_use_index = True
# load PhpLexer
from sphinx.highlighting import lexers
from pygments.lexers.web import PhpLexer
from pygments.lexers.web import JavascriptLexer
# enable highlighting for PHP code not between <?php ... ?> by default
lexers['php'] = PhpLexer(startinline=True)
lexers['php-annotations'] = PhpLexer(startinline=True)
# inline highliting for Javascript
lexers['Javascript'] = JavascriptLexer(startinline=True)
lexers['Javascript-annotations'] = JavascriptLexer(startinline=True)

209
source/contribute.rst Normal file
View File

@ -0,0 +1,209 @@
==========
Contribute
==========
OPNsense is an open source community project that depends on your contributions
for its continuing development & success.
There are plenty of opportunities to contribute and help OPNsense reach its goal
of becoming the most widely used open source security & firewall platform.
Financial contributions are always welcome and will allow us to develop parts
of the system that may otherwise stay untouched.
The OPNsense core team wants to thank everyone who contributed already.
------------------
-----------
Financially
-----------
"*An open source project can only thrive by the community around it.*"
We are grateful of all the kind words and support the users of OPNsense are
giving us.
Frequently users ask us how they can contribute to the project.
To make the software better we need your involvement in testing and providing
feedback and if you can spare a few bucks that would be great.
---------------
Donations
---------
To enable us to continue development and keep on improving the project you can
contribute by donating to the project, this a simple non recurring - no strings
attached - way of supporting the project. Any amount will be gratefully accepted!
.. raw:: html
<form action="https://www.paypal.com/cgi-bin/webscr" method="post">
<div class="paypal-donations">
<b>Why wait? Donate today ! </b>&nbsp;
<input name="cmd" value="_donations" type="hidden">
<input name="bn" value="TipsandTricks_SP" type="hidden">
<input name="business" value="donate@opnsense.org" type="hidden">
<input name="return" value="https://opnsense.org/thanks" type="hidden">
<input name="item_name" value="Donate to the OPNsense project" type="hidden">
<input name="rm" value="0" type="hidden">
<input name="currency_code" value="EUR" type="hidden">
<input name="lc" value="US" type="hidden">
<input src="https://www.paypal.com/en_US/i/btn/btn_donate_LG.gif" name="submit" alt="PayPal - The safer, easier way to pay online." type="image">
</div>
</form>
</br>
---------------
Partner program
---------------
The OPNsense project offers a partner program where businesses receive project
benefits while supporting the project financially.
Main benefits include:
* Listing on our `OPNsense partner page <https://opnsense.org/partners/>`__
* Access to the core team
To get enlisted as partner of the OPNsense project means a minimum annual investment
of € 2500.Partners that made an exceptional contribution to the project are assigned
the Platinum Partner status.
---------------
Support Contract
----------------
with a support contract we support you and you support us as OPNsense is fully
supported by Deciso.
For support options see `OPNsense Commercial Support <https://opnsense.org/support-overview/commercial-support/>`__
------------------
-----------
Development
-----------
Contributing to the ongoing development of OPNsense can be done by:
* Testing a development version and
* Report issues and/or
* Help fixing issues as well as by
* Contributing new functionality
* Share your code with the project by manner of a pull request.
---------------
Testing
-------
Contribute by testing the latest development version to make the next release even
better than the last. If you like to test a development version then the easiest
way is to login to the console and type:
::
pkg install -y opnsense-devel
And to revert back to the production version:
::
pkg install -y opnsense
That is all there is to it to test the latest development release.
Development releases are usually built at the same day the latest production
release comes available.
---------------
Reporting an issue
------------------
Issues can be easily reported on github, please consider carefully if the issue
could be a configuration or user error before reporting it. If you are unsure,
report you issue on the `Forum <https://forum.opnsense.org>`__ or on IRC/Freenode (#opnsense).
---------------
Fixing issues
-------------
If you are a programmer or just know how to fix a certain issue then you can help
by either sharing your ideas on or send in a pull request on github.
---------------
Designing new features
----------------------
If you like to help designing new features then start with reading the :doc:`Development
manual </develop>` and checkout our `roadmap <https://opnsense.org/about/road-map/>`__ as well as our `issue tracker <https://github.com/opnsense/core/issues>`__.
Before starting it is always a good to share your idea first with a core developer,
to do so you can use either:
* `github <https://github.com/opnsense/core/>`__ and `create a issue <https://github.com/opnsense/core/issues/new>`__
and mention you volunteer for taking on the development task (we will correctly label it as enhancement or feature)
* find one of us on IRC/Freenode (#opnsense) and see if we are available to
discuss your idea.
------------------
------------
Translations
------------
OPNsense has an active `translation project <https://translate.opnsense.org/projects/>`__,
currently supporting:
* Czech
* English
* French
* German
* Japanese
* Portuguese
* Russian
* Simplified Chinese
Working on translations is time consuming, but if you feel up to it and would
like to help adding another language, then please contact us via email (contact @ opnsense.org).
------------------
-----------------------------
Documentation & wiki articles
-----------------------------
The easiest way to help with documentation is to write how-to type articles.
As the wiki & documentation project itself is written in **reStructuredText** you
can offer your content in this format (preferably as pull request), but other
formats are also possible, such as:
* markup with ./images/directory including the used images(in any)
* word document with embedded images (if any)
To include you documentation send it to contact @ opnsense.org. Make sure that:
* Your content does not include copyrighted material if you do not own the copyright yourself
* State that we may use the content under our Documentation Copyright as listed in the :doc:`legal` section.
------------------
-----------
Forum & IRC
-----------
If you are an experienced network engineer, know a lot about firewall technology
or if you are excited about OPNsense, then you can contribute to the project by helping
others on the forum or on irc.
------------------
------------
Social media
------------
Contribute to the success of the project by letting others know how OPNsense helped
solving your network or security challenges. Let others know about OPNsense and/or
follow us & retweet our messages on `twitter <https://twitter.com/opnsense>`__.
Anything you can do to spread the word about OPNsense will help to reach our goal
to become the most widely used open source security & firewall platform.
------------------
-------------
Closing Words
-------------
If you have suggestions on how others can contribute to OPNsense and it is not yet
listed on this page, then let us know. You can reach us at contact @ opnsense.org.

36
source/develop.rst Normal file
View File

@ -0,0 +1,36 @@
====================================
Development Manual
====================================
.. image:: /development/images/ideas_join_the_development.jpg
The OPNsense® project invites developers to start developing with OPNsense:
"For your own purpose or even better to join us in creating the best FreeBSD
based open source firewall available!" The development workflow & build process
has been redesigned to make it more straightforward and easy for developers to
build OPNsense.
Being able to get the sources and build it yourself is one of the key factors of
open source software. One reason that for starting the OPNsense project is that
the team believes sources and build tools should be freely available and as easy
to use as possible.
.. toctree::
:maxdepth: 2
:titlesonly:
:glob:
development/workflow
development/guidelines
development/architecture
development/backend
development/frontend
development/components
development/examples
development/howtos
development/*
-------
Sources
-------
Just looking for the sources? See: `OPNsense repository <https://github.com/opnsense>`__

View File

@ -0,0 +1,136 @@
============
Architecture
============
The main focus of the OPNsense project is to provide a secure and
manageable platform for all your security applications. This means high
quality software that is easily maintainable and bug free. We think that
having a framework with a clear separation of concerns is essential to
achieving these goals.
OPNsense is a fork of pfSense ®. The existing code base of pfSense ®
does not always apply a clear separation of concerns. This means we need
a transition of the old (legacy) code base to a new one with a clear
separation. We have chosen a gradual transition to avoid a big bang and
keep the product feature rich while increasing code quality. This
enables simple addition of new features with less bugs and shorter time
to market.
This article describes how this will be achieved.
-----------------------
High-level architecture
-----------------------
|OPNsense Components.png|
As the above model shows there are two main areas in our stack, the
frontend implemented with PHP/Phalcon and the backend using a custom
service built in Python.
The frontend handles user interaction and communicates with the backend
service. Applying configuration changes, monitoring and controlling
services offered by OPNsense is done by the backend service.
By using a fully configurable backend service, we avoid hardcoding of
services and ease the implementation of new features.
The frontend stack delivers a model driven approach to handle
configuration data, including automatic validation.
Manipulation of the core configuration file is handled at the frontend
model; the backend service is merely a consumer of the information
provided.
--------------------
Backend Architecture
--------------------
|OPNsense backend.png|
Configd, is responsible
for the core system interaction like starting and stopping of daemons
and generating configuration files for used services and applications.
The daemon listens on a unix domain socket and is capable of executing
actions defined in its own configuration directory
(“/usr/local/opnsense/service/conf/actions\_\*.conf”).
Currently there are two types of services implemented in the daemon:
- script : execute external (rc) scripts
- inline : perform inline actions which are part of configd, currently
only template generation.
|
| Template generation is handled by Jinja2 (http://jinja.pocoo.org/),
more information on how to create application templates can be found
at :doc:`/development/backend/templates`.
---------------------
Frontend Architecture
---------------------
|OPNsense frontend.png|
Routing
-------
The OPNsense framework uses components from Phalcon where possible; the
first layer initializes Phalcons routing, which handles requests and
delivers them to the controller based on its url. User content is
generated using Volt templates, which are picked by the controller.
Because Phalcons default Models function with (relational) databases
and we are using xml data, our model implementation is custom. But
wherever possible we use components from Phalcon (for example,
validation is handled using Phalcons classes). For a detailed
description on the routing principles used in OPNsense, visit Frontend
:doc:`/development/frontend/routing`.
Controllers and views
---------------------
Not all parts of the framework are already implemented, but by deriving
all controllers from the base in the OPNsense project its easy to
extend and adapt to future needs. Documentation on how to implement
controllers, with the use of views, can be found at :doc:`/development/frontend/controller`.
Models
------
All models are defined by a combination of a class and an xml containing
a (nested) definition. More information on defining models can be found
at the frontend model page :doc:`/development/frontend/models`.
Communication
-------------
Communication to the backend service is handled via a unix domain
socket.
Core system
-----------
The core of OPNsense is powered by an almost standard FreeBSD ® system
extended with packages using the pkg system. GIT is used for version
control and the repositories are split into 4 parts:
- src : the base (FreeBSD ®) system
- ports : the ports collection containing third party software
- core : the OPNsense gui and system configuration parts
- tools : easy tools to build OPNsense
.. TIP::
| For detailed information about the development workflow see:
| :doc:`OPNsense development workflow </development/workflow>`
.. |OPNsense Components.png| image:: images/OPNsense_Components.png
:width: 600px
:height: 548px
.. |OPNsense backend.png| image:: images/OPNsense_backend.png
:width: 600px
:height: 575px
.. |OPNsense frontend.png| image:: images/OPNsense_frontend.png
:width: 600px
:height: 461px

View File

@ -0,0 +1,27 @@
=======
Backend
=======
The OPNsense backend consists of several components (see Architecture for a full stack description).
Our core backend service (configd) is implemented using `Python <https://en.wikipedia.org/wiki/Python>`__. and provides two main features:
- Service interaction (using configd actions)
- Generation of configuration data (using templates)
Because some of the codebase still integrates with our legacy codebase, we provide additional plugin options for the following components:
- Services (the services status)
- Syslog (define syslog targets)
- Interface (register interfaces, firewall use etc.)
- Service configuration (legacy service configuration, new style uses configd templates)
Services which need to be executed at system startup can use rc(8) or our syshook system.
.. toctree::
:maxdepth: 2
:titlesonly:
:glob:
backend/*

View File

@ -0,0 +1,54 @@
========================
Bootup / autorun options
========================
-------
syshook
-------
OPNsense offers an easy method to plugin shell scripts during (early) boot stage.
Syshook scripts should be installed in :
::
/usr/local/etc/rc.syshook.d/
They can contain regular shell scripts using the following extensions:
- start
- start script after normal system startup
- early
- start script before normal system startup.
Example (vmware guestd start, filename /usr/local/etc/rc.syshook.d/vmware.early)
::
#!/bin/sh
export vmware_guest_vmblock_enable="YES"
export vmware_guest_vmhgfs_enable="YES"
export vmware_guest_vmmemctl_enable="YES"
export vmware_guest_vmxnet_enable="YES"
/usr/local/etc/rc.d/vmware-kmod start
-----
rc(8)
-----
Part of the bootup process of OPNsense is probing the available rc(8) configuration files in */etc/rc.conf.d/*, when a daemon is enabled, the system will call the regular rc(8) start command.
In case the daemon needs some extra preparation, an additional "bootup" script can be provided, which will be run before executing normal "start".
Example (from a configured squid proxy server using */etc/rc.conf.d/squid*):
::
squid_enable=YES
squid_opnsense_bootup_run="/usr/local/opnsense/scripts/proxy/setup.sh"
The configd template system can be used to generate the necessary configuration file(s).

View File

@ -0,0 +1,102 @@
===============
Using configd
===============
-------
General
-------
To add new services and system calls, which can be used from the frontend system or command line, you can create configd actions.
All available templates should be installed at the following location on
the OPNsense system:
::
/usr/local/opnsense/service/conf/actions.d/
*Please note that all actions which should be accessible from the frontend should have a registered configd action, if possible use standard rc(8) scripts for service start/stop.*
-----------------
Naming convention
-----------------
Service templates should use distinctive names to identify your service and contain simple / clear actions.
For example, we will describe the template for ssh, which is installed by default.
**File name:**
::
/usr/local/opnsense/service/conf/actions.d/actions_sshd.conf
Our ssh service has two actions available:
- restart
- starts / restarts ssh service
- stop
- stops / kills all ssh daemons
::
[restart]
command:/usr/local/etc/rc.sshd
parameters:
type:script
message:starting sshd
[stop]
command:/bin/pkill -TERM sshd || exit 0
parameters:
type:script
message:stop sshd
Between brackets [] you find the name of the action, the definition of the actual call is defined in the following parameter:value pairs.
When a service or module provides a lot of actions, it sometimes is practical to add another level of operation.
For example, the restart service call for this service will translate to: **sshd restart**
In case we have an action like **filter diag info**, you can create an actions_filter.conf which contains a section [diag.info].
-----------------
Action properties
-----------------
+-----------------------+------------------------+--------------------------------------------------------+
| Property | Syntax | Description |
+=======================+========================+========================================================+
| command | text | shell command string to execute |
+-----------------------+------------------------+--------------------------------------------------------+
| parameters | %s for every parameter | list of parameters to use, example : /i %s |
+-----------------------+------------------------+--------------------------------------------------------+
| type | script|script_output | type of call: |
| | | - script (only return exit status) |
| | | - script_output (return result) |
+-----------------------+------------------------+--------------------------------------------------------+
| message | text | Message to send to syslog (you can use %s parameters) |
+-----------------------+------------------------+--------------------------------------------------------+
| description | text | User friendly description. |
+-----------------------+------------------------+--------------------------------------------------------+
-----------
Test action
-----------
To test a new configd action, please restart the configd service first using:
::
service configd restart
Next use the supplied helper command to execute our action:
::
configctl sshd restart

View File

@ -0,0 +1,114 @@
====================
Using legacy plugins
====================
-------
General
-------
Legacy type plugins are located in the following location:
::
/usr/local/etc/inc/plugins.inc.d/
And contain files with the extension ".inc".
All automatically registered functions start with the name of the file (without the extension), followed by the purpose.
For example *vpn_configure* would be the *configure* handle in a plugin file name vpn.inc.
-----------------
Services
-----------------
To register services, the *<plugin>_services()* function should return a structure containing its name, description and operating properties.
::
function myplugin_services()
{
$service = array();
$service['name'] = 'myservice';
$service['description'] = gettext('My service');
$service['configd']['restart'] = array('myservice restart');
$service['configd']['start'] = array('myservice start');
$service['configd']['stop'] = array('myservice stop');
$services[] = $pconfig;
return $services;
}
For a full list of supported service methods, please inspect *services.inc*
-----------------
Syslog
-----------------
To register syslog targets, the *<plugin>_syslog()* function should return a structure containing targets and definitions.
::
function myplugin_syslog()
{
$logfacilities = array();
$logfacilities['myplugin'] = array(
'facility' => array('myplugin'),
'remote' => 'myplugin',
);
return $logfacilities;
}
-----------------
Interface
-----------------
To register new (virtual) interfaces, create a function called *<plugin>_interfaces()*, which should return a named array containing the unique interface name as key (enc0 for ipsec for example).
Every item should contain the following properties:
+-----------------------+------------------------+--------------------------------------------------------+
| Property | Syntax | Description |
+=======================+========================+========================================================+
| enable | boolean | interface enabled, if so it will be saved in the config|
+-----------------------+------------------------+--------------------------------------------------------+
| descr | text | User readable description |
+-----------------------+------------------------+--------------------------------------------------------+
| networks | array, [network, mask] | list of named arrays containing remote networks |
+-----------------------+------------------------+--------------------------------------------------------+
| type | text | "none" |
+-----------------------+------------------------+--------------------------------------------------------+
| if | text | physical interface (e.g. enc0) |
+-----------------------+------------------------+--------------------------------------------------------+
| virtual | boolean | Virtual interface, true/false |
+-----------------------+------------------------+--------------------------------------------------------+
Example:
::
function myplugin_interfaces()
{
global $config;
$interfaces = array();
if (isset($config['myplugin']['enable'])) {
$oic = array("enable" => true);
$oic['if'] = 'tun0';
$oic['descr'] = 'myplugin';
$oic['type'] = "none";
$oic['virtual'] = true;
$oic['networks'] = array();
$interfaces['tun0'] = $oic;
}
return $interfaces;
}
-----------------
Configure
-----------------
When your plugin needs configuration after boot, you can create a function called *<plugin>_configure()* which will be called upon boot.

View File

@ -0,0 +1,147 @@
===============
Using Templates
===============
-------
General
-------
For config file generation, we provide a backend service which can bind
config.xml data to templates written in Jinja2
(http://jinja.pocoo.org/docs/dev/).
All available templates should be installed at the following location on
the OPNsense system:
#. /usr/local/opnsense/service/templates/
-----------------
Naming convention
-----------------
All templates should be put into a directory structure containing the
vendor and package/application name, our sample application is placed
inside the directory:
/usr/local/opnsense/service/templates/*OPNsense/Sample*
Template package content
Every template directory should contain at least 2 files:
#. a content descriptor, containing the actual targets, named +TARGETS
#. one or more template(s)
-------
Targets
-------
The +TARGETS file contains the source template name inside the template
directory and the (dynamic) target filename divided by a colon (:)
multiple lines may be inserted per file.
For example :
::
example_simple_page.txt:/tmp/template_sample/simple_page.txt
Will create a file /tmp/template\_sample/simple\_page.txt using the
template example\_simple\_page.txt.
.. Note::
Optionally you can specify which file or files to remove on call of "template cleanup", which can be specified by
using an extra tag next to the target, such as:
:code:`example_simple_page.txt:/tmp/template_sample/simple_page.txt:/tmp/template_sample/simple_page.*`
By default all targets will be removed when calling cleanup.
If you want to use information from within the config.xml file as output
filename, you can use tags to address the content, like [version] to
input the tag version from the xml file. When generating multiple files
from 1 template, you can use one wildcard (%) to address a section of
the config file, for example [interfaces.%.if] loops over the interfaces
and outputs the value of **if**.
-----------------
Target overwrites
-----------------
Every template package can specify overwrites, which can be used by vendors who implement and maintain their own templates
for features in OPNsense.
Simply add files using the target definition in the **+TARGETS.D** directory of the templates folder using as extension **.TARGET**.
For example an overwrite for OPNsense/Sample can use the following name and location
:code:`/usr/local/opnsense/service/templates/OPNsense/Sample/+TARGETS.D/custom.TARGET`
.. Note::
Be vey careful using this feature, you need to maintain these templates yourself and features may break after upgrades
of OPNsense.
---------
Templates
---------
For more information of the template language itself, please look at
http://jinja.pocoo.org/docs/dev/ and the examples installed in
/usr/local/opnsense/service/templates/OPNsense/Sample.
There's one special case when using the template engine, every wildcard
used for the output file generation is also provided to the template, so
you are able to determine which filter let to this output.
Those filters are stored in the variable TARGET\_FILTERS.
.. code-block:: jinja
{% if TARGET_FILTERS['interfaces.wan'] %}
{% endif %}
----------
Test usage
----------
The templates can be rendered via the backend service (configd), to test
this functionality on a running OPNsense system, use:
::
# generate template package
configctl template reload OPNsense/Sample
# cleanup files
configctl template cleanup OPNsense/Sample
|
-----------------------------
Python template usage example
-----------------------------
The template system itself is a separate module which is used by
configd, to use (or test) the system without the daemon, use:
.. code-block:: python
# import template system and config.xml handling
from modules import template
from modules import config
 
# construct a new template object, set root to /tmp/
tmpl = template.Template(target_root_directory="/tmp/")
# open the config.xml and bind to template object
conf = config.Config('/config.xml')
tmpl.setConfig(conf.get())
 
# generate output for OPNsense/Sample
generated_filenames = tmpl.generate('OPNsense/Sample')
 
# print results
for filename in generated_filenames:
print ('.. generated : %s'%filename)

View File

@ -0,0 +1,18 @@
==========
Components
==========
OPNsense® **components** are not directly related to the front and backend.
For the OPNsense framework we've developed some shared components for common
tasks, this page indexes those components which aren't directly related to the
`Model View Controller <https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller>`__ (MVC) framework itself.
.. toctree::
:maxdepth: 2
:titlesonly:
:glob:
components/menusystem
components/acl
components/*

View File

@ -0,0 +1,55 @@
===================
Access Control List
===================
.. sidebar:: Access Control List
.. image:: images/acl-finger-print.jpg
--------
Overview
--------
The current ACL system is targeted at delivering backwards compatibility
for legacy code and being able to extend this a little to add new
features without having to reimplement the whole system.
In the legacy system the access control is using the following steps to
determine if a page can be accessed by a user:
#. The user, stored in the config.xml file at system/user (one item per
user)
#. One or more groups for that user, stored in system/group which
contains priv sections.
#. A php file binding the priv section content to a page mask (including
wildcards)
Our temporary solution is to keep the user and the group in place and replace the
php file with a simple config in the model which uses the same mask construction
there was in the old codebase. To bind priv to pages, edit models/OPNsense/Core/ACL\_Legacy\_Page\_Map.txt
--------------
Usage from php
--------------
Using the system from php is rather simple:
.. code-block:: php
$acl = new OPNsense\Core\ACL();
if ( $acl->isPageAccessible("user", "/firewall_rules.php") ) {
print ( "/firewall_rules.php is accessible" ) ;
}
-----------------------
Usage in Volt templates
-----------------------
The acl scheme is bound to the default UI controller, and can be used by
using the acl keyword:
.. code-block:: jinja
{% if acl.isPageAccessible(session.get('Username'),subMenuItem.Url)  %}
this page is accessible
{% endif %}

Binary file not shown.

After

Width:  |  Height:  |  Size: 864 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

View File

@ -0,0 +1,66 @@
===========
Menu System
===========
.. sidebar:: OPNsense Menu System
.. image:: images/menusystem.png
:width: 300px
:align: center
--------
Overview
--------
One of the shared components of the OPNsense framework is the menu system, which
is wrapped in a single class and part of the base model.
The only responsibility of the menu system is to create a tree like structure to
represent the menu and being able to keep track of the mapping between a location
and the hierarchy of the menu system. To keep things clean and understandable,
the menu system doesn't know anything about users or authorisation.
Currently the main focus for the menu system is to support the legacy code, so
we will be able to reimplement the menu in both legacy and new code.
Our base UI controller (\\OPNsense\\Base\\ControllerBase) implements the menu
system for further use.
An example of how to create a menu, is given below:
.. code-block:: php
// create new menu
$menu = new Menu\MenuSystem();
// append an additional dynamic item into the system
$menu->appendItem("System.Advanced", "test123", array("url"=>"/testpage.php","order"=>1));
// test, print menu as structured named array
print_r($menu->getItems("/testpage.php"));
The current version only implements a static menu defined by one xml file
(models/OPNsense/Base/Menu/Menu.xml), but extending with additional xml files
is already supported in the component for future use.
--------
Menu.xml
--------
The menu xml is defined as follows:
.. code-block:: xml
<menu>
<MainItem order="0" VisibleName="System" cssClass="glyphicon glyphicon-dashboard">
<SubItem1 url="/ui/test.php"/>
<SubItem2 url="/ui/test2.php"/>
</MainItem>
</menu>
The top level should be named "menu" to let the system know this is a menu
structure, the next layers will be used for the structure of itself. To map the
attributes to the menu objects created there are setters in
OPNsense\\Base\\Menu\\MenuItem, in this version the next attributes are supported:
- order, sort order in our menu
- VisibleName, name to use ( if not set the tagname / id will be used)
- cssClass, style attributes for the frontend system.

View File

@ -0,0 +1,10 @@
========
Examples
========
.. toctree::
:maxdepth: 2
:titlesonly:
:glob:
examples/*

View File

@ -0,0 +1,987 @@
===========================
Hello world module & plugin
===========================
.. sidebar:: Creating the hello world module
.. image:: images/Hello-World.jpg
:width: 300px
:align: center
----
Goal
----
.. rubric:: Goal for this sample
:name: goal-for-this-sample
----------------------------------
The goal of the "Hello world" module we're creating in the example is to
control a program on our system named "testConnection.py", which is part
of the example package available on GitHub. It will try to send an email
using plain smtp and will respond with a json text message about the
result of that attempt.
Our application will need some settings to operate correctly, like an ip
address and an email address and we need to be able to run that
application. Because this application returns some valuable data for our
users, we need to be able to fetch the response data back.
|overview|
-----------------------------
----------
Guidelines
----------
.. rubric:: Guidelines and coding style
:name: guidelines-and-coding-style
For all OPNsense modules and applications there are some basic style and
coding guides which you should use.
Naming
------
When creating modules for OPNsense, always name your components like
this: VendorName/ModuleName
In our sample case this will be: OPNsense/HelloWorld
PHP code
--------
Please use PSR-2 style (http://www.php-fig.org/psr/psr-2/) for all new
code.
Architecture
------------
Always make sure there's a clear separation of concerns, back-end calls
(like shell scripts) should be implemented using the configd system, all
communication to the client should be handled from an api endpoint. (the
example provides more insights on how this works).
Back-end programs should not access the config.xml directly, if data is
needed let the template system handle the desired output (most
applications, daemons and tools deliver their own desired configuration
format). There's generally no good reason to avoid the standards that
are already there.
If you follow this basic rules, you're automatically building a command
structure for the system administrators and provide a connector to third
party tools to the API of your component (as of version 16.1).
--------
Skeleton
--------
.. rubric:: Setup a skeleton for the frontend / middleware
:name: setup-a-skeleton-for-the-frontend-middleware
First step for our project is to build a skeleton which holds the
structure for our frontend/middleware.
Model
-----
For our sample application we want to setup some configuration data,
which for all new style projects should live in its own model.
First we start by creating two files inside the
models/OPNsense/HelloWorld directory.
The first one is the boilerplate for the model class, which should
contain model specific methods and (by deriving it from BaseModel)
automatically understands the second file.
.. code-block:: php
<?php
namespace OPNsense\HelloWorld;
 
use OPNsense\Base\BaseModel;
 
class HelloWorld extends BaseModel
{
}
(/usr/local/opnsense/mvc/app/models/OPNsense/HelloWorld/HelloWorld.php)
Not all modules contain additional code in the php class, sometimes all
the standard behaviour is already sufficient for your
modules/application.
Which is the model xml template, our skeleton starts with something like
this:
.. code-block:: xml
<model>
<mount>//OPNsense/helloworld</mount>
<description>
the OPNsense "Hello World" application
</description>
<items>
</items>
</model>
(/usr/local/opnsense/mvc/app/models/OPNsense/HelloWorld/HelloWorld.xml)
The content of the mount tag is very important, this is the location
within the config.xml file where this model is responsible. Other models
cannot write data into the same area. You should name this location with
your vendor and module name to make sure others could easily identify
it.
Use the description tag to identify your model, the last tag in place is
the items tag, where the actual definition will live. We leave it empty
for now as we proceed with the next step of creating our skeleton.
View
----
.. rubric:: Page template (View)
:name: page-template-view
We should add a (Volt) template to use for the index page of our module;
we will use the same naming convention here.
Create a template named index.volt inside the views/OPNsense/HelloWorld
directory containing the following data:
.. code-block:: html
<h1>Hello World!</h1>
(/usr/local/opnsense/mvc/app/views/OPNsense/HelloWorld/index.volt)
Controller
----------
Next step is to add controllers, which will be automatically picked up
by the system routing. A controller connects the user interaction to
logic and presentation.
Every OPNsense module should separate presentation from logic, thats
why there should always be multiple controllers per module.
Our first controller handles the template rendering to the user and
connects the user view we just created. We start by creating a php file
in controllers/OPNsense/HelloWorld/ with the following name
IndexController.php and contents:
.. code-block:: php
<?php
namespace OPNsense\HelloWorld;
class IndexController extends \OPNsense\Base\IndexController
{
public function indexAction()
{
// set page title, used by the standard template in layouts/default.volt.
$this->view->title = "Hello World";
// pick the template to serve to our users.
$this->view->pick('OPNsense/HelloWorld/index');
}
}
(/usr/local/opnsense/mvc/app/controllers/OPNsense/HelloWorld/IndexController.php)
At this point you should be able to test if your work so far was
successful, by going to the following location (after being logged in to
the firewall as root user):
::
http[s]://<your ip>/ui/helloworld/
Which should serve you the “Hello World!” text youve added in the
template.
|Serving the first "hello world" page|
Next two controllers we are going to create are to be used for the api
to the system, they should take care of service actions and the
retrieval/changing of configuration data.
They should live in a subdirectory of the controller called Api and
extend the corresponding class.
For our modules we create two api controllers, one for controlling
settings and one for performing service actions. (Named
SettingsController.php and ServiceController.php) Both should look like
this (replace Settings with Service for the other one):
.. code-block:: php
<?php
namespace OPNsense\HelloWorld\Api;
 
use \OPNsense\Base\ApiControllerBase;
class SettingsController extends ApiControllerBase
{
}
(/usr/local/opnsense/mvc/app/controllers/OPNsense/HelloWorld/Api/SettingsController.php)
----------------
First Input Form
----------------
.. rubric:: Building your first input form
:name: building-your-first-input-form
The first step in building forms is to determine what information we
should collect.
Our simple application will send an email using data in our
configuration xml. For this very module we want to collect the
following:
+-----------------------+----------------------+----------------------------------------------+
| Property | Default | Description |
+=======================+======================+==============================================+
| General.Enabled | Enabled (1) | Should this module be enabled (Boolean) |
+-----------------------+----------------------+----------------------------------------------+
| General.SMTPHost | <empty> | IP address for the remote smtp host |
+-----------------------+----------------------+----------------------------------------------+
| General.FromEmail | sample@example.com | Email address of the sender |
+-----------------------+----------------------+----------------------------------------------+
| General.ToEmail | <empty> | Email address to send our test email to |
+-----------------------+----------------------+----------------------------------------------+
| General.Description | <empty> | Description, used as subject of the email. |
+-----------------------+----------------------+----------------------------------------------+
Adding Fields
-------------
.. rubric:: Adding fields to your model
:name: adding-fields-to-your-model
When building the skeleton, we have created an empty model (xml), which
we are going to fill with some attributes now. The items section of the
model xml should contain the structure you want to use for your
application, you can create trees to hold data in here. All leaves
should contain a field type to identify and validate its content. The
list of attributes for our application can be translated to this:
.. code-block:: xml
………
<items>
<!-- container -->
<general>
<!-- fields -->
<Enabled type="BooleanField">
<default>1</default>
<Required>Y</Required>
</Enabled>
<SMTPHost type="NetworkField">
<Required>Y</Required>
</SMTPHost>
<FromEmail type="EmailField">
<default>sample@example.com</default>
<Required>Y</Required>
</FromEmail>
<ToEmail type="EmailField">
<Required>Y</Required>
</ToEmail>
<Description type="TextField">
<Required>Y</Required>
</Description>
</general>
</items>
………
All available field types can be found in the
models/OPNsense/Base/FieldTypes directory. If specific field types
support additional parameters, for example for validation, they should
be registered in the model as well (just like the default tag in
Enabled).
Presentation XML
----------------
.. rubric:: Create a presentation xml to feed your template
:name: create-a-presentation-xml-to-feed-your-template
Because creating forms is one of the key assets of the system, we have
build some easy to use wrappers to guide you through the process. First
we create an xml file for the presentation, which defines fields to use
and adds some information for your template to render. Create a file in
your controller directory using the sub directory forms and name it
general.xml. Next copy in the following content:
.. code-block:: xml
<form>
<field>
<id>helloworld.general.Enabled</id>
<label>enabled</label>
<type>checkbox</type>
<help>Enable this feature</help>
</field>
<field>
<id>helloworld.general.SMTPHost</id>
<label>SMTPHost</label>
<type>text</type>
<help><![CDATA[ip address of the mail host]]></help>
<hint>choose a valid IPv4/v6 address</hint>
</field>
<field>
<id>helloworld.general.FromEmail</id>
<label>Email (from)</label>
<type>text</type>
</field>
<field>
<id>helloworld.general.ToEmail</id>
<label>Email (to)</label>
<type>text</type>
</field>
<field>
<id>helloworld.general.Description</id>
<label>Description</label>
<type>text</type>
</field>
</form>
(/usr/local/opnsense/mvc/app/controllers/OPNsense/HelloWorld/forms/general.xml)
All items should contain at least an id (where to map data from/to), a
type (how to display) and a label, which identifies it to the user.
Optional you may add additional fields like help or mark features as
being only for advanced users. (The Volt template defines which
attributes are usable.)
Now we need to tell the controller to use this information and pass it
to your template, so change the IndexController.php and add this line:
.. code-block:: php
$this->view->generalForm = $this->getForm("general");
And we are ready to update the (Volt) template with this information.
Lets remove the "<h1>Hello World!</h1>" line and replace it with
something like this:
.. code-block:: jinja
{{ partial("layout_partials/base_form",['fields':generalForm,'id':'frm_GeneralSettings'])}}
This tells the template system to add a form using the contents of
generalForm and name it frm\_GeneralSettings in the html page. Based on
a standard template part which is already part of the standard system,
named base\_form.volt.
When opening the page again it will render like this:
|Template with fields without content|
Create API calls
----------------
.. rubric:: Create API calls to retrieve and store data
:name: create-api-calls-to-retrieve-and-store-data
The framework provides some helpful utilities to get and set data from
and to the configuration xml by using your defined model. First step in
binding your model to the system is to add a method to the
SettingsController to fetch the data from our configuration (or provide
the defaults if there is no content).
We start by adding the model to our SettingsController, by adding this
in the “use” section:
.. code-block:: php
use \OPNsense\HelloWorld\HelloWorld;
Which includes our model into the controller. Next we create an action
to get data from our system, and put it into a json object for the
client (browser) to parse, by using the wrappers already in our model.
.. code-block:: php
* retrieve HelloWorld general settings
* @return array general settings
*/
public function getAction()
{
// define list of configurable settings
$result = array();
if ($this->request->isGet()) {
$mdlHelloWorld = new HelloWorld();
$result['helloworld'] = $mdlHelloWorld->getNodes();
}
return $result;
}
(/usr/local/opnsense/mvc/app/controllers/OPNsense/HelloWorld/Api/SettingsController.php)
You will probably notice the return value of the action, it's a standard
array which uses "helloworld" for all attributes from getNodes() which
will automatically be converted by the framework to a json object for
the client. The getNodes method itself returns a tree a values, as
defined by your model.
You can test the result (while logged in as root), by going to this
address:
::
http[s]://<your ip>/api/helloworld/settings/get
For saving the data back, we need a similar kind of call, lets name it
“set” and add this to the same php file:
.. code-block:: php
/**
* update HelloWorld settings
* @return array status
*/
public function setAction()
{
$result = array("result"=>"failed");
if ($this->request->isPost()) {
// load model and update with provided data
$mdlHelloWorld = new HelloWorld();
$mdlHelloWorld->setNodes($this->request->getPost("helloworld"));
 
// perform validation
$valMsgs = $mdlHelloWorld->performValidation();
foreach ($valMsgs as $field => $msg) {
if (!array_key_exists("validations", $result)) {
$result["validations"] = array();
}
$result["validations"]["general.".$msg->getField()] = $msg->getMessage();
}
 
// serialize model to config and save
if ($valMsgs->count() == 0) {
$mdlHelloWorld->serializeToConfig();
Config::getInstance()->save();
$result["result"] = "saved";
}
}
return $result;
}
(/usr/local/opnsense/mvc/app/controllers/OPNsense/HelloWorld/Api/SettingsController.php)
And include the Config class from our base system by adding this to the
“use” section:
.. code-block:: php
use \OPNsense\Core\Config;
Support jQuery API calls
------------------------
.. rubric:: Update the view to support the API calls using jQuery
:name: update-the-view-to-support-the-api-calls-using-jquery
Now we need to link the events to the backend code to be able to load
and save our form, by using the OPNsense libraries you can validate your
data automatically.
Add this to the index.volt template from the HelloWorld module:
.. code-block:: html
<script type="text/javascript">
$( document ).ready(function() {
var data_get_map = {'frm_GeneralSettings':"/api/helloworld/settings/get"};
mapDataToFormUI(data_get_map).done(function(data){
// place actions to run after load, for example update form styles.
});
 
// link save button to API set action
$("#saveAct").click(function(){
saveFormToEndpoint(url="/api/helloworld/settings/set",formid='frm_GeneralSettings',callback_ok=function(){
// action to run after successful save, for example reconfigure service.
});
});
 
 
});
</script>
 
<div class="col-md-12">
<button class="btn btn-primary" id="saveAct" type="button"><b>{{ lang._('Save') }}</b></button>
</div>
The first piece of javascript code handles the loading of data when
opening the form, then a button is linked to the save event.
Lets give it a try and save our data, without modifying it first.
|Form with validation errors|
Next correct the errors and save again, on successful save the data
should be stored in the config.xml. If you want to change validation
messages, just edit the model xml and add your message in the
ValidationMessage tag. For example:
.. code-block:: xml
<ToEmail type="EmailField">
<Required>Y</Required>
<ValidationMessage>please specify a valid email address</ValidationMessage>
</ToEmail>
Changes the “email address invalid” into “please specify a valid email
address”
Add actions
-----------
.. rubric:: Add some activity to the module
:name: add-some-activity-to-the-module
Our basic module provides a way to read and modify configuration data
using the web interface (and in time also other consumers using the
api). Next step is to add some activity to our system, all backend
applications should use their own configuration, which in real life we
would keep as standard as possible.
For our example we will follow the same process as for any other service
and start writing some configuration data for our sample application.
Which means, creating a template and hooking it into our save action.
Our example will write a simple configuration file, stored in
/usr/local/etc/helloworld/helloworld.conf
The configd system is responsible for updating the contents of that file
when requested, it does so by using a definition found in its template
folder. This sample will use the following path to store the backend
templates:
::
/usr/local/opnsense/service/templates/OPNsense/HelloWorld/
First we add a content definition, by creating a file named +TARGETS,
which should hold the following information:
::
helloworld.conf:/usr/local/etc/helloworld/helloworld.conf
This basically tells the engine that there will be a file in the same
folder named “helloworld.conf” which provides, together with config.xml,
data for the file in /usr/local/etc/helloworld/helloworld.conf
Next thing to do is create that helloworld.conf file in the templates
directory. We will keep things very simple for this one and just copy in
our data into an ini file structured configuration, when the module is
enabled.
.. code-block:: html+jinja
{% if helpers.exists('OPNsense.helloworld.general') and OPNsense.helloworld.general.Enabled|default("0") == "1" %}
[general]
SMTPHost={{ OPNsense.helloworld.general.SMTPHost|default("") }}
FromEmail={{ OPNsense.helloworld.general.FromEmail|default("") }}
ToEmail={{ OPNsense.helloworld.general.ToEmail|default("") }}
Subject={{ OPNsense.helloworld.general.Description|default("") }}
{% endif %}
Now we need to be able to reload this module (or in real life, this
would probably be a service) by adding a service action into our
ServiceController. Edit
controllers/OPNsense/HelloWorld/Api/ServiceController.php and add the
backend module to the use section, like this:
.. code-block:: php
use \OPNsense\Core\Backend;
By doing this we can use the backend communication in this class. Next
add a new action to the class called “reloadAction” using this piece of
code:
.. code-block:: php
public function reloadAction()
{
$status = "failed";
if ($this->request->isPost()) {
$backend = new Backend();
$bckresult = trim($backend->configdRun("template reload OPNsense/HelloWorld"));
if ($bckresult == "OK") {
$status = "ok";
}
}
return array("status" => $status);
}
(/usr/local/opnsense/mvc/app/controllers/OPNsense/HelloWorld/Api/ServiceController.php)
This validates the type of action (it should always be POST to enable
csrf protection) and adds a backend action for reloading the template.
When successful the action will return “status”:”ok” as json object back
to the client.
Now we are able to refresh the template content, but the user interface
doesnt know about it yet. To hook loading of the template into the save
action, we will go back to the index.volt view and add the following
jQuery / framework code between the braces of “saveFormToEndPoint”.
.. code-block:: javascript
ajaxCall(url="/api/helloworld/service/reload", sendData={},callback=function(data,status) {
// action to run after reload
});
If you save the form now (when enabled), you should see a new file in
::
helloworld.conf:/usr/local/etc/helloworld/helloworld.conf
Containing something like this:
.. code-block:: ini
[general]
SMTPHost=127.0.0.1
FromEmail=sample@example.com
ToEmail=sample@example.com
Subject=test
What have we accomplished now, we can input data, validate it and save
it to the corresponding format of the actual service or application,
which uses this data. So if you have a third party application, which
you want to integrate into the user interface. You should be able to
generate what it needs now. (theres more to learn, but these are the
basics).
But how do should we control that third part program now? Thats the
next step.
----------------------
Controlling the sample
----------------------
In stead of running all kinds of shell commands directly from the php
code, which very often need root access (starting/stopping services,
etc), we should always communicate to our backend process which holds
templates of possible things to run and protects your system from
executing arbitrary commands.
Another advantage of this approach is that all commands defined here,
can also be ran from the command line of the firewall providing easier
serviceability. For example, the command to refresh the helloworld
configuration can be run from the command line by running:
::
configctl template reload OPNsense/HelloWorld
First thing to do when registering new actions to the system for a new
application is to create a config template.
::
/usr/local/opnsense/service/conf/actions.d/actions_helloworld.conf
And add a command to the template like this:
::
[test]
command:/usr/local/opnsense/scripts/OPNsense/HelloWorld/testConnection.py
parameters:
type:script_output
message:hello world module test
Lets test our new command by restarting configd from the command line:
::
service configd restart
And test our new command using:
::
configctl helloworld test
Which should return some response in json format.
Next step is to use this command in our controller (middleware), just
like we did with the template action. For consistency we call our action
testAction and let it pass json data to our clients when using a POST
type request.
.. code-block:: php
public function testAction()
{
if ($this->request->isPost()) {
$backend = new Backend();
$bckresult = json_decode(trim($backend->configdRun("helloworld test")), true);
if ($bckresult !== null) {
// only return valid json type responses
return $bckresult;
}
}
return array("message" => "unable to run config action");
}
(/usr/local/opnsense/mvc/app/controllers/OPNsense/HelloWorld/Api/ServiceController.php)
And now we can make our user interface aware of the action, place a
button and link an action in the index.volt. Using the following
elements:
|
| (in script section)
.. code-block:: javascript
$("#testAct").click(function(){
$("#responseMsg").removeClass("hidden");
ajaxCall(url="/api/helloworld/service/test", sendData={},callback=function(data,status) {
// action to run after reload
$("#responseMsg").html(data['message']);
});
});
(in html section)
.. code-block:: xml
<div class="alert alert-info hidden" role="alert" id="responseMsg">
 
</div>
<button class="btn btn-primary" id="testAct" type="button"><b>{{ lang._('Test') }}</b></button>
(/usr/local/opnsense/mvc/app/views/OPNsense/HelloWorld/index.volt)
Now go back to the page and save some data using the save button, next
press test to see some results.
|test the application action|
-----------------------------
Multi language / Translations
-----------------------------
OPNsense is available in may different languages like english, german or japanese.
This works because we are using the gettext library which is available to all GUI components.
While the XML based user interfaces are supporting it automatically,
there may still the need to call it manually (buttons, tabs etc.).
If you have a static string, you should add it like this into a classic php page:
.. code-block:: php
<?= gettext('your string here') ?>
And this way into a volt template:
.. code-block:: html+jinja
{{ lang._('your string here') }}
If your string is not only plaintext because it contains non-static words, HTML tags and other dynamic content,
you need to use a format string. This way, you can use placeholders for such elements which should not land in
the translation file.
For php it works this way:
.. code-block:: php
<?= sprintf(gettext('your %s here'), $data) ?>
And for volt templates it works this way:
.. code-block:: html+jinja
{{ lang._('your %s here') | format(data) }}
.. Note::
You should NEVER split strings which should belong together like a sentence.
This makes plugins hard to translate and will decrease the quality of OPNsense in other languages.
-------------------------
Plugin to the menu system
-------------------------
Most modules and applications need a place in the menu system, you could
easily arrange that by creating a Menu.xml definition for your module in
the model directory under Menu/Menu.xml.
Now lets register our “hello world” in the user section of our menu, by
adding this content into the menu.xml:
.. code-block:: xml
<menu>
<!-- Plugin HelloWorld menu -->
<User order="999">
<HelloWorld VisibleName="Hello World!" url="/ui/helloworld/"/>
</User>
</menu>
When you refresh your page now, you should notice the menu system
automatically picks up this new information.
|menu registration|
------------------------------
Plugin to access control (ACL)
------------------------------
If we want to authorize users to access this module, we can add an acl
to this module. Without it, only admin users can access it. Create an
xml file in the model directory name ACL/ACL.xml and place the following
content in it:
.. code-block:: xml
<acl>
<!-- unique acl key, must be globally unique for all acl's -->
<page-user-helloworld>
<name>WebCfg - Users: Hello World! </name>
<description>Allow access to the Hello World! module</description>
<patterns>
<pattern>ui/helloworld/*</pattern>
<pattern>api/helloworld/*</pattern>
</patterns>
</page-user-helloworld>
</acl>
This creates an acl key named “page-user-helloworld” which authorizes
access to both the ui and api urls of this application. You can now
grant access to this module from the system user manager.
|
----------------------------
Create an installable plugin
----------------------------
All files are created in their original locations (on the OPNsense
machine /usr/local/…), now we are ready to create a package from them.
To fully use this process and create the actual package, its best to
setup a full build environment (explained over here:
https://github.com/opnsense/tools )
When everything is in place, we will create a new plugin directory. For
this example we will use the following:
::
/usr/plugins/devel/helloworld/
Add a new Makefile, containing the information for our plugin:
.. code-block:: kconfig
PLUGIN_NAME= helloworld
PLUGIN_VERSION= 1.0
PLUGIN_COMMENT= A sample framework application
#PLUGIN_DEPENDS=
PLUGIN_MAINTAINER= user@domain
 
.include "../../Mk/plugins.mk"
|
| Then create an src directory in here:
::
/usr/plugins/devel/helloworld/src/
Next copy all files created and located in /usr/local/ into this new src
directory, which results in the following file listing:
::
src/opnsense/mvc/app/controllers/OPNsense/HelloWorld/Api/ServiceController.php
src/opnsense/mvc/app/controllers/OPNsense/HelloWorld/Api/SettingsController.php
src/opnsense/mvc/app/controllers/OPNsense/HelloWorld/IndexController.php
src/opnsense/mvc/app/controllers/OPNsense/HelloWorld/forms/general.xml
src/opnsense/mvc/app/models/OPNsense/HelloWorld/ACL/ACL.xml
src/opnsense/mvc/app/models/OPNsense/HelloWorld/HelloWorld.php
src/opnsense/mvc/app/models/OPNsense/HelloWorld/HelloWorld.xml
src/opnsense/mvc/app/models/OPNsense/HelloWorld/Menu/Menu.xml
src/opnsense/mvc/app/views/OPNsense/HelloWorld/index.volt
src/opnsense/scripts/OPNsense/HelloWorld/testConnection.py
src/opnsense/service/templates/OPNsense/HelloWorld/+TARGETS
src/opnsense/service/templates/OPNsense/HelloWorld/helloworld.conf
src/opnsense/service/conf/actions.d/actions_helloworld.conf
Next add a +POST\_INSTALL file in the plugin directory, to reload the
configd process after installation. This is needed for the new “test”
command to register.
.. code-block:: sh
if /usr/local/etc/rc.d/configd status > /dev/null; then
/usr/local/etc/rc.d/configd restart
fi
With everything in place, you could build the plugin package using the
“make plugins” command in the /usr/tools directory. The result of this
will be a standard pkg package, which you can install on any OPNsense
system and will be usable right after installing. All plugins are
prefixed with os-, our new package file will be called:
::
os-helloworld-1.0.txz
(-1.0 comes from the version in the makefile)
.. rubric:: Reference
:name: reference
- source of this example :
https://github.com/opnsense/plugins/tree/master/devel/helloworld
- build instructions : https://github.com/opnsense/tools
- frontend template language reference (Volt) :
https://docs.phalconphp.com/en/latest/reference/volt.html
- configuration template language reference (mostly the same as Volt) :
http://jinja.pocoo.org/docs/dev/
- OPNsense architecture :doc:`Architecture <../architecture>`
- OPNsense creating models
`Develop:Frontend/Creating\_models </index.php/Develop:Frontend/Creating_models>`__
.. |overview| image:: images/Helloworld_overview.png
:width: 700px
.. |Serving the first "hello world" page| image:: images/HelloWorld_Empty_template.png
:width: 884px
:height: 605px
.. |Template with fields without content| image:: images/HelloWorld_Template_no_content.png
:width: 889px
:height: 535px
.. |Form with validation errors| image:: images/HelloWorld_form_validation_error.png
:width: 1098px
:height: 525px
.. |test the application action| image:: images/HelloWorld_first_test_action.png
:width: 1403px
:height: 624px
.. |menu registration| image:: images/HelloWorld_menu_registration.png
:width: 1400px
:height: 639px

Binary file not shown.

After

Width:  |  Height:  |  Size: 242 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 77 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 73 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 118 KiB

View File

@ -0,0 +1,15 @@
========
Frontend
========
The OPNsense frontend is implemented with `PHP/Phalcon <https://en.wikipedia.org/wiki/Phalcon_(framework)>`__.
.. toctree::
:maxdepth: 2
:titlesonly:
:glob:
frontend/models
frontend/routing
frontend/controller
frontend/*

View File

@ -0,0 +1,101 @@
===========================
Using controllers and views
===========================
-------
General
-------
After routing is performed, the controller takes care of the actual code
to execute for the request. Because we want to implement some basics for
every request that gets processed you should inherit from our base
classes to ensure basic functionality such as authorisation and csrf
protection.
Controllers are placed in the directory /usr/local/opnsense/mvc/app/controllers/<Vendor\_name>/<Module\_name>/
and should use the standard Phalcon naming conventions, suffix Controller.php on
every class file and suffix Action on all action methods.
For a detailed description of how Controllers work in Phalcon, please
look at the Phalcon documentation at http://docs.phalconphp.com/en/latest/reference/controllers.html
----------------------
View based controllers
----------------------
For rendering standard pages we have chosen to use Volt templates, the
base controller to inherit from in this case is
OPNsense\\Base\\ControllerBase and should take care of binding a
template to the controller. Every template automatically receives
standard features (such as the menu system).
The wireframe for implementing a single action should look like this:
.. code-block:: php
<?php
public function indexAction()
{
// address some variables to pass through the view
$this->view->my_variable1 = 'test 1';
$this->view->my_variable2 = 'test 2';
// pick a template
$this->view->pick('SampleVendor/Sample/index');
}
And the volt template SampleVendor/Sample/index.volt could contain something like:
.. code-block:: html
the contents of my_variable1 => <b> {{ my_variable1 }} </b> <br>
the contents of my_variable2 => <b> {{ my_variable2 }} </b> <br>
A full example can be found in the OPNsense\\Sample controller
directory.
More information on how to write Volt pages can be found here :
http://docs.phalconphp.com/en/latest/reference/volt.html
---------------------
API based controllers
---------------------
For API calls a separate class is used to derive from, which implements
a simple interface to handle calls. The main difference with the view
controllers is that an action should return a named array containing
response data in stead of picking a template.
A simple index controller to echo a request back looks like this:
.. code-block:: php
class TestController extends ApiControllerBase
{
/**
* @return array
*/
public function echoAction()
{
if ($this->request->hasPost("message")) {
$message = $this->request->getPost("message");
} else {
$message = " " ;
}
 
return array("message" => $message);
}
}
When placed inside the api directory of Vendor/Sample can be called by sending a
post request to /api/sample/test/echo, using jquery:
.. code-block:: javascript
$.ajax({
type: "POST",
url: "/api/sample/test/echo",
success: function(data){
alert(data.message) ;
},
data:{message:"test message"}
});

View File

@ -0,0 +1,202 @@
===============
Creating Models
===============
A model represents the data which the application will use and takes
care of the interaction to that data. In OPNsense most of the relevant
data is physically stored in an xml structure (config.xml). The primary
goal for OPNsense models is to structure the use of configuration data,
by creating a clear abstraction layer.
In this chapter we will explain how models are designed and build.
-------------------
Designing the model
-------------------
Creating models for OPNsense is divided into two separate blocks:
#. A php class describing the actions on our data (also acts as a
wrapper to our data),
#. The definition of the data and the rules it should apply to.
Every model's class should be derived from OPNsense\\Base\\BaseModel, a very
simple model without any (additional) logic is defined with:
.. code-block:: php
<?php
namespace myVendorName\myModule;
 
use OPNsense\Base\BaseModel;
 
class myModel extends BaseModel
{
}
This class should be placed inside the model directory of our project, in this
case the full path for our class file would be
- /usr/local/opnsense/mvc/app/models/**myVendorName/myModule/myModel.php**
When you design a model, the next thing to do is to figure out what data is
relevant for your application or module and think of the rules it should comply
to (for example, if you need an email address you might want to validate the
input). Designing the actual model is as simple as creating an xml file and
putting in your structure, the name of our xml file should be the same as the
base name of our model suffixed by .xml.
Using the same model, we would create the following file:
- /usr/local/opnsense/mvc/app/models/**myVendorName/myModule/myModel.xml**
And start describing our (information) model, like this:
.. code-block:: xml
<model>
<mount>//myManufacturer/myModule</mount>
<description>A description of this model (metadata)</description>
<items>
<exampleNumber type="TextField">
<Mask>/^([0-9]){0,1}$/</Mask>
<Default>5</Default>
<ValidationMessage>you should input a number from 0 to 9</ValidationMessage>
</exampleNumber>
<contacts>
<entity type="ArrayField">
<email type="EmailField">
<ValidationMessage>you should input a valid email address!</ValidationMessage>
</email>
<name type="TextField"/>
</entity>
<someText type="TextField"/>
</contacts>
</items>
</model>
Now let's explain what's happing here one tag at a time.
#. the <model> tag is used for identification of the file. (this is a
model file)
#. Next in line is the <mount> tag, this tells the system where this
information lives in the configuration file, in this case
ROOT\_tag/myManufacturer/myModule
#. If desired, there is some space reserved to explain the usage of the
model, the <description> tag
#. Last item on the top of our list is the <items> tag, this is where
the magic begins.
The content of a items tag describes the full tree based structure which holds
our data, in theory this could be as large as you want it to be, but keep in
mind that the content for your model should be logical and understandable. Every
node in the tree could have a type, which defines it's behavior, nodes without a
type are just containers.
From top to bottom we find the following nodes in our tree:
- exampleNumber, defined as a TextField
- Mask, validation can be performed by a regex expression, this sets
the expression
- Default, this field is default filled with a number: 5
- ValidationMessage, when validation fails, this message is returned
- contacts, this is a container
- entity, is defined as a recurring item, which holds the next items
- email, defined as an EmailField
- when validation fails, the **ValidationMessage** is returned
- name, defined as a TextField without any validations
- someText, not part of the entity tag and also defined as text without
validation
The fieldtypes are easily extendable in the base system and they all live in
their own namespace at *OPNsense\\Base\\FieldTypes* deriving from *BaseField*.
-------------
Usage example
-------------
Now let's test our model using a small php script (in /usr/local/opnsense/mvc/script/ ):
.. code-block:: php
<?php
// initialize phalcon components for our script
require_once("load_phalcon.php");
 
// include myModel and the shared config component
use myVendorName\myModule\myModel;
use OPNsense\Core\Config;
 
// create a new model, reading the model definition and the current data from our config.xml
$myMdl = new myModel();
$myMdl->exampleNumber =1;
$myMdl->contacts->someText = "just a test";
 
// add a new contact node
$node = $myMdl->contacts->entity->add();
$node->email = "test@test.com";
$node->name = "my test user";
 
// perform validation on the data in our model
$validationMessages = $myMdl->performValidation();
foreach ($validationMessages as $messsage) {
echo "validation failure on field ". $messsage->getField()." returning message : ". $messsage->getMessage()."\n";
}
 
// if validation succeeded, write data back to config
if ($validationMessages->count() == 0) {
// serialize our model to the config file (config.xml)
// (this raises an error on validation failures)
$myMdl->serializeToConfig();
$cnf = Config::getInstance();
$cnf->save();
}
If you fill in an invalid value to one of the validated fields, you can easily
try the validation. Try to input the text "X" into the field exampleNumber to try out.
When inspecting our config.xml file, you will notice the following content has
been added to the root:
.. code-block:: xml
<myManufacturer>
<myModule>
<exampleNumber>1</exampleNumber>
<contacts>
<entity>
<email>test@test.com</email>
<name>my test user</name>
</entity>
<someText>just a test</someText>
</contacts>
</myModule>
</myManufacturer>
----------
Guidelines
----------
.. rubric:: Some (simple) guidelines developing models
:name: some-simple-guidelines-developing-models
#. One model should always be completely responsible for the its mount
point, so if there's a model at mount point /A/B there can't be a
model at /A/B/C
#. Try to keep models logical and understandable, it's better to build
two models for you application if the content of two parts aren't
related to each other. It's no issue to create models at deeper
levels of the structure.
#. When using more models in a application/module, you might want to
consider the following naming convention: /Vendor/Module/Model
#. Try to avoid more disc i/o actions than necessary, only call save()
if you actually want to save content, serializeToConfig just keeps
the data in memory.

View File

@ -0,0 +1,85 @@
=======
Routing
=======
-------
General
-------
To retain backward compatibility with legacy code, we try to keep the
old pages at their original location. For the new code, we define two
root folders in the url:
- /ui/ for the new user interface parts
- /api/ used for webservices (REST)
This part of the routing is handled by lighthttpd using mod\_alias and mod\_rewrite.
----------------------
User interface Routing
----------------------
If you look at the controller directory in OPNsense, you will notice
there are different directory levels under the root controller directory
in /usr/local/opnsense/mvc/app/controllers. To support different apps
and vendors eventually, we already used a structure which is
automatically used to setup the routing.
At the first level we use the vendor of the app, in our case that will
always be OPNsense.
The next level is used to name the topic (or app), for example we use
Sample for our example application.
Finally you may place your standard Phalcon classes for controllers in
that directory, so if you want to create a page helloworld, that should
come with a controller helloworldController.php (and a indexAction to
define the index action for that page).
The complete path of the helloworld page would eventually be:
::
/usr/local/opnsense/mvc/app/controllers/OPNsense/Sample/helloworldController.php
When publishing the page, the vendor part of the controller is not used in the
mapping, so in this example the helloworld index page will be at:
::
https://{url}/ui/sample/helloworld/
All the parts of the url are automatically converted to lower-case, so **S**\ample
will be mapped to **s**\ample.
This routing is setup via the index page of our new code base and uses
::
/usr/local/opnsense/mvc/app/config/services.php to wire it all together.
-----------
API routing
-----------
Routing for api functions is quite similar to routing UI components,
just create a Api directory under the app path and place a controller
class to handle the request. The only major difference is that it's
handled by a separate php file (called api.php) in stead of the
index.php file used to configure the ui part, details of the routing can
be found in /usr/local/opnsense/mvc/app/config/services\_api.php .
If our sample app needs an api to echo something back via a controller called
tools it could be put into a file called:
::
/usr/local/opnsense/mvc/app/controllers/OPNsense/Sample/Api/toolsController.api
And called via the following url:
::
https://{host}}/api/sample/tools/echo
When the controller has a method called echoAction.

View File

@ -0,0 +1,18 @@
==================
Coding Guidelines
==================
.. image:: images/guidelines_new.png
------------------
.. toctree::
:maxdepth: 2
:titlesonly:
:glob:
guidelines/basics
guidelines/psr1
guidelines/psr2
guidelines/peps
guidelines/*

View File

@ -0,0 +1,92 @@
=================
Basics and Future
=================
This article explains the basic coding guidelines that apply and put the
development effort into perspective by explaining the difficulties of legacy
code and the interaction/migration to new MVC-based code. It also explains guideline
differences between new and legacy code.
--------
PHP code
--------
For PHP code the PSR1 and PSR2 Coding Standard apply.
------
Python
------
For Python code the Python Enhancement Proposals (PEPs) apply.
See the `Python Developer's Guide <https://www.python.org/dev/>`__ for detailed
information.
------------
Architecture
------------
Documentation is available about our :doc:`architecture </development/architecture>`
and used :doc:`components </development/components>`.
-----------------
Ideal Development
-----------------
Our ideal OPNsense system looks like a standard FreeBSD system using our
pluggable user interface for management, which supports both real users as "machine"
users (REST).
When developing we want the code to be clean and coded as DRY (Don't Repeat Yourself)
as possible and do not want to invent the wheel when not needed.
The user interface should to be able to run as non-root user instead of root by
restructuring the way commands are passed to the system (configd).
----------------------------
Reality: Overdue Maintenance
----------------------------
In reality we forked a system that went without code maintenance for a very long
time and we needed to transition that into something more structured.
One of the first things (on the programming part of the system) we did was build
components around an existing framework (Phalcon) to create new modules, which
could use validated configuration data (from the config.xml), supply a RESTful
API and generate html output using standard templates (Volt).
We created the configd system, which can generate system configuration and
execute system calls using predefined templates. And then we started using those
new components for our first newly designed modules (like the proxy and the traffic shaper).
More information about the “to-be” architecture can be found in our
:doc:`architecture </development/architecture>` documentation.
---------
Strategy
---------
Knowing we cant change the world in a single day and having a lot of legacy to
drag around with us, our strategy consists of three parts:
**1)** Cleanup and maintenance
Restructure old (legacy) code, basically all code in the src/www, src/etc/inc to
make it better readable, easier to use and remove unused / unnecessary parts. By
doing so we want to extend the lifetime of the old code a bit and make the
transition in new code easier eventually.
**2)** Detach
Move system configuration calls to configd where possible, which gives the
administrator the advantage of running those commands from the command line and
helps removing the need for root user access in the future. The ipsec VICI
implementation is one example of this stage.
**3)** Moving on
(re)build new parts, using our new modules, which provide a layered development
system to automatically support api calls from other systems and xml based model
templates to describe configuration data.
*See also:*
* :doc:`Hello World Module </development/examples/helloworld>`
* :doc:`Howto use the API </development/how-tos/api>`
Our guidelines somewhat depend of the stage the code is in, when writing new code,
all actions should use the api system for actually changing configuration and
performing configuration tasks. They should, of course, use the normal PSR coding
standards for php code and follow the python peps.
When moving to the legacy part of the system, our goal is to stick as close to
PSR1/2 as possible, knowing it will never be perfect.

View File

@ -0,0 +1,7 @@
===========
Python PEPs
===========
For Python code the Python Enhancement Proposals (PEPs) apply.
See the `Python Developer's Guide <https://www.python.org/dev/>`__ for detailed
information.

View File

@ -0,0 +1,196 @@
===========================
PSR-1 Basic Coding Standard
===========================
.. Note::
| The PSR1 and PSR2 Coding Standards are provided by FIG under a MIT license.
| See license details: http://www.php-fig.org/bylaws/licensing-policies/
| The original content of this page can be found at `php-fig <http://www.php-fig.org/psr/psr-1/>`__
This section of the standard comprises what should be considered the
standard coding elements that are required to ensure a high level of
technical interoperability between shared PHP code.
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
"SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
document are to be interpreted as described in `RFC
2119 <http://www.ietf.org/rfc/rfc2119.txt>`__.
-----------
1. Overview
-----------
- Files MUST use only ``<?php`` and ``<?=`` tags.
- Files MUST use only UTF-8 without BOM for PHP code.
- Files SHOULD *either* declare symbols (classes, functions, constants,
etc.) *or* cause side-effects (e.g. generate output, change .ini
settings, etc.) but SHOULD NOT do both.
- Namespaces and classes MUST follow an "autoloading" PSR:
[`PSR-0 <https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-0.md>`__,
`PSR-4 <https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-4-autoloader.md>`__].
- Class names MUST be declared in ``StudlyCaps``.
- Class constants MUST be declared in all upper case with underscore
separators.
- Method names MUST be declared in ``camelCase``.
--------
2. Files
--------
2.1. PHP Tags
-------------
PHP code MUST use the long ``<?php ?>`` tags or the short-echo
``<?= ?>`` tags; it MUST NOT use the other tag variations.
2.2. Character Encoding
-----------------------
PHP code MUST use only UTF-8 without BOM.
2.3. Side Effects
-----------------
A file SHOULD declare new symbols (classes, functions, constants, etc.)
and cause no other side effects, or it SHOULD execute logic with side
effects, but SHOULD NOT do both.
The phrase "side effects" means execution of logic not directly related
to declaring classes, functions, constants, etc., *merely from including
the file*.
"Side effects" include but are not limited to: generating output,
explicit use of ``require`` or ``include``, connecting to external
services, modifying ini settings, emitting errors or exceptions,
modifying global or static variables, reading from or writing to a file,
and so on.
The following is an example of a file with both declarations and side
effects; i.e, an example of what to avoid:
.. code-block:: php
<?php
// side effect: change ini settings
ini_set('error_reporting', E_ALL);
// side effect: loads a file
include "file.php";
// side effect: generates output
echo "<html>\n";
// declaration
function foo()
{
// function body
}
The following example is of a file that contains declarations without
side effects; i.e., an example of what to emulate:
.. code-block:: php
<?php
// declaration
function foo()
{
// function body
}
// conditional declaration is *not* a side effect
if (! function_exists('bar')) {
function bar()
{
// function body
}
}
----------------------------
3. Namespace and Class Names
----------------------------
Namespaces and classes MUST follow an "autoloading" PSR:
[`PSR-0 <https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-0.md>`__,
`PSR-4 <https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-4-autoloader.md>`__].
This means each class is in a file by itself, and is in a namespace of
at least one level: a top-level vendor name.
Class names MUST be declared in ``StudlyCaps``.
Code written for PHP 5.3 and after MUST use formal namespaces.
For example:
.. code-block:: php
<?php
// PHP 5.3 and later:
namespace Vendor\Model;
class Foo
{
}
Code written for 5.2.x and before SHOULD use the pseudo-namespacing
convention of ``Vendor_`` prefixes on class names.
.. code-block:: php
<?php
// PHP 5.2.x and earlier:
class Vendor_Model_Foo
{
}
-------------------------------------------
4. Class Constants, Properties, and Methods
-------------------------------------------
The term "class" refers to all classes, interfaces, and traits.
4.1. Constants
--------------
Class constants MUST be declared in all upper case with underscore
separators. For example:
.. code-block:: php
<?php
namespace Vendor\Model;
class Foo
{
const VERSION = '1.0';
const DATE_APPROVED = '2012-06-01';
}
4.2. Properties
---------------
This guide intentionally avoids any recommendation regarding the use of
``$StudlyCaps``, ``$camelCase``, or ``$under_score`` property names.
Whatever naming convention is used SHOULD be applied consistently within
a reasonable scope. That scope may be vendor-level, package-level,
class-level, or method-level.
4.3. Methods
------------
Method names MUST be declared in ``camelCase()``.

View File

@ -0,0 +1,656 @@
========================
PSR-2 Coding Style Guide
========================
.. Note::
| The PSR1 and PSR2 Coding Standards are provided by FIG under a MIT license.
| See license details: http://www.php-fig.org/bylaws/licensing-policies/
| The original content of this page can be found at `php-fig <http://www.php-fig.org/psr/psr-2/>`__
This guide extends and expands on
`PSR-1 <https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-1-basic-coding-standard.md>`__,
the basic coding standard.
The intent of this guide is to reduce cognitive friction when scanning code from
different authors. It does so by enumerating a shared set of rules and expectations
about how to format PHP code.
The style rules herein are derived from commonalities among the various member
projects. When various authors collaborate across multiple projects, it helps to
have one set of guidelines to be used among all those projects. Thus, the benefit
of this guide is not in the rules themselves, but in the sharing of those rules.
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
"SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
document are to be interpreted as described in `RFC
2119 <http://www.ietf.org/rfc/rfc2119.txt>`__.
-----------
1. Overview
-----------
- Code MUST follow a "coding style guide" PSR
[`PSR-1 <https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-1-basic-coding-standard.md>`__].
- Code MUST use 4 spaces for indenting, not tabs.
- There MUST NOT be a hard limit on line length; the soft limit MUST be
120 characters; lines SHOULD be 80 characters or less.
- There MUST be one blank line after the ``namespace`` declaration, and
there MUST be one blank line after the block of ``use`` declarations.
- Opening braces for classes MUST go on the next line, and closing
braces MUST go on the next line after the body.
- Opening braces for methods MUST go on the next line, and closing
braces MUST go on the next line after the body.
- Visibility MUST be declared on all properties and methods;
``abstract`` and ``final`` MUST be declared before the visibility;
``static`` MUST be declared after the visibility.
- Control structure keywords MUST have one space after them; method and
function calls MUST NOT.
- Opening braces for control structures MUST go on the same line, and
closing braces MUST go on the next line after the body.
- Opening parentheses for control structures MUST NOT have a space
after them, and closing parentheses for control structures MUST NOT
have a space before.
1.1. Example
------------
This example encompasses some of the rules below as a quick overview:
.. code-block:: php
<?php
namespace Vendor\Package;
use FooInterface;
use BarClass as Bar;
use OtherVendor\OtherPackage\BazClass;
class Foo extends Bar implements FooInterface
{
public function sampleFunction($a, $b = null)
{
if ($a === $b) {
bar();
} elseif ($a > $b) {
$foo->bar($arg1);
} else {
BazClass::bar($arg2, $arg3);
}
}
final public static function bar()
{
// method body
}
}
----------
2. General
----------
2.1 Basic Coding Standard
-------------------------
Code MUST follow all rules outlined in
`PSR-1 <https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-1-basic-coding-standard.md>`__.
2.2 Files
---------
All PHP files MUST use the Unix LF (linefeed) line ending.
All PHP files MUST end with a single blank line.
The closing ``?>`` tag MUST be omitted from files containing only PHP.
2.3. Lines
----------
There MUST NOT be a hard limit on line length.
The soft limit on line length MUST be 120 characters; automated style
checkers MUST warn but MUST NOT error at the soft limit.
Lines SHOULD NOT be longer than 80 characters; lines longer than that
SHOULD be split into multiple subsequent lines of no more than 80
characters each.
There MUST NOT be trailing whitespace at the end of non-blank lines.
Blank lines MAY be added to improve readability and to indicate related
blocks of code.
There MUST NOT be more than one statement per line.
2.4. Indenting
--------------
Code MUST use an indent of 4 spaces, and MUST NOT use tabs for
indenting.
.. Note::
N.b.: Using only spaces, and not mixing spaces with tabs, helps to
avoid problems with diffs, patches, history, and annotations. The
use of spaces also makes it easy to insert fine-grained
sub-indentation for inter-line alignment.
2.5. Keywords and True/False/Null
---------------------------------
PHP `keywords <http://php.net/manual/en/reserved.keywords.php>`__ MUST
be in lower case.
The PHP constants ``true``, ``false``, and ``null`` MUST be in lower
case.
---------------------------------
3. Namespace and Use Declarations
---------------------------------
When present, there MUST be one blank line after the ``namespace``
declaration.
When present, all ``use`` declarations MUST go after the ``namespace``
declaration.
There MUST be one ``use`` keyword per declaration.
There MUST be one blank line after the ``use`` block.
For example:
.. code-block:: php
<?php
namespace Vendor\Package;
use FooClass;
use BarClass as Bar;
use OtherVendor\OtherPackage\BazClass;
// ... additional PHP code ...
-----------------------------------
4. Classes, Properties, and Methods
-----------------------------------
The term "class" refers to all classes, interfaces, and traits.
4.1. Extends and Implements
---------------------------
The ``extends`` and ``implements`` keywords MUST be declared on the same
line as the class name.
The opening brace for the class MUST go on its own line; the closing
brace for the class MUST go on the next line after the body.
.. code-block:: php
<?php
namespace Vendor\Package;
use FooClass;
use BarClass as Bar;
use OtherVendor\OtherPackage\BazClass;
class ClassName extends ParentClass implements \ArrayAccess, \Countable
{
// constants, properties, methods
}
Lists of ``implements`` MAY be split across multiple lines, where each
subsequent line is indented once. When doing so, the first item in the
list MUST be on the next line, and there MUST be only one interface per
line.
.. code-block:: php
<?php
namespace Vendor\Package;
use FooClass;
use BarClass as Bar;
use OtherVendor\OtherPackage\BazClass;
class ClassName extends ParentClass implements
\ArrayAccess,
\Countable,
\Serializable
{
// constants, properties, methods
}
4.2. Properties
---------------
Visibility MUST be declared on all properties.
The ``var`` keyword MUST NOT be used to declare a property.
There MUST NOT be more than one property declared per statement.
Property names SHOULD NOT be prefixed with a single underscore to
indicate protected or private visibility.
A property declaration looks like the following.
.. code-block:: php
<?php
namespace Vendor\Package;
class ClassName
{
public $foo = null;
}
4.3. Methods
------------
Visibility MUST be declared on all methods.
Method names SHOULD NOT be prefixed with a single underscore to indicate
protected or private visibility.
Method names MUST NOT be declared with a space after the method name.
The opening brace MUST go on its own line, and the closing brace MUST go
on the next line following the body. There MUST NOT be a space after the
opening parenthesis, and there MUST NOT be a space before the closing
parenthesis.
A method declaration looks like the following. Note the placement of
parentheses, commas, spaces, and braces:
.. code-block:: php
<?php
namespace Vendor\Package;
class ClassName
{
public function fooBarBaz($arg1, &$arg2, $arg3 = [])
{
// method body
}
}
4.4. Method Arguments
---------------------
In the argument list, there MUST NOT be a space before each comma, and
there MUST be one space after each comma.
Method arguments with default values MUST go at the end of the argument
list.
.. code-block:: php
<?php
namespace Vendor\Package;
class ClassName
{
public function foo($arg1, &$arg2, $arg3 = [])
{
// method body
}
}
Argument lists MAY be split across multiple lines, where each subsequent
line is indented once. When doing so, the first item in the list MUST be
on the next line, and there MUST be only one argument per line.
When the argument list is split across multiple lines, the closing
parenthesis and opening brace MUST be placed together on their own line
with one space between them.
.. code-block:: php
<?php
namespace Vendor\Package;
class ClassName
{
public function aVeryLongMethodName(
ClassTypeHint $arg1,
&$arg2,
array $arg3 = []
) {
// method body
}
}
4.5. ``abstract``, ``final``, and ``static``
--------------------------------------------
When present, the ``abstract`` and ``final`` declarations MUST precede
the visibility declaration.
When present, the ``static`` declaration MUST come after the visibility
declaration.
.. code-block:: php
<?php
namespace Vendor\Package;
abstract class ClassName
{
protected static $foo;
abstract protected function zim();
final public static function bar()
{
// method body
}
}
4.6. Method and Function Calls
------------------------------
When making a method or function call, there MUST NOT be a space between
the method or function name and the opening parenthesis, there MUST NOT
be a space after the opening parenthesis, and there MUST NOT be a space
before the closing parenthesis. In the argument list, there MUST NOT be
a space before each comma, and there MUST be one space after each comma.
.. code-block:: php
<?php
bar();
$foo->bar($arg1);
Foo::bar($arg2, $arg3);
Argument lists MAY be split across multiple lines, where each subsequent
line is indented once. When doing so, the first item in the list MUST be
on the next line, and there MUST be only one argument per line.
.. code-block:: php
<?php
$foo->bar(
$longArgument,
$longerArgument,
$muchLongerArgument
);
---------------------
5. Control Structures
---------------------
The general style rules for control structures are as follows:
- There MUST be one space after the control structure keyword
- There MUST NOT be a space after the opening parenthesis
- There MUST NOT be a space before the closing parenthesis
- There MUST be one space between the closing parenthesis and the
opening brace
- The structure body MUST be indented once
- The closing brace MUST be on the next line after the body
The body of each structure MUST be enclosed by braces. This standardizes
how the structures look, and reduces the likelihood of introducing
errors as new lines get added to the body.
5.1. ``if``, ``elseif``, ``else``
---------------------------------
An ``if`` structure looks like the following. Note the placement of
parentheses, spaces, and braces; and that ``else`` and ``elseif`` are on
the same line as the closing brace from the earlier body.
.. code-block:: php
<?php
if ($expr1) {
// if body
} elseif ($expr2) {
// elseif body
} else {
// else body;
}
The keyword ``elseif`` SHOULD be used instead of ``else if`` so that all
control keywords look like single words.
5.2. ``switch``, ``case``
-------------------------
A ``switch`` structure looks like the following. Note the placement of
parentheses, spaces, and braces. The ``case`` statement MUST be indented
once from ``switch``, and the ``break`` keyword (or other terminating
keyword) MUST be indented at the same level as the ``case`` body. There
MUST be a comment such as ``// no break`` when fall-through is
intentional in a non-empty ``case`` body.
.. code-block:: php
<?php
switch ($expr) {
case 0:
echo 'First case, with a break';
break;
case 1:
echo 'Second case, which falls through';
// no break
case 2:
case 3:
case 4:
echo 'Third case, return instead of break';
return;
default:
echo 'Default case';
break;
}
5.3. ``while``, ``do while``
----------------------------
A ``while`` statement looks like the following. Note the placement of
parentheses, spaces, and braces.
.. code-block:: php
<?php
while ($expr) {
// structure body
}
Similarly, a ``do while`` statement looks like the following. Note the
placement of parentheses, spaces, and braces.
.. code-block:: php
<?php
do {
// structure body;
} while ($expr);
5.4. ``for``
------------
A ``for`` statement looks like the following. Note the placement of
parentheses, spaces, and braces.
.. code-block:: php
<?php
for ($i = 0; $i < 10; $i++) {
// for body
}
5.5. ``foreach``
----------------
A ``foreach`` statement looks like the following. Note the placement of
parentheses, spaces, and braces.
.. code-block:: php
<?php
foreach ($iterable as $key => $value) {
// foreach body
}
5.6. ``try``, ``catch``
-----------------------
A ``try catch`` block looks like the following. Note the placement of
parentheses, spaces, and braces.
.. code-block:: php
<?php
try {
// try body
} catch (FirstExceptionType $e) {
// catch body
} catch (OtherExceptionType $e) {
// catch body
}
-----------
6. Closures
-----------
Closures MUST be declared with a space after the ``function`` keyword,
and a space before and after the ``use`` keyword.
The opening brace MUST go on the same line, and the closing brace MUST
go on the next line following the body.
There MUST NOT be a space after the opening parenthesis of the argument
list or variable list, and there MUST NOT be a space before the closing
parenthesis of the argument list or variable list.
In the argument list and variable list, there MUST NOT be a space before
each comma, and there MUST be one space after each comma.
Closure arguments with default values MUST go at the end of the argument
list.
A closure declaration looks like the following. Note the placement of
parentheses, commas, spaces, and braces:
.. code-block:: php
<?php
$closureWithArgs = function ($arg1, $arg2) {
// body
};
$closureWithArgsAndVars = function ($arg1, $arg2) use ($var1, $var2) {
// body
};
Argument lists and variable lists MAY be split across multiple lines,
where each subsequent line is indented once. When doing so, the first
item in the list MUST be on the next line, and there MUST be only one
argument or variable per line.
When the ending list (whether or arguments or variables) is split across
multiple lines, the closing parenthesis and opening brace MUST be placed
together on their own line with one space between them.
The following are examples of closures with and without argument lists
and variable lists split across multiple lines.
.. code-block:: php
<?php
$longArgs_noVars = function (
$longArgument,
$longerArgument,
$muchLongerArgument
) {
// body
};
$noArgs_longVars = function () use (
$longVar1,
$longerVar2,
$muchLongerVar3
) {
// body
};
$longArgs_longVars = function (
$longArgument,
$longerArgument,
$muchLongerArgument
) use (
$longVar1,
$longerVar2,
$muchLongerVar3
) {
// body
};
$longArgs_shortVars = function (
$longArgument,
$longerArgument,
$muchLongerArgument
) use ($var1) {
// body
};
$shortArgs_longVars = function ($arg) use (
$longVar1,
$longerVar2,
$muchLongerVar3
) {
// body
};
Note that the formatting rules also apply when the closure is used
directly in a function or method call as an argument.
.. code-block:: php
<?php
$foo->bar(
$arg1,
function ($arg2) use ($var1) {
// body
},
$arg3
);
-------------
7. Conclusion
-------------
There are many elements of style and practice intentionally omitted by
this guide. These include but are not limited to:
- Declaration of global variables and global constants
- Declaration of functions
- Operators and assignment
- Inter-line alignment
- Comments and documentation blocks
- Class name prefixes and suffixes
- Best practices
Future recommendations MAY revise and extend this guide to address those or other
elements of style and practice.

View File

@ -0,0 +1,121 @@
===========
Use the API
===========
--------
Overview
--------
All components that are using the full architecture of OPNsense
automatically receive API capabilities, for this simple tutorial we use
the firmware module but others will function in the same way. API access
is part of the local user authentication system, but uses key/secret
pairs to separate account information from machine to machine
communication. Secrets are not stored on OPNsense and can be downloaded
only once, if lost, a new key has to be generated for your application.
A user can have multiple keys, our advice is to create a unique key for
every application in use.
-------------
Creating keys
-------------
API keys are managed in the user manager (system\_usermanager.php), go
to the user manager page and select a user. Somewhere down the page you
will find the api section for this user.
|Usermanager add api key.png|
Click on the + sign to add a new key. When the key is created, you will
receive a (single download) with the credentials in one text file (ini
formatted). The contents of this file look like this:
.. code-block:: c
key=w86XNZob/8Oq8aC5r0kbNarNtdpoQU781fyoeaOBQsBwkXUt
secret=XeD26XVrJ5ilAc/EmglCRC+0j2e57tRsjHwFepOseySWLM53pJASeTA3
--------------------
Code sample (python)
--------------------
For the python code sample we use the nice "requests" library
(http://docs.python-requests.org/en/latest/), which makes http calls
very easy.
Before you can start, make sure your OPNsense has a valid SSL
certificate (or choose to ignore it for testing purposes by setting
verify=False), don't forget to verify that the selected user may access
the firmware page.
The web interface uses the same logic that will be available for the
api, in this example we will collect some status information from the
firmware module and print it out for the user.
It all starts with creating the request and waiting for the response,
all data interaction is using json format, both for the responses as for
the request data (when sending POST data).
First step of the example is importing the required libraries, then
define the endpoint url and credentials to use and finally fire the (get
type) request. As soon as we receive the response, we parse the json
string back to a dictionary and print some data depending on the
response.
.. code-block:: php
# import libraries
import json
import requests
# define endpoint and credentials
api_key = 'w86XNZob/8Oq8aC5hxh2he+vLN00r0kbNarNtdpoQU781fyoeaOBQsBwkXUt'
api_secret = 'puOyw0Ega3xZXeD26XVrJ5WYFepOseySWLM53pJASeTA3'
url = 'https://192.168.1.1/api/core/firmware/status'
 
# request data
r = requests.get(url,
verify='OPNsense.pem',
auth=(api_key, api_secret))
if r.status_code == 200:
response = json.loads(r.text)
if response['status'] == 'ok' and response['status_upgrade_action'] == 'all':
print ('OPNsense can be upgraded')
print ('download size : %s' % response['download_size'])
print ('number of packages : %s' % response['updates'])
if response['upgrade_needs_reboot'] == '1':
print ('REBOOT REQUIRED')
elif response['status'] == 'ok' and response['status_upgrade_action'] == 'pkg':
print ('OPNsense can be upgraded, but needs a pkg upgrade first')
elif 'status_msg' in response:
print (response['status_msg'])
else:
print ('Connection / Authentication issue, response received:')
print r.text
----------
Using curl
----------
Simple testing with curl is also possible, the sample below uses the
same credentials, but ignores the ssl certificate check (-k) for
testing.
.. code-block:: sh
curl -k -u "w86XNZob/8Oq8aC5hxh2he+vLN00r0kbNarNtdpoQU781fyoeaOBQsBwkXUt":"puOyw0Ega3xZXeD26XVrJ5WYFepOseySWLM53pJASeTA3" https://192.168.1.1/api/core/firmware/status
And schedule the actual upgrade of all packages using:
.. code-block:: sh
curl -XPOST -d '{"upgrade":"all"}' -H "Content-Type: application/json" -k -u "w86XNZob/8Oq8aC5hxh2he+vLN00r0kbNarNtdpoQU781fyoeaOBQsBwkXUt":"puOyw0Ega3xZXeD26XVrJ5WYFepOseySWLM53pJASeTA3" https://10.211.55.100/api/core/firmware/upgrade
.. |Usermanager add api key.png| image:: images/Usermanager_add_api_key.png
:width: 700px

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

View File

@ -0,0 +1,10 @@
====================================
How to's
====================================
.. toctree::
:maxdepth: 2
:titlesonly:
:glob:
how-tos/*

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 111 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 523 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 92 KiB

View File

@ -0,0 +1,181 @@
====================
Development Workflow
====================
.. image:: images/flow.png
Its pretty hard to approach a larger repository you have never
worked with. The biggest issue is that few projects have defined
development (as in actual coding) workflow laid out for new
contributors, so one is just going to be stabbing in the dark for a few
days or weeks until things start making sense. Speaking of *sense*,
lets explain how weve designed the development experience for
`OPNsense <https://opnsense.org/developers-invitation/>`__ and how you
can start contributing code in no time.
---------
Structure
---------
.. rubric:: Source, Ports, Core, Tools
:name: structure-source-ports-core-tools
The structure is pretty much FreeBSD: we have a `source
code <https://github.com/opnsense/src>`__ repository and a `ports
tree <https://github.com/opnsense/ports>`__. Historically, we also have
a `core code <https://github.com/opnsense/core>`__ and `tools
repository <https://github.com/opnsense/tools>`__. The tools repository
is project shell code gluing all repositories together, producing final
images, while the core is the important GUI and system configuration
bits.
.. Note::
As of 16.1 there is also plugin support, the source repository is `plugins tree <https://github.com/opnsense/plugins>`__ .
Plugins are a modular way of easily extending the existing system.
.. rubric:: Why core is not a part of source
:name: core-not-part-of-source
The first thing thats interesting is that the core is not part of
the source repository, because it depends on third party software found in the
ports. We cant stick core into source, because ports are things that
dont fit into the base system. It also helps to keep source repository
changes to the minimum to make major FreeBSD upgrades easier in the
future.
.. rubric:: Why core isn't part of ports either
:name: core-not-part-of-ports
Why is the core repository not in the ports? Well, we have a couple of
custom ports in the ports tree, but these are small. The core repository as
well as the ports tree itself are so big that it made sense to keep them
separate. Another reason is that the core repository only contains scripts in
Shell, Python and PHP. So the tools repository actually treats the core
repository as a package that depends on all the ports it needs. This
way, on the images, it looks like the core code is just another package.
**That makes upgrading the core code very easy and fast without modifying
base.** We can even upgrade to newer ports pages and add and remove them
as we go forward.
--------
Building
--------
.. rubric:: Not Clobbering the Build System
:name: building-not-clobbering-the-build-system
The tools repository is designed to run on a stock FreeBSD using `chroot
mechanics <http://en.wikipedia.org/wiki/Chroot>`__ to keep the build
contained and consistent. Theres nothing worse than a build system that
modifies the build system and at some point starts to dash out working
imagesonly to stop working some time in the future. No, no, no.
You can also “cross-build” between FreeBSD versions. Weve successfully
built images on FreeBSD 10.1 when OPNsense was still running on FreeBSD 10.0.
(version 16.1 now runs on FreeBSD 10.2) Thats not a huge gap and the ABI is the
same, but we expect this to work with FreeBSD 11 and beyond as well so that if
you have a FreeBSD box you will always be able to produce your own images if you
desirewithout spinning up extra machines, jails or virtual machines.
Here are the `build instructions for
OPNsense <https://github.com/opnsense/tools/blob/master/README.md>`__.
.. TIP::
As of November 2015 OPNsense is equipped with a tool that can completely
reinstall a running system in place for a thorough factory reset or to restore
consistency of all the OPNsense files. It can also wipe the configuration
directory, but won't do that by default.
The `opnsense-bootstrap <https://github.com/opnsense/update>`__ script is
particularly useful if you want to convert a hosted FreeBSD system to OPNsense.
-------------------------------
Virtual Machine for Development
-------------------------------
.. rubric:: Running: Use a Virtual Machine for Development
:name: running-use-a-virtual-machine-for-development
Its just easier and less tedious if the kernel crashes, to revert to a
previous state, or isolate and test different features. A VM can be set
up easily using the ISO images. Also very good for testing installation
and upgrades. Of course, at some point you will want to bring OPNsense
to your actual target device—just make sure you know the system well
enough before you attempt this.
`VirtualBox <https://www.virtualbox.org/>`__ is a solid tool for the
job, but be sure to check out `FreeBSDs Bhyve <http://bhyve.org/>`__ as
well (it was added in FreeBSD 10). However, If you are only interested
in GUI coding, you can skip all the build parts and directly download an
image and spin it up. Because…
--------
Packages
--------
.. rubric:: It Gets Even Better
:name: packages-it-gets-even-better
Once you have a running instance, how to produce and push code? Well,
theres a couple optional of packages that help you to be productive:
::
# pkg install vim-lite joe nano gnu-watch git tmux screen
The most important one is *git* for obtaining the code, the rest is
optional if you need it—mostly editors and terminal wrappers. It is also
possible to mount sshfs or do sftp to sync files from the repo if you
would like to use a graphical editor from your own system. As the root
user do the following:
::
# cd
# git clone https://github.com/opnsense/core
Once you have the repository, you switch it live using:
::
# cd core
# make mount
Yes, the changes that you make in the repository will show up directly
in the GUI now! Unfortunately, this will mount the repo over
*/usr/local* so if you modify packages the changes will light up in git.
Be careful. To prevent that from happening you can temporarily unmount
using:
::
# make umount
To finish that off the boot sequence will mount the core repository set
up in */root/core* as early as possible (if its available) and will use
its modifications for booting up (with the exception of
/usr/local/etc/rc itself). This makes it possible to work on the backend
configuration and boot sequence improvements without having out of sync
system files and repositories.
-------
Summary
-------
.. rubric:: Easy Access is Key to Collaboration
:name: summary-easy-access-is-key-to-collaboration
Although this is just a peek into OPNsense development workflow it brings to
attention a key aspect: moving barriers out of the way to enable as many people
as possible to produce quick results. Yes,there are barriers like
`git <http://git-scm.com/book/en/v2/Git-Basics-Getting-a-Git-Repository>`__
and `GitHub <https://guides.github.com/activities/contributing-to-open-source/>`__
to deal with, maybe even learning FreeBSD intricacies, but once you have
your code in the GUI and working fine, youll feel proud enough to
endure the hardships of making sure your patch will have a place in our
upstream repositories so the community as a whole can benefit from your
dedication.
The OPNsense core team looks forward to your feedback;
"We are seeking for more improvements in the build system and eagerly await
your pull requests." Take care and code responsibly. :)

Binary file not shown.

After

Width:  |  Height:  |  Size: 201 KiB

135
source/fork/thefork.rst Normal file
View File

@ -0,0 +1,135 @@
==============
About the Fork
==============
Welcome to about the fork. This page is intended to explain the original motivation
for forking, but keep in mind that currently less than 10% of the original legacy code
base remains. As it stand today, OPNsense has evolved from being a fork to a whole new
security platform with leading innovations such as weekly security updates for
all components, a REST API, inline Intrusion Prevention and intuitive modern user
interface.
-------------------
Debunking the Myths
-------------------
There are some myths surrounding our project offered mostly by pfSense enthusiasts,
if you have read their comments on us then we'd recommend to just ignore them and
install OPNsense, if you have not already done so.
.. sidebar:: Lets fork and lift the project!
.. image:: images/fork-lift_new.jpg
-------------------
So why did we fork?
-------------------
Back in 2014, after having sponsored pfSense® for years we felt there was no other
option than fork the project and keep the spirit of the - original m0n0wall based
fork - alive. Below you can read about our original motivations and the birth of
OPNsense®.
Technical
---------
We had technical reasons to fork.
As much as we love the functionality/feature set of pfSense, we do not enjoy the
:doc:`code quality </development/guidelines/basics>` and dispersed development method. We like structure, achievable
goals set forth in a `roadmap <https://opnsense.org/about/road-map/>`__ with
regular releases and a decent :doc:`framework </development/architecture>`.
Security
--------
On the security part the main issue was the need to separate logic. The GUI
should not perform tasks that require root access and potential security issues
should be fixed before they become a real problem.
Quality
-------
As for quality, all new features will be built using a solid :doc:`framework </development/architecture>` with a
Model View Controller. For this purpose we choose `Phalcon <https://phalconphp.com/nl/>`__ as it is the fastest
open source PHP framework available. And we will gradually migrate parts inherited
from pfSense to the new framework to avoid a big-bang approach.
Community
---------
A thriving community can only exist when people are willing to share. We want to
make it easier for people to join and help to build the community. With pfSense
this has been rather difficult as the tools to build it are difficult to use and
often do not work in the first few attempts. And since 2014 year they are not
freely available any more, you need to apply for access with ESF. We believe a
good open source project has nothing to hide so access to the sources should be
there for all. It will remain a mystery why ESF made that move as commit rights
and read rights are totally different.
.. Note::
ESF has since changed their policy several times with different license models,
including the ESF 6 clause license and the latest being a Apache style license.
Transparency
-------------
A real concern with pfSense is transparency. Since Netgate bought
the majority share of pfSense and renamed the company to ESF it has been
difficult to understand the direction they want the project to go. Removing the
tools from github without prior warning and using the brand name to fence off
competitors has scared quite a lot of people. Also the license had changed for
no apparent reason…
Restore a firm open source project
----------------------------------
With OPNsense we have restored a stable project with clear goals and a very simple
license that is suitable for forking and making OEM versions. We think a community
project is there for all to use and work with.
-------------
First Release
-------------
Much work had already been done before the `first official release <https://opnsense.org/opnsense-version-15-1-released/>`__:
* The build-tools had been completely rewritten from the ground up
with clear and easy to read build scripts that are portable and small,
* OPNsense is now a package that can be installed on top of our custom FreeBSD
build (you can literally do pkg remove opnsense and are left with an almost
standard FreeBSD base system),
* The firmware upgrade process is now done with pkgng,
* Captive portal has been rewritten and does not make use of kernel patches anymore,
* New features (captive portal) have been implemented with a clear structure,
* The check_reload_status functionality, effectively the backend daemon starting
and stopping components, has been fully rewritten in Python (configd),
* Fully reworked the GUI to a modern Bootstrap based one that is also easier to
customize if you want to.
--------------------------
Future Development & Focus
--------------------------
Moving forward the focus will remain on code quality and security.
.. Note::
A lot of work has been done to improve the code quality and with weekly
updates we have proven to be able to act quickly on known security threats.
For current status of the project and future development see our `roadmap <https://opnsense.org/about/road-map/>`__.
Deciso's involvement
--------------------
That being said it is important to know that `Deciso <https://www.deciso.com/about-deciso/>`__ has been a long time sponsor
of pfSense and invested a lot of time and money into the project. Deciso helped
to make it a success in Europe. Until Netgate bought the company there was room
for many others like us, but that has changed unfortunately.
Closing thoughts
----------------
In the end it all boils down to the direction we will go both technical as well
as community involvement and transparency.
You are invited! Try OPNsense, be part of the community and help the project move
forward. OPNsense is rapidly becoming the number one open source firewall platform!

Binary file not shown.

After

Width:  |  Height:  |  Size: 109 KiB

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 831 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 113 KiB

31
source/index.rst Normal file
View File

@ -0,0 +1,31 @@
.. OPNsense documentation master file
.. image:: ./images/opnsense_logo-zilver_grijs.png
-----------------
====================================
Welcome to OPNsense's documentation!
====================================
`OPNsense® <https://opnsense.org>`__ is an open source,
easy-to-use and easy-to-build FreeBSD based firewall and routing platform.
**OPNsense** includes most of the features available in expensive commercial
firewalls, and more in many cases. It brings the rich feature set of commercial
offerings with the benefits of open and verifiable sources.
-----------------
Table of Contents
-----------------
.. toctree::
:maxdepth: 2
fork/thefork
intro
manual
develop
relations
legal
support
contribute

105
source/intro.rst Normal file
View File

@ -0,0 +1,105 @@
============
Introduction
============
Welcome to the OPNsense documentation & wiki project!
The documentation is work in progress and is updated frequently.
If you would like to contribute in anyway, please take a look at our guide
how to :doc:`contribute`.
.. image:: ./images/opnsense_logo-zilver_grijs.png
------------------------------------
Welcome to OPNsense's documentation!
------------------------------------
`OPNsense® <https://opnsense.org>`__ is an open source,
easy-to-use and easy-to-build FreeBSD based firewall and routing platform.
**OPNsense** includes most of the features available in expensive commercial
firewalls, and more in many cases. It brings the rich feature set of commercial
offerings with the benefits of open and verifiable sources.
-----------------
Mission Statement
-----------------
Give users, developers and businesses a friendly, stable and transparent
environment. Make OPNsense the most widely used open source security platform.
The projects name is derived from open and sense and stands for:
“Open (source) makes sense.”
.. image:: ./images/OPNsense-Deciso-Screenshot.jpg
-------------------
-----------
Feature set
-----------
The feature set of OPNsense includes high-end features such as forward caching
proxy, traffic shaping, intrusion detection and easy OpenVPN client setup.
The latest release is based upon FreeBSD 10.1 for long-term support and uses a
newly developed MVC-framework based on Phalcon. OPNsenses focus on security
brings unique features such as the option to use LibreSSL instead of OpenSSL
(selectable in the GUI) and a custom version based on HardenedBSD.
The robust and reliable update mechanism gives OPNsense the ability to provide
important security updates in a timely fashion.
----------------------
----------------------
OPNsense Core Features
----------------------
- Traffic Shaper
- Captive portal
- Voucher support
- Template manager
- Multi zone support
- Forward Caching Proxy
- Transparent mode supported
- Blacklist support
- Virtual Private Network
- Site to site
- Road warrior
- IPsec
- OpenVPN
- Legacy PPTP support
- High Availability & Hardware Failover
- Includes configuration synchronization & synchronized state tables
- Can be combined with Traffic Shaping
- Intrusion Detection and Inline Prevention
- Build-in support for Emerging Treats rules
- Simple setup by use of rule categories
- Scheduler for period automatic updates
- Build-in reporting and monitoring tools
- System Health, the modern take on RRD Graphs
- Packet Capture
- Support for plugins
- DNS Server & DNS Forwarder
- DHCP Server and Relay
- Dynamic DNS
- Backup & Restore
- Encrypted cloud backup to Google Drive
- Configuration history with colored diff support
- Local drive backup & restore
- Stateful inspection firewall
- Granular control over state table
- 802.1Q VLAN support
- and more..

143
source/legal.rst Normal file
View File

@ -0,0 +1,143 @@
=============
Legal notices
=============
.. image:: ./images/opnsense_logo-zilver_grijs.png
:width: 300px
The OPNsense project wants to be a project that is friendly for users,
developers and partners. In this world with trademarks and copyright it
is best to “keep things as simple as possible, but not simpler”. Below
we pointed out the Licensing and Trademark rules we use.
----------------------------
OPNsense License & Copyright
----------------------------
.. sidebar:: OSI Approved License
.. image:: ./relations/images/osi_standard_logo.png
OPNsense is licensed under an `Open Source Initiative approved license <http://opensource.org/licenses>`__.
We like the BSD license, a simple two clause license that gives freedom to the
audience we want to serve.  It basically gives you the right to do whatever you
want to do with the code, even fork it and take it from there.
OPNsense is available under the BSD 2-Clause “Simplified” or “FreeBSD”
license:
`OPNsense® <http://opnsense.org>`__ is Copyright © 2014 2016 by
Deciso B.V.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
OPNsense is based on `FreeBSD <https://www.freebsd.org>`__
Copyright © The FreeBSD Project. All rights reserved.
OPNsense is a fork of `pfSense® <https://www.pfsense.org>`__
(Copyright © 2004-2014 Electric Sheep Fencing, LLC. All rights
reserved.) a fork from `m0n0wall <http://m0n0.ch/wall/>`__ (Copyright
© 2002-2013 Manuel Kasper).
------------------
Packages and ports
------------------
OPNsense includes various freely available software packages and ports.
The current ports are listed `here <https://github.com/opnsense/tools/blob/master/config/latest/ports.conf>`__.
The authors of OPNsense would like to thank all contributors for their efforts.
.. _documentation-copyright:
-----------------------
Documentation Copyright
-----------------------
The documentation is provided under a 2-clause BSD license:
(c) Deciso B.V. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS DOCUMENTATION IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE OPNSENSE DOCUMENTATION PROJECT BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS DOCUMENTATION, EVEN IF
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
------------------
Pictures Copyright
------------------
Some pictures are licensed under the Creative Commons Zero (CC0) license:
https://creativecommons.org/publicdomain/zero/1.0/
-----------------
Logo's Copyright
-----------------
Logo's may be subject to additional copyrights, property
rights, trademarks etc. and may require the consent of a third party or the
license of these rights. Deciso B.V. does not represent or make any warranties
that it owns or licenses any of the mentioned, nor does it grant them.
----------------
Trademark policy
----------------
OPNsense is a trademark. If you wish to use the name or logo in any way,
you must comply with this policy.
#. The name and logo may be used to promote OPNsense based products or
services.
#. The name and logo may be used to promote or serve OPNsense or related
projects and their communities.
#. When using the logo on online media like websites, social media and
apps the logo should link to https://opnsense.org
#. You must request our permission to use derivatives of the name and/or
logo at **project** @ **opnsense.org** prior to any use of the
derivative name and/or logo, and we may grant or withhold permission
to use the derivative name and/or logo in our sole discretion.
#. You may not state or otherwise lead people to believe, that you
represent the OPNsense project in any way other than as an individual
or corporate contributor to the project.
The official OPNsense logo is available for download:
:download:`OPNsense logo<images/OPNsense_Logo.ai>`.
If you have any questions about this policy, its interpretation, or want
to ask for permission please email **project** @ **opnsense.org**.

35
source/manual.rst Normal file
View File

@ -0,0 +1,35 @@
====================================
User Manual
====================================
.. image:: images/manual_guy.png
:width: 600px
:align: center
----------------
.. toctree::
:maxdepth: 2
:titlesonly:
manual/hardware
manual/install
manual/virtuals
manual/gui
manual/users
manual/ipv6
manual/two_factor
manual/systemhealth
manual/netflow
manual/aliases
manual/vpnet
manual/ips
manual/proxy
manual/antivirus
manual/shaping
manual/multiwan
manual/mobile_wan
manual/hacarp
manual/captiveportal
manual/dynamic_routing
manual/howtos

155
source/manual/aliases.rst Normal file
View File

@ -0,0 +1,155 @@
=============
Using Aliases
=============
Aliases are named lists of networks, hosts or ports that can be used as one entity
by selecting the alias name in the various supported sections of the firewall.
These aliases are particularly useful to condense firewall rules and minimize
changes.
-----------
Alias Types
-----------
OPNsense offers the following alias types:
+------------+------------------------------------------------------+
| Type | Description |
+============+======================================================+
| Hosts | Single hosts by IP or Fully Qualified Domain Name |
+------------+------------------------------------------------------+
| Networks | Entire network p.e. 192.168.1.1/24 |
+------------+------------------------------------------------------+
| Ports | Port numbers or a port range like 20:30 |
+------------+------------------------------------------------------+
| URL Tables | A table of ip addresses that can be fetched |
+------------+------------------------------------------------------+
-----
Hosts
-----
Hosts can be entered as a single IP address or a fully qualified domain name.
When using a fully qualified domain name, the name will we resolved periodically
(default is each 300 seconds).
Sample
Lets say we want to create an alias table for **www.youtube.com**
.. image:: images/aliases_host.png
:scale: 100%
**Apply changes** and look at the content of our newly created pf table.
Go to **Firewall->Diagnostics->pfTables** and select our newly created youtube table.
.. image:: images/pftable_youtube.png
:scale: 100%
As you can see there are multiple ip addresses for this domain.
--------
Networks
--------
Networks are specified in Classless Inter-Domain Routing format (CIDR). Use the
the correct CIDR mask for each entry. For instance a /32 specifies a single IPv4 host,
or /128 specifies a single IPv6 host, whereas /24 specifies 255.255.255.0 and
/64 specifies a normal IPv6 network.
-----
Ports
-----
Ports can be specified as a single number or a range using a colon **:**.
For instance to add a range of 20 to 25 one would enter 20:25 in the **Port(s)**
section.
----------
URL Tables
----------
URL tables can be used to fetch a list of ip addresses from a remote server.
There are several IP lists available for free, most notably are the "Don't Route
Or Peer" lists from Spamhaus.
--------------
Import Feature
--------------
To quickly add a list of aliases OPNsense also offers an import feature, where
you can paste or enter a list in text format.
Common examples are lists of IPs, networks, blacklists, etc.
The list may contain IP addresses, with or without CIDR prefix, IP ranges,
blank lines (ignored) and an optional description after each IP. e.g.:
.. code::
172.16.1.2
172.16.0.0/24
10.11.12.100-10.11.12.200
192.168.1.254 Home router
10.20.0.0/16 Office network
10.40.1.10-10.40.1.19 Managed switches
Spamhaus
--------
The Spamhaus Don't Route Or Peer Lists
DROP (Don't Route Or Peer) and EDROP are advisory "drop all traffic" lists,
consisting of netblocks that are "hijacked" or leased by professional spam or
cyber-crime operations (used for dissemination of malware, trojan downloaders,
botnet controllers). The DROP and EDROP lists are a tiny subset of the SBL,
designed for use by firewalls and routing equipment to filter out the malicious
traffic from these netblocks.
*Source :* https://www.spamhaus.org/drop/
Downloads
* `DROP list <https://www.spamhaus.org/drop/drop.txt>`__
* `EDROP list <https://www.spamhaus.org/drop/edrop.txt>`__
----------------------------------
Using Aliases in pf Firewall Rules
----------------------------------
Aliases can be used in the firewall rules to make administration of large lists
easy. For instance we could have a list of remote ip's that should have access to
certain services, when anything changes we only need to update the list.
Lets create a simple alias list and assume we have 3 remote ip's that may access
the ipsec server for a site to site tunnel connection:
* 192.168.100.1
* 192.168.200.2
* 192.168.300.3
.. image:: images/alias_remote_ipsec.png
:scale: 100%
We call our list remote_ipsec and update our firewall rules accordingly.
.. image:: images/alias_firewall_rules.png
:scale: 100%
Notice the list icon to identify a rule with an alias (list).
--------
Advanced
--------
For hosts it is possible to use lists in lists. Per example you could have:
* critical_servers {10.0.1.1 , 10.0.1.2}
* other_servers {10.0.1.100 , 10.0.1.200}
Then concatenate both by defining a new list:
* servers { critical_servers , other_servers}.
The end result will be a list with all ip addresses in one alias list (servers).
-------
GeoIP's
-------
While it is possible to use geoIP lists in aliases by importing or using the url
feature, OPNsense has a much more advanced way of blocking or allowing traffic based
on the geographical location (country) by utilizing the netmap enabled
:doc:`ips` see also :doc:`how-tos/ips-geoip`
------------------------------
Configure DROP and EDROP lists
------------------------------
To setup the DROP and EDROP lists in combination with the firewall rules, read:
:doc:`how-tos/edrop`

View File

@ -0,0 +1,18 @@
===================
Anti Virus Engine
===================
.. image:: images/eye_on_virus_new.jpg
:scale: 100%
**OPNsense** offers the industry standard ICAP to protect http and https
connections against ransomware, trojans, viruses and other malware .
OPNsense offers a ClamAV plugin, which can be used with the C-ICAP plugin or relies on third
party engines from well known vendors, such as Symantec's Protection Engine.
Setup ICAP Anti Virus Engine
----------------------------
- :doc:`how-tos/proxyicapantivirus`
- :doc:`how-tos/proxyicapantivirusinternal`

View File

@ -0,0 +1,111 @@
=========================
Captive portal & GuestNET
=========================
A **Captive Portal** allows you to force authentication, or redirection to a click
through page for network access. This is commonly used on hotspot networks,
but is also widely used in corporate networks for an additional layer of security
on wireless or Internet access.
.. image:: images/hotspot_login.png
:scale: 100%
--------------------
Typical Applications
--------------------
* Guest Network
* Hotel & Camping Wifi Access
* Bring Your Own Device (BOYD)
-------------------
Template Management
-------------------
OPNsenses unique template manager makes setting up your own login page an easy
task. At the same time it offers additional functionalities, such as:
* URL redirection
* Option for your own Pop-up
* Custom Splash page
.. image:: images/captiveportal_template_folder.png
:scale: 100%
---------------
Zone Management
---------------
Different zones can be setup on each interface or multiple interfaces can share
one zone setup. Each Zone can use a different Captive Portal Template or share it
with another zone.
--------------
Authentication
--------------
Secure authentication via HTTPS or splash-only portal with URL redirection to a
given page Different sources can be used to authenticate a user in a zone:
* LDAP [Microsoft Active Directory]
* Radius
* Local user manager
* Vouchers / Tickets
* No authentication (Splash Screen Only)
* Multiple (a combination of above)
---------------
Voucher Manager
---------------
OPNsense's Captive Portal has an easy voucher creation system that exports the
vouchers to a csv file for use with you favorite application. The export allows
you to print vouchers by merging them with your word or open office template and
create a good looking handout with your logo and company style.
-----------------------
Timeouts & Welcome Back
-----------------------
Connection can be terminated after the user has been idle for a certain amount
of time (idle timeout) and/or force a disconnect when a number of minutes
have passed even if the user is still active (hard timeout). In case a user
reconnect within the idle timeout and/or hard timeout no login is required and
the user can resume its active session.
--------------------
Bandwidth Management
--------------------
The Build-in traffic shaper can be utilized to:
* Share bandwidth evenly
* Give priority to protocols port numbers and/or ip addresses
See also: :doc:`/manual/shaping`
-------------
Portal bypass
-------------
MAC and IP addresses can be white listed to bypass
the portal.
-------------------
Real Time Reporting
-------------------
Basic Real Time Reporting is Integrated
* Live top IP bandwidth usage (Traffic Graph)
* Active Sessions
* Time left on Vouchers
----------------------------
Category based Web Filtering
----------------------------
By combining the Captive Portal with the caching proxy it is possible to utilize
category web filtering and block certain content for the users and by enabling the
cache reduce bandwidth and improve response times. See also: :doc:`/manual/proxy`
--------------------
Platform Integration
--------------------
Through the integrated REST API the captive portal application can be integrated
with other services. See: :doc:`/development/how-tos/api`
--------------------
Configure the Portal
--------------------
To setup a hotspot controller for business or hotel usage see:
:doc:`how-tos/guestnet`

View File

@ -0,0 +1,59 @@
===============
Dynamic Routing
===============
.. Warning::
Disabling a running routing daemon can be dangerous as it can lead to an inaccessible machine.
If you want to disable a running routing daemon, make sure, you don't lose routes which are
required by your connection to this machine (for example when using SSH)
Dynamic Routing (using routing protocos) is supported via an external plugin. Routing protocols are used to make your network equipment find the best path where your packets should be sent to.
Routing protocols are used to
* improve fault tolerance (if a connection breaks, a new route will be found if possible)
* simplify administration (You have to add less routes manually)
You should not use routing protocols if
* your network is small (so it would be better to use static routes)
* you are working in a highly isolated environment, where you have to be in control of everything happening in your network
Routing Protocols supported by the plugin include:
* OSPFv2 and v3
* RIPv1 and RIPv2
* BGPv4
.. Warning::
Not all routing protocols will work in any setup because they may have to be direct neighbors.
Consider the limitations of a routing protocol before using it.
------------
Installation
------------
First of all, select Plugins in the menu:
.. image:: images/menu_plugins.png
On this page, you can install the quagga plugin by clicking the `+` icon:
.. image:: images/plugins_quagga.png
-------------
Configuration
-------------
* :doc:`how-tos/dynamicrouting_zebra`
* :doc:`how-tos/dynamicrouting_ospf`
* :doc:`how-tos/dynamicrouting_rip`
------
How To
------
* :doc:`how-tos/dynamicrouting_howto`

130
source/manual/gui.rst Normal file
View File

@ -0,0 +1,130 @@
===========================
The OPNsense User Interface
===========================
This article explains the basics of the OPNsense Graphical User Interface or GUI
for short.
----------
User Login
----------
Before we can take a look at the GUI options we need to login.
The default user is root and the password is opnsense.
.. image:: images/login.png
----------------------------
GUI Layout & Main Components
----------------------------
The GUI consists out of the following main components:
.. image:: images/gui_layout.png
:scale: 100%
Logo & Link to Lobby
---------------------
Click on the OPNsense logo wherever you are in the interface and you will be
directed to the lobby and dashboard.
In the Lobby you can:
* Look at the dashboard with widgets
* View the 2 clause BSD license
* Change your password
* Logout
Menu Area
---------
The Menu area holds all the primary and sub menu's.
Here you can select what part of the system you want to watch or change.
You can see the layering on the menu. There are three levels:
#. Category level
#. Function level
#. Configuration level *(may not exist if the function is simple)*
In the following sample you see a screenshot of the Category **System**, with:
* Function: **Settings**
* Selected Configuration item: **General**
.. image:: images/submenu.png
Quick Navigation
----------------
A faster way to navigate trough the gui is by using the quick navigation/search box
on the upper right corner of the screen. Either click on it or hit tab to select it.
The search field is a type-a-head field, meaning that it will guess what you are
looking for and fill up while typing. Hit enter or click on an option to select
and navigate directly to the right page.
.. image:: images/quick-navigation.png
User & Local domain
-------------------
In the right corner just to the left of the quick navigation you will see your
username and the full domain name the firewall is configured with
(to change firewall name, go to **System->Setting->General**).
Content Area
------------
The content area is used to display:
* Input forms
* Popup Forms
* Buttons
* General forms of data output graphical and text based
----------
Form View
----------
Lets take a look at how an advanced form may look like:
.. image:: images/proxy_form.png
Full Help
---------
Many Forms are equipped with build-in help. In the upper right corner of the form
you can select to view all help messages at once. The toggle will color green when
enabled and show the help messages beneath the input items.
.. image:: images/help_msg.png
Advanced Mode
-------------
Some forms have hidden advanced features, to view them toggle the **advanced mode** in
the left corner of the form. Doing so will reveal all advanced options.
.. image:: images/advanced.png
Single Item Help
----------------
Show a single line help by pressing the **(i)** left of a form item.
Like this:
.. image:: images/info.png
Standard Tabs
-------------
A standard tab can be clicked upon to open the corresponding form.
A sample can be seen here:
.. image:: images/tab.png
Dropdown Tabs
-------------
A dropdown tab can be clicked upon to open the first menu item or you can click on
the arrow next to it to show all options, like:
.. image:: images/dropdown_tab.png

43
source/manual/hacarp.rst Normal file
View File

@ -0,0 +1,43 @@
=====================================
High Availability & Hardware Failover
=====================================
OPNsense utilizes the Common Address Redundancy Protocol or CARP for hardware
failover. Two or more firewalls can be configured as a failover group. If one
interface fails on the primary or the primary goes offline entirely, the
secondary becomes active.
Utilizing this powerful feature of OPNsense creates a fully redundant firewall
with automatic and seamless fail-over. While switching to the backup network
connections will stay active with minimal interruption for the users.
.. image:: images/light_bulbs.png
:scale: 100%
------------------
Automatic failover
------------------
If the primary firewall becomes unavailable, the secondary firewall will take
over without user intervention and minimal interruption.
-------------------------
Synchronized state tables
-------------------------
The firewalls state table is replicated to all failover configured firewalls.
This means the existing connections will be maintained in case of a failure,
which is important to prevent network disruptions.
-----------------------------
Configuration synchronization
-----------------------------
OPNsense includes configuration synchronization capabilities. Configuration
changes made on the primary system are automatically synchronized to the
secondary firewall.
-----------------
Configure HA CARP
-----------------
For detailed setup guide see: :doc:`/manual/how-tos/carp`

191
source/manual/hardware.rst Normal file
View File

@ -0,0 +1,191 @@
=======================
Hardware sizing & setup
=======================
The **harware setup** requires a careful preparation and selection of
the standard PC hardware components for the intended installation of
OPNsense.
⚠ Computer hardware with the open source security software OPNsense®
pre-installed can be purchased directly from various (online) stores.
.. TIP::
The OPNsense development team encourage everyone looking for a turn-key solution
to buy from `Deciso <https://www.deciso.com>`__ or one of the other partners listed at our partner page.
**Listed partners make significant contributions back to the project**
--------------------------------
Supported hardware architectures
--------------------------------
OPNsense® is available for
`x86-32 <https://en.wikipedia.org/wiki/X86-32>`__ (i386) and
`x86-64 <https://en.wikipedia.org/wiki/X86-64>`__ (amd64) bit
microprocessor architectures. Full installs on `SD memory
cards <https://en.wikipedia.org/wiki/Secure_Digital>`__, `solid-state
disks (SSD) <https://en.wikipedia.org/wiki/Solid-state_drive>`__ or
`hard disk drives
(HDD) <https://en.wikipedia.org/wiki/Hard_disk_drive>`__ are intended
for OPNsense.
While the range of supported devices are from embedded systems to rack
mounted servers, we recommend to use a 64-bit versions of OPNsense, if
the hardware is capable of running 64-bit `operating
systems <https://en.wikipedia.org/wiki/operating_system>`__. It is
possible to install and run 32-bit (x86-32, i386) versions of OPNsense®
on 64-bit (x86-64, amd64) PC hardware, but we do not recommend it,
especially not for new deployments.
---------------------
Hardware requirements
---------------------
For substantially narrowed OPNsense® functionality there is the basic
specification. For full functionality there are minimum, reasonable and
recommended specifications.
.. rubric:: Minimum
:name: minimum
The minimum specification to run all OPNsense standard features that do
not need disk writes, means you can run all standard features, expect
for the ones that require disk writes, e.g. a caching proxy (cache) or intrusion detection
and prevention (alert database).
+------------------+--------------------------------------------------------------------------+
| Processor | 500MHz single core cpu |
+------------------+--------------------------------------------------------------------------+
| RAM | 512 MB |
+------------------+--------------------------------------------------------------------------+
| Install method | Serial console or video (vga) |
+------------------+--------------------------------------------------------------------------+
| Install target | SD or CF card with a minimum of 4GB, use nano images for installation. |
+------------------+--------------------------------------------------------------------------+
Table: *Minimum hardware requirements*
.. rubric:: Reasonable
:name: reasonable
The reasonable specification to run all OPNsense standard features,
means every feature is functional, but perhaps not with a lot of users
or high loads.
+------------------+--------------------------------------------------------------------------+
| Processor | 1 GHz dual core cpu |
+------------------+--------------------------------------------------------------------------+
| RAM | 1 GB |
+------------------+--------------------------------------------------------------------------+
| Install method | Serial console or video (vga) |
+------------------+--------------------------------------------------------------------------+
| Install target | 40 GB SSD, a minimum of 1GB memory is needed for the installer to run. |
+------------------+--------------------------------------------------------------------------+
Table: *Reasonable hardware requirements*
.. rubric:: Recommended
:name: recommended
The recommended specification to run all OPNsense standard features,
means every feature is functional and fits most use cases.
+------------------+---------------------------------+
| Processor | 1.5 GHz multi core cpu |
+------------------+---------------------------------+
| RAM | 4 GB |
+------------------+---------------------------------+
| Install method | Serial console or video (vga) |
+------------------+---------------------------------+
| Install target | 120 GB SSD |
+------------------+---------------------------------+
Table: *Recommended hardware requirements*
.. rubric:: Hardware guide
:name: hardware-guide
The hardware required for your local OPNsense, will be determined by the
intended minimum `throughput <https://en.wikipedia.org/wiki/>`__ and the
feature set.
---------------------
Impact of Feature set
---------------------
While most features do not effect hardware dimensioning, a few features
have massive impact on it. The candidates are:
`Squid <https://en.wikipedia.org/wiki/Squid_(software)>`__ 
a caching web proxy which can be used for web-content control,
respectively. These packages rely strongly on CPU load and
disk-cache writes.
`Captive portal <https://en.wikipedia.org/wiki/Captive_portal>`__
settings with hundreds of simultaneously served captive portal users
will require more CPU power in all the hardware specifications
displayed below.
`State transition tables <https://en.wikipedia.org/wiki/State_transition_table>`__
it is a known fact, that each state table entry requires about 1KB
(kilo bytes) of RAM. The average state table, filled with 1000
entries will occupy about ~10MB (mega bytes) of
`RAM <https://en.wikipedia.org/wiki/Random-access_memory>`__.
OPNsense usage settings with hundred of thousands of connections
will require memory accordingly.
|
----------
Throughput
----------
The main hardware-factors of the OPNsense setup involved are CPU, RAM,
mass storage (disc), the number and quality of network interfaces.
+-------------------+-----------------------+-------------+------------------------+
| Throughput (Mbps) | Hardware requirements | Feature set | Users / Networks |
+===================+=======================+=============+========================+
| 1-10 | Basic spec. | narrowed | few (1-10) |
+-------------------+-----------------------+-------------+------------------------+
| 11-150 | Minimum spec. | reduced | adjusted (10-30) |
+-------------------+-----------------------+-------------+------------------------+
| 151-350 | Reasonable spec. | all | substantial (30-50) |
+-------------------+-----------------------+-------------+------------------------+
| 350-750+ | Recommended spec. | all | substantial+ (50-150+) |
+-------------------+-----------------------+-------------+------------------------+
| Mbps (Mbit/s or Mb/s) - Megabit per second - 1,000,000 bits per second |
+----------------------------------------------------------------------------------+
Network interface cards
As the FreeBSD hardware-lists and -recommendations
say, Intel® network interface cards (NIC) for
`LAN <https://en.wikipedia.org/wiki/Local_area_network>`__
connections are reliable, fast and not error-prone. Intel chipset
NICs deliver higher throughput at a reduced `CPU
load <https://en.wikipedia.org/wiki/Load_(computing)>`__.
.. rubric:: Supported hardware
:name: supported-hardware
The FreeBSD 10.2-RELEASE is the base of OPNsense. All FreeBSD drivers
are included in the OPNsense kernel, and the hardware compatibility is
the same.
.. Tip::
If you are looking to buy new hardware then take a look at our `partner page <https://opnsense.org/partners>`__
as these partners contribute back to OPNsense and sell hardware that is know to work well.
For further help and support, see
- `FreeBSD 10.2-RELEASE Hardware Compatibility
List <https://www.freebsd.org/releases/10.2R/hardware.html>`__
- `OPNsense Forum <https://forum.opnsense.org/>`__
.. rubric:: List of references
:name: list-of-references
- Schellevis, Jos; *Hardware requirements*; `OPNsense > Get
started <https://opnsense.org/users/get-started/>`__ (2015)
- McKusick, Marshall; Neville-Neil, George V; Warson, Robert NM; *The
Design and Implementation of the FreeBSD Operating System* (2015);
Addison-Wesley, New Jersey; ISBN 978-0321968975

View File

@ -0,0 +1,100 @@
===============================
Setup FreeRADIUS for accounting
===============================
---------------------
Goal of this tutorial
---------------------
This tutorial can be used to test your Captive portal setup with radius
accounting, it's not intended to use for production setups (because we
only use simple flat files for everything). We used Ubuntu linux for
this setup, a different operating system might result in some paths
being different.
User limits on the OPNsense firewall are set right after login, the
Radius server should tell the firewall how much resources are left for
the user that logged in successfully. A normal login sequence look like
this:
[login] -> [send accounting start] -> [send interim updates while
connected] -> [on logout, send accounting stop]
-----
Setup
-----
To setup freeradius in ubuntu, execute the following command:
::
apt-get install freeradius
Arrange client access
---------------------
Edit the file /etc/freeradius/clients.conf and append a block for your
network, as sample we will use 10.211.55.0/24.
.. code-block:: php
client 10.211.55.0/24 {
secret = testing123
shortname = test-network
}
Enable daily session limits
---------------------------
Enable daily session limits, which needs accounting to signal the
clients use.
- In /etc/freeradius/sites-available/default uncomment daily in
authorize and accounting sections.
- in /etc/freeradius/radiusd.conf uncomment daily in the instantiate
section
- append to /etc/freeradius/dictionary
.. code-block:: c
ATTRIBUTE Daily-Session-Time 3000 integer
ATTRIBUTE Max-Daily-Session 3001 integer
- uncomment sradutmp in the accounting section, to be able to use the
radwho command.
--------------
Add test users
--------------
You can add your test users to /etc/freeradius/users, they should look
like this:
.. code-block:: c
"test" Cleartext-Password := "test", Max-Daily-Session := 1800
Framed-IP-Address = 10.211.55.100,
Reply-Message = "Hello, %{User-Name}"
Make sure the second and third lines are indented by a single tab
character.
This should result in a user with a maxim use per day of 1800 seconds.
-----------
Test radius
-----------
For the initial test, it might be practical to debug the traffic going
in and out from Freeradius. The next steps help you start Freeradius in
debug mode, without output to console:
.. code-block:: c
/etc/init.d/freeradius stop
freeradius -X

View File

@ -0,0 +1,75 @@
======
c-icap
======
------------
Installation
------------
First of all, you have to install the c-icap plugin (os-cicap) from the plugins view.
.. image:: ../images/menu_plugins.png
After a page reload you will get a new menu entry under services for C-ICAP.
Select it and you will get to the following screen:
.. image:: images/c-icap_settings.png
----------------
General Settings
----------------
:Enable c-icap service:
Enable the C-ICAP service to handle ICAP requests.
:Timeout:
The time after which the socket will be closed.
:Max keepalive timeout:
The time after which the socket will be closed if it stays inactive.
:Start servers:
The count of the server processes which will be spawned.
:Max servers:
Limit the count of processes
:Listen address:
The address in which the server should be bound.
This address is usually the loopback address (\:\:1 for IPv6 or
127.0.0.1 for IPv4). The default value is \:\:1.
:Server admin:
This field should be set to an email address which acts as a contact
for users, who are having issues with the server.
A good idea would be an address, which converts the mails to your internal
ticket system.
:Servername:
If you want to override the server name (displayed on error pages),
you can enter it here.
---------
Antivirus
---------
.. image:: images/c-icap_av.png
:Enable ClamAV:
Enables the virus
-scan plugin of c-icap-modules using ClamAV
:Scan for filetypes:
The type of files which should be analyzed.
You should scan as many file types as possible but keep in mind that
scanning requires resources which have to be available.
:Send percentage data:
Amount of Data of the original file which should be included in the preview.
More Data will have better scanning results and is better for security while
a lower value improves performance.
:Allow 204 response:
A 204 response has the advantage, that the data don't have
to be sent over the wire again. In case of a preview, no more data
will be sent to the ICAP server and the data will be forwarded to
the client. In case of all data has been received by the ICAP server,
the data does not need to be sent back. Please note, that the ICAP client
has to support 204 responses.
:Pass on error:
In case the scan fails, the file can be passed through.
This is less secure but keeps the business running in case of failure.
Keep in mind that this may put your network at risk.

View File

@ -0,0 +1,192 @@
===================
Setup Caching Proxy
===================
.. image:: images/proxy_basics.png
:scale: 100%
----------------
Enable / Disable
----------------
The proxy is delivered with sane default settings for easy setup.
To enable the proxy just go to **Services->Proxy Server->Administration** and
check **Enable proxy** en click on **Apply**. The default will enable the proxy
with User Authentication based on the local user database and runs on port 3128
of the lan interface.
-----------------------
Change Proxy Interfaces
-----------------------
If you want to change the interfaces (subnets) the proxy will bind to then click
on the tab **Forward Proxy**. Now add/remove the interfaces in the **Proxy interfaces**
field. When adding make sure it is applied and a tag is visible (use , Enter or
select from the list).
---------------------------
Change Proxy Listening Port
---------------------------
By default the proxy will listen at port 3128, you can change this by clicking
on the tab **Forward Proxy** and fill in the port in the **Proxy port** feild.
Don't forget to **Apply** your changes.
------------
Enable Cache
------------
To enable caching click on the arrow next to the **General Proxy Settings** to
see the dropdown menu and click on **Local Cache Settings**.
.. image:: images/proxy_cache.png
:scale: 100%
Check the **Enable local cache** and click **Apply**.
.. Important::
As the cache is not created by default you will need to stop and start the service
under **Services->Diagnostics**, this will ensure correct creation of the cache.
Advanced
--------
Under the advanced settings (see mode switch on left top of the form) you can
change the cache size, directory structure and max object size to keep in cache.
Again defaults are fine for normal browsing and creates a 100MB cache with max 4MB
object size.
----------------------------
Change Authentication Method
----------------------------
Click on the arrow next to the **Forward Proxy** tab to show the drop down menu.
Now select **Authentication Settings** and select the desired Authenticator(s) in
the field **Authentication method**. Click on **Clear All** if you do not want to
use any authentication.
Depending on the Authentication Servers you have setup under **System->Access->Servers**
You can select one or more of the following:
* No Authentication (leave field blank)
* Local User Database
* LDAP
* Radius
---------
FTP Proxy
---------
To enable the FTP Proxy Click on the arrow next to the **Forward Proxy** tab to
show the drop down menu. Now select **FTP Proxy Settings** and select one or more
interfaces in the **FTP proxy interfaces** field and **Apply**.
.. Note::
The FTP proxy will only function if the Proxy Server itself is enabled.
And the proxy only works for non encrypted ftp traffic.
-------------------
Access Control List
-------------------
You can setup ACL's by clicking on the arrow next to **Forward Proxy** and select
**Access Control List**. Here you can:
* Setup Allowed Subnets (By default the proxy interfaces will be allowed)
* Add Unrestricted IP addresses (Unrestricted means just that, no authentication and no blacklisting for those IP's)
* Add Banned hosts IP address (A ban will stop this client from being able to use the proxy)
* Whitelist (Click on the (i) to see examples, whitelist prevail above blacklists)
* Blacklist (If not allowed by a whitelist, this will block traffic based upon a regular expression)
.. Warning::
Don't forget to press Enter or a comma after filling in a tag field as otherwise
the value will not be applied. It should look similar to:
.. image:: images/proxy_tag.png
-------------------------------
Remote Black List / Ad Blocking
-------------------------------
Use simple flat files to block ads.
For this sample we will use the ad list found here:
http://pgl.yoyo.org/adservers/serverlist.php?hostformat=nohtml
This list is a simple flat list that looks like this:
.. code-block:: guess
101com.com
101order.com
123found.com
180hits.de
180searchassistant.com
1x1rank.com
207.net
247media.com
Go to **Services->Proxy Server->Administration** and click on the tab **Remote
Access Control Lists**
Now click on the **+** at the bottom right corner of the form to add a new list.
Fill in:
================= ======================= ===========================================
**Enabled** Checked *Enable/Disable*
**Filename** yoyoads *Choose a unique filename*
**URL** (copy/paste the URL) *The URL of the blacklist*
**categories** (Leave blank) *Used for Category based web filtering*
**Description** Yoyo Ads Blacklist *Your description*
================= ======================= ===========================================
Looks like (screenshots of version 16.1.4):
.. image:: images/proxy_blacklist.png
:scale: 100%
**Save changes**
Now click on **Download ACLSs & Apply** to enable the blacklist/ad blocker.
-----------------------------
Firewall Rule No Proxy Bypass
-----------------------------
To make sure no-one can bypass the proxy you need to add a firewall rule.
Go to **Firewall->Rules** and add the following to the top of the list rule on the
LAN interface (if LAN is where your clients and proxy are on).
============================ =====================
**Action** Block
**Interface** LAN
**Protocol** TCP/UDP
**Source** LAN net
**Destination Port Range** HTTP
**Category** Block Proxy Bypass
**Description** Block http bypass
============================ =====================
**Save**
And one more rule to block HTTPS access:
============================ =====================
**Action** Block
**Interface** LAN
**Protocol** TCP/UDP
**Source** LAN net
**Destination Port Range** HTTPS
**Category** Block Proxy Bypass
**Description** Block https bypass
============================ =====================
**Save** & **Apply changes**
.. image:: images/proxy_firewall.png
:scale: 100%
-------------------------
Configure Browser/Firefox
-------------------------
To configure you browser for use with the proxy, just go to your network settings
and configure a proxy like this in firefox:
.. image:: images/proxy_firefox.png
:scale: 100%
For a set-for-step guide on full category based web filtering see :doc:`proxywebfilter`.

View File

@ -0,0 +1,238 @@
==============
Configure CARP
==============
--------
Overview
--------
One of the more powerful features of OPNsense is to set-up a redundant
firewall with automatic fail-over option. This chapter describes step by
step how to create a set-up based on two networks. The 192.168.1.0/24
will be used for the internal network and 172.8.0.0/24 will be used to
route our traffic to the internet.
.. image:: ./images/900px-Carp_setup_example.png
:scale: 100%
When using CARP ( `FreeBSD handbook on CARP <https://www.freebsd.org/doc/handbook/carp.html>`__ ), all
fail-safe interfaces should have a dedicated ip address which will be
combined with one shared virtual ip address to communicate to both
networks. In the picture above the dashed lines are used to mark the
virtual addresses.
The configuration file (xml) for both firewalls can be downloaded from
the wiki.
-----------
Terminology
-----------
There is some terminology involved in setting up a CARP cluster, which
we will explain briefly first:
.. rubric:: CARP
:name: carp
Common Address Redundancy Protocol uses IP protocol 112, is derived from
OpenBSD and uses multicast packets to signal it's neighbours about it's
status. Always make sure that each interface can receive carp packets.
Every virtual interface must have a unique Virtual Host ID (vhid), which
is shared across the physical machines. To determine which physical
machine has a higher priority, the advertised skew is used. A lower skew
means a higher score. (our master firewall uses 0).
.. rubric:: pfSync
:name: pfsync
Together with CARP, we can use pfSync to replicate our firewalls state.
When failing over you need to make sure both machines know about all
connections to make the migration seamless. It's highly advisable to use
a dedicated interface for pfSync packets between the hosts, both for
security reasons (state injection) as for performance.
.. rubric:: XMLRPC sync
:name: xmlrpc-sync
OPNsense includes a mechanism to keep the configuration of the backup
server in sync with the master. This mechanism is called xmlrpc sync and
can be found under System -> High Availability.
-----------------------------------------
Setup interfaces & basic firewall rules
-----------------------------------------
Our example uses three interfaces, which all have a rather basic setup.
.. rubric:: Master
:name: master
Go to interfaces, make sure you have all three interfaces assigned and
setup the following addresses and subnets:
+-----------------------+
| LAN 192.168.1.10/24 |
+-----------------------+
| WAN 172.18.0.101/24 |
+-----------------------+
| PFSYNC 10.0.0.1 |
+-----------------------+
Next we need to make sure the appropriate protocols can be used on the
different interfaces, go to firewall -> rules and make sure both LAN and
WAN accept at least carp packets (see protocol selection). Because we're
connecting both firewalls using a direct cable connection, we will add a
single rule to accept all traffic on all protocols for that specific
interface. Another option is to only accept traffic to the GUI port and
pfSync protocol.
.. rubric:: Backup
:name: backup
The backup server needs it's own dedicated addresses, we will use these:
+----------+-------------------+
| LAN | 192.168.1.20/24 |
+----------+-------------------+
| WAN | 172.18.0.102/24 |
+----------+-------------------+
| PFSYNC | 10.0.0.2 |
+----------+-------------------+
Because we are going to synchronize firewall settings between both
hosts, we only need to make sure that the pfsync interface can accept
data from the master for the initial setup. Use the same rule as used
for the master on this interface.
-----------------
Setup Virtual IPs
-----------------
On the master node we are going to setup our Virtual IP addresses, which
will also be used for the backup node after synchronisation. Go to
Firewall -> Virtual IPs and add a new one with the following
characteristics:
+-------------------------+------------------------------------+
| Type | Carp |
+-------------------------+------------------------------------+
| Interface | WAN |
+-------------------------+------------------------------------+
| IP addresses | 172.18.0.100 / 24 |
+-------------------------+------------------------------------+
| Virtual password | opnsense (the example uses this) |
+-------------------------+------------------------------------+
| VHID Group | 1 |
+-------------------------+------------------------------------+
| Advertising Frequency | Base 1 / Skew 0 |
+-------------------------+------------------------------------+
| Description | VIP WAN |
+-------------------------+------------------------------------+
And another using the following:
+-------------------------+------------------------------------+
| Type | Carp |
+-------------------------+------------------------------------+
| Interface | LAN |
+-------------------------+------------------------------------+
| IP addresses | 192.168.1.1 / 24 |
+-------------------------+------------------------------------+
| Virtual password | opnsense (the example uses this) |
+-------------------------+------------------------------------+
| VHID Group | 3 |
+-------------------------+------------------------------------+
| Advertising Frequency | Base 1 / Skew 0 |
+-------------------------+------------------------------------+
| Description | VIP LAN |
+-------------------------+------------------------------------+
------------------
Setup outbound NAT
------------------
When traffic is going out of the firewall it should also use the virtual
IP address to make a seamless migration possible. The default for
OPNsense is to use the interfaces IP address, which is in our case the
wrong one.
Go to Firewall -> NAT and select outbound nat. Choose manual outbound
nat on this page and change the rules originating from the
192.168.1.0/24 network to use the CARP virtual interface (172.18.0.100).
----------------------------
(optional) Setup DHCP server
----------------------------
When using dhcp for the local area network, there are some things to
consider. All clients should use the virtual address in stead of the
physical address it's normally propagating. Next thing to consider is
there will be two servers active at the same time, which should know of
each others pools. If dns requests are also forwarded by OPNsense, make
sure the dhcp server sends the right ip address. These are settings used
in our example (on the master server):
+--------------------+----------------+
| DNS servers | 192.168.1.1 |
+--------------------+----------------+
| Gateway | 192.168.1.1 |
+--------------------+----------------+
| Failover peer IP | 192.168.1.20 |
+--------------------+----------------+
---------------------------------
Setup HA sync (xmlrpc) and pfSync
---------------------------------
First we should enable pfSync using our dedicated interface using the
master firewall. Go to System -> High Availability, enable pfsync and
select the interface used for pfSync. Next setup the peer ip to the
other hosts address (10.0.0.2).
Now we need to configure the settings we want to duplicating to the
backup server using the xmlrpc sync option. For our setup we will enable
the following:
+---------------------------+
| Synchronize rules |
+---------------------------+
| Synchronize NAT |
+---------------------------+
| Synchronize DHCPD |
+---------------------------+
| Synchronize Virtual IPs |
+---------------------------+
--------------
Finalize setup
--------------
Just to make sure all settings are properly applied, reboot both
firewalls before testing.
-------------
Testing setup
-------------
First go to Status -> Carp in the OPNsense webinterface and check if
both machines are properly initialized.
To test our setup, we will connect a client to the local area network
and open a ssh connection to a host behind both firewalls. Now when
connected you should be able to look at the state table on both OPNsense
firewalls (Diagnostics -> States) and they should both display the same
connection. Next try to pull the network plug from the master firewall
and it should move over to the backup without loosing (or freezing) the
ssh connection.
---------
Resources
---------
#. Configuration for master server ( :download:`Carp_example_master.xml <resources/Carp_example_master.xml>` )
#. Configuration for backup server ( :download:`Carp_example_backup.xml <resources/Carp_example_backup.xml>` )

View File

@ -0,0 +1,87 @@
===========================
Configuring Cellular Modems
===========================
OPNsense supports a wide range of USB and miniPCIe cellular modems that can be used
as primary internet (WAN) connection or as failover for a fixed/ethernet connection.
With this guide we show you how to easily add a new modem and configure it to be
used as primary WAN connection.
----------------------------
Devices used for this How-to
----------------------------
For this how-to we used a `Deciso Netboard A10 desktop appliance <https://www.deciso.com/product-catalog/opn20076b/>`__
and a Huawei ME909u-521 miniPCIe cellular modem provided by `OSNet <https://www.osnet.eu/>`__.
.. Note::
Support for the ME909u-521 will be added in OPNsense 16.1.18.
----------------------------------------
Step 1 - Configure Point to Point device
----------------------------------------
Go to **Interfaces->Point-to-Point->Devices** and click on **Add** in the upper
right corner of the form.
Fill in the form like this (Example is for Dutch Mobile 4G KPN Subscription):
============================ =======================================================
**Link Type** PPP
**Link interface(s)** /dev/cuaU0.0 ( HUAWEI Mobile Connect - Modem)
**Description** 4G Cellular Network
**Service Provider** Select Country, Provider & Plan for auto configuration
**Username** Leave Empty (for NL KPN)
**Password** Leave Empty (for NL KPN)
**Phone Number** \*99# (for NL KPN)
**Access Point Name (APN)** fastinternet (for NL KPN 4G)
============================ =======================================================
If you need to enter a PIN number then click on **Advanced Options**
Click **Save** to apply the settings.
.. image:: images/4g_configure_ppp.png
:scale: 100%
.. image:: images/ppp_celular_configured.png
:scale: 100%
---------------------------------
Step 2 - Assign the WAN interface
---------------------------------
To assign the interface go to **Interfaces->Assignments** in our case we will make
this our primary internet connection and change the WAN assignment accordingly.
To do so just change the **Network port** for **WAN** to **ppp0 (/dev/cuaU0.0) - 4G Cellular Network**.
No click **Save** below the form.
If everything went fine then your are all setup and the default gateway will be
the one of you cellular connection.
.. image:: images/Interface_assignment_4g.png
:scale: 100%
-------------------------
Step 3 - Trouble shooting
-------------------------
Ok, so it doesn't work as expected.
In that case, first look at the log of the cellular device's PPP connection, to do
so go to: **Interfaces->Point-to-Point->Log File**. Often you can see what went
wrong directly in the log.
If you can't figure out what is wrong then a reboot to reinitialize the device can
sometimes help.
.. Note::
Before booting your device it is best to make sure the SIM card is inserted correctly.
When the device seems to work properly then checkout if the interface was assigned
an IP address, go to **Interfaces->Overview** and click on the WAN interface to
see the details.
You should see an IP address, Gateway IP and ISP DNS server(s).
If all is filled in then either your firewall is blocking the traffic or the
network connection is not working well.

View File

@ -0,0 +1,127 @@
======
ClamAV
======
.. Warning::
Your machine needs at least 1.5 GB RAM. Otherwise the machine will run out of
memory and crash because of out of memory kills. Using a machine with at least
2 GB RAM is recommended.
.. Warning::
There are some techniques to avoid detection and scanning using AV software and not
every malware is known by AV products.
Signature based AV software can decrease the risk of getting hit by a known malware
but it does never guarantee that your computers don't get infected.
It is **important** to teach the users how to handle files from the internet
and untrusted devices safely. Also plan a regular Backup of important files, make sure,
that ACLs are used correctly and apply patches asap to keep the attack surface and
damage as small as possible.
.. Note::
To make ClamAV working, you need to download signatures.
Please note that those files need to be fetched after a reboot again if they
are stored on a ram disk.
------------
Installation
------------
First of all, you have to install the ClamAV plugin (os-clamav) from the plugins view.
.. image:: ../images/menu_plugins.png
After a page reload you will get a new menu entry under services for ClamAV.
Select it and you will get to the following screen:
.. image:: images/clamav_settings.png
---------------------
Configuration Options
---------------------
:Enable clamd service:
Selecting this checkbox enables clamd so you can use it to scan files.
:Enable freshclam service:
Freshclam is a service to update your malware signatures.
If you use ClamAV, it is recommended to update the signatures on a regular basis.
:Enable TCP Port:
This checkbox needs to be checked, if you want to use clamd over the network or
for local services, which use a TCP connection.
:Maximum number of threads running:
Thread limit is used to avoid a denial of service of the daemon and your machine.
Usually a number next or equal to the number of cores would be good.
:Maximum number of queued items:
This is the maximum of files which can be in the queued for scanning.
The reason is the same as for the threads.
:Idle Timeout:
The connection will be dropped if it is inactive for this amount of time.
If the other socket endpoint is a machine, this value can be low but if you
plan to use it for develpoment reasons, you may set it to a higher value.
:Max directory recursion:
Limit the depth of the directory tree.
In the worst case there is a loop which causes the scanner to run endlessly and
this setting should prevent it.
:Follow directory symlinks:
If this is checked, clamav will follow directory symlinks which may lead to a loop.
If you want to check this, make sure the recursion limit is set to a useful value.
:Follow regular file symlinks:
If this is checked, clamav will follow symlinks to regular files.
This may expose information about the filesystem, the user should not have access to.
:Disable cache:
If you check this, the results are not cached. This is only useful in develpoment
environments as it slows down the response time.
:Scan portable executable:
Check this box, if you want to scan PE files.
If you are using PE-files (\*.exe, \*.dll etc.) files in your network,
checking this box is recommended.
:Scan executeable and linking format:
Check this box, if you want to scan ELF-files.
ELF is for example used on Linux based operating systems and on \*BSD.
:Detect broken executables:
This setting will mark an executable as broken if it does not match the spec.
A executable may be broken because of a download issue or manipulation.
In any case, there should not be any legit case to pass a broken executable.
:Scan OLE2:
If this is checked, OLE2 files (for example Microsoft Office files) will be analyzed.
Such files should be analyzed as they may contain macros which have been used to download
and install malware (usually ransomware).
:OLE2 block macros:
Check this box, if documents containing macros should be blocked. If you don't use macros and
you don't expect them from your business partners or friends, this setting is recommended.
:Scan PDF files:
If this checkbox is checked, PDF files will be scanned.
PDF files can carry other files or multimedia as well as javascript and fonts.
Scanning PDF files is recommended.
:Scan SWF:
If you check this box, Flash files will be scanned.
Flash is used to provide video players or interactive content.
Nowadays it should have been replaced by HTML5.
:Scan XMLDOCS:
Scan XML Documents
:Scan HWP3:
HWP seems to be a korean document format. If you don't use them,
it is better to block them in the proxy than scanning them.
If you have them in use, you should scan them.
:Decode mail files:
If you select this option, the sections of emails will be read and therefore
it will be possible to scan email attachments.
Mail attachments are important to scan as an attached file may contain malware.
For example, some malware campaigns used a JScript file which has been packed
in a ZIP file which was attached to an email.
:Scan HTML:
Scans HTML files which may have dangerous embedded JavaScript.
:Scan archives:
Scan files inside archives.
This is very important as archives can contain malware.
Please note that archive nesting is used to bypass scans,
so scanners detect such archives as dangerous at a specific recursion level.
Also keep in mind that zip bombs may be possible to DoS a scanner.
:Block encrypted archive:
Encrypted archives are usually used to transfer files encrypted which don't support encryption
on their own or the sender is not aware how to encrypt those files.
A tool like 7z can derive a key from a password given by the creator of the file,
which will be used to encrypt the compressed data.
The ClamAV cannot scan this data as it is missing the key/password. Some malware authors used
encrypted archives to avoid scanning and told the victim in the email text how to unpack it.

View File

@ -0,0 +1,118 @@
==========================
Configuration Cloud Backup
==========================
------------
Google Drive
------------
**Google Drive** is a digital file storage and management service by the
information technology company Google. Amongst other features, like
collaborative editing of documents, spreadsheets, and presentations, it
allows signed up users with an account to store and share files in the
digital cloud.
The OPNsense configuration can be stored as a backup file in XML format,
to your PC on an USB stick or remotely in the digital Google Drive
cloud.
-------------------
Free online storage
-------------------
Because Google officially offers a free storage of 15 GB and nearly
unlimited traffic, a remote backup of an OPNsense configuration file is
free of charge, the only thing you need is an account at google
(`Google Drive Signup <https://accounts.google.com/signup?hl=en>`__) .
--------
Easy API
--------
An application programming interfaces (API) for Google Drive was
released in 2013. This API empowers third-party developers to easily
write apps for Google Drive.
-------------
Remote backup
-------------
In OPNsense\ :sup:`1` you can **backup** your configuration directly and
automatically to **Google Drive**, using the new backup feature. Every
backup will be encrypted with the same algorithm used in the manual
backup so it's quite easy to restore to a new installed machine.
After set-up, the backup feature will do first store of the OPNsense
config file and subsequently a daily new backup of changed config
content.
----------------------
Setup Google API usage
----------------------
First we need to have a project in the google developer console:
- Go to https://console.developers.google.com/project
- Create a project and give it a name, you may leave it default it
doesn't really matter for this.
- Enable the Drive API
- In the left menu APIs -> "Drive API" -> Enable
- Open the project and start to create an api key
- In the left menu : APIs & auth -> Credentials
- Click on the button "Create new Client ID"
- Choose "Service account", followed by "Create Client ID"
- Download the key and save it (for your own use)
- Click "Generate new P12 key" and download the key (for your own
use, you need this one later)
- Copy Email Address, you need it later.
.. rubric:: Create a Google Drive folder
:name: create-a-google-drive-folder
Next thing is to create a folder in Google Drive and share it to the
"service user" you've just created.
- Go to https://drive.google.com
- Choose "NEW" and the folder to create a new folder, the name doesn't
really matter (for example type OPNsense).
- right click the newly created folder and choose share
- paste the email address from the service account and "send"
- Now open the folder and copy the folder ID ( in the url, the last
piece after #/folders/, it's quite long)
.. rubric:: Setup the account in OPNsense
:name: setup-the-account-in-opnsense
Now we can put it all together, login to your OPNsense firewall and go
to the backup feature (default : https://192.168.1.1/diag_backup.php )
.. image:: ./images/600px-Google_Drive_Backup_screenshot.png
:scale: 100%
On the bottom of the page are the options for the Google Drive backup,
enable the feature and fill in the parameters. Email address is acquired
in step 2, the key in step 1. Choose a strong password to protect your
data and fill in a number of backups you want to keep.
When you click Setup/Test Google Drive, the firewall will automatically
save and test your settings and you will receive either an error
(connectivity issues) or a list of config files currently in the backup.
The moment the feature is enabled, it will do a daily compare of the
last file in backup and the current configuration and creates a new
backup when something has changed.
.. rubric:: References
:name: references
- `Official website of Google Drive <https://www.google.com/drive/>`__
.. rubric:: Notes
:name: notes
:sup:`1` As of OPNsense version 1.15.8 .2 (25 March 2015)

View File

@ -0,0 +1,78 @@
=======================
Dynamic Routing: How To
=======================
.. Note::
To keep this tutorial short, a configuration is only added a single time.
For example, the configuration of Site A and Site B are identical beside one
octet in the IP addresses.
Also both routers have the same configuration except the Network address of the
uplink and the client network.
---------
Situation
---------
.. image:: images/dynamic_routes_howto.png
We have two sites (Site A and Site B) which are connected via a layer 2 VPN.
Each site has two additional routers,
which are connected to the edge router and with each oder.
On those routers, the clients are attached.
-------------
Configuration
-------------
In this setup, OSPF is used.
All routers belong to the area 0.0.0.0 and no prefix lists are used.
Core Router of Site A
---------------------
General Settings:
========================= ============
Setting Value
========================= ============
Enable Checked
Advertise Default Gateway Checked
Passive Interfaces Empty
Route Redistribution Empty
========================= ============
Networks:
============ ============
Network Network Mask
============ ============
192.168.0.0 30
192.168.1.0 30
192.168.1.4 30
============ ============
Left Floor Router of Site A
---------------------------
General Settings:
========================= ===========================
Setting Value
========================= ===========================
Enable Checked
Advertise Default Gateway Unchecked
Passive Interfaces Interface name of 10.1.1.0
Route Redistribution Empty
========================= ===========================
Networks:
============ ============
Network Network Mask
============ ============
10.1.1.0 24
192.168.1.4 30
192.168.1.8 30
============ ============

View File

@ -0,0 +1,128 @@
======================================
Dynamic Routing: Configuration: OSPFv2
======================================
-------
General
-------
.. Warning::
Saving the settings will apply them and reload the daemon. This means you may lose the connection to your firewall for some seconds.
.. image:: images/dynamic_routes_ospf_general.png
Enable
------
Enables the OSPF routing daemon.
If this does not work, please check the settings of General.
Check this checkbox if you want to use OSPFv2 in your network.
Passive Interfaces
------------------
Passive Interfaces are interfaces,
which exist in OSPFv2 but where no routing updates should be sent to.
These are usually the Interfaces,
where your clients are connected to and no router should exist.
You dont need to add interfaces here, where no network is specified.
Route Redistribution
--------------------
Route Redistribution is used,
if you want to send information this router has learned via another protocol
or routes from kernel (OPNsense static routes).
Advertise Default Gateway
-------------------------
Advertise Default Gateway should be checked,
if this machine has a default gateway to the internet.
Always Advertise means, that this route should be also broadcasted,
if it is not available. Be careful with this option in HA setups.
--------
Networks
--------
.. image:: images/dynamic_routes_ospf_networks.png
Networks gives you a brief overview of the configured networks. The dialog looks like this:
.. image:: images/dynamic_routes_ospf_network_dialog.png
Enabled
-------
Enabled means that this Network is going to be used.
You should only disable networks if you plan to do some changes in your topology or some routes get broken.
Network Address
---------------
The Network Address of a local interface on which OSPFv2 should be enabled.
Network Mask
------------
A CIDR Mask for the Network Address.
For example, if your LAN IP is 192.168.0.1/24, the network address is 192.168.0.0 and Network Mask is 24.
Area
----
The area describes which routers belong to the same group (autonomous system). This value is a 32 bit integer, which is entered in dotted decimal notation (like an IPv4 address is usually written).
Prefix-List in and Out
----------------------
Only used for advanced route filtering using access lists.
----------
Interfaces
----------
This tab shows an overview of the configured interfaces:
.. image:: images/dynamic_routes_ospf_interfaces.png
.. Note::
Changes in this view do *NOT* apply the settings.
If you add or edit an entry, you will get this dialog:
.. image:: images/dynamic_routes_ospf_interface_dialog.png
Interface
---------
Choose a single interface, where this interface settings apply to.
Authentication Type and Authentication Key
------------------------------------------
This values can be set,
but they are not used as there is no area configuration which would make use of them.
You may want to set the password here if you add a custom area setting via vtysh.
Cost
----
A numeric value to set the cost on an interface.
The cost is used to calculate the route to the target.
A bigger value here means, the route is less likely used.
Hello and Dead Interval
-----------------------
Hello interval is the interval in which hello packets (detection of other OSPF routers) are sent out.
A bigger value means sower detection but less load on the interface.
Dead Interval is the time window, in which the router has to receive a hello packet from another router.
If it does not, it is removed.
Priority
--------
This field specifies the router priority which means a router with a good priority is more probably the designated router.
Network type usually does not need to be set.

View File

@ -0,0 +1,45 @@
===================================
Dynamic Routing: Configuration: RIP
===================================
.. Note::
RIP should not be used in larger networks due to the limited hop count. Cosider using OSPF in such cases.
.. Warning::
Saving the settings will apply them and reload the daemon. This means you may lose the connection to your firewall for some seconds.
RIP is a well known distance vector protocol.
It may be preferred to be used in smaller networks,
where the topology is not too complex and the possibillity of loops is small.
.. image:: images/dynamic_routes_rip.png
Enable
------
enables the routing protocol if the support of routing protocols is enabled in general. If you check this box, RIP will be enabled.
Version
-------
Enter 1 or 2 here. 1 is “classful” which means, that this routing protocol does not support variable length routing.
If you choose version 2, variable length subnet masks are supported. In most cases, you want to choose version 2 here.
Passive Interfaces
------------------
Interfaces, which are known by the routing daemon, but no updates are sent.
You should add interfaces with networks here, which do not have any other routers.
Route Redistribution
--------------------
Also send routes from other sources to neighbors (if desired).
Networks
--------
Add the networks here which should be known by the router and which are subject to be sent to the neighbors.
Passive interfaces will not be used to look for another router.

View File

@ -0,0 +1,40 @@
=====================================
Dynamic Routing: Configuration: Zebra
=====================================
Zebra is the core of quagga and needs to be enabled in any case. It can be enabled in the general view:
.. Note::
If this service is disabled, all other routing protocols are disabled too.
.. Warning::
Saving the settings will apply them and reload the daemon. This means you may lose the connection to your firewall for some seconds.
.. image:: images/dynamic_routes_zebra.png
------
Enable
------
Checking „Enable“ means that zebra and all other enabled routing daemons will be started.
If you disable this checkbox, Quagga will be completely disabled.
----------------------------------
Create a logfile and Logfile level
----------------------------------
If you check this checkbox, messages with a higher or equal severity will be written
to a log file on this device. You can view this log file under diagnostics if you want
to debug errors in your network.
--------------------------------------------
Send log messages to syslog and Syslog level
--------------------------------------------
Settings are the same as for the log file but for syslog.
This is useful if you use an external logging server.

View File

@ -0,0 +1,137 @@
==========================
Configure Spamhaus (E)DROP
==========================
The Spamhaus Don't Route Or Peer Lists
DROP (Don't Route Or Peer) and EDROP are advisory "drop all traffic" lists,
consisting of netblocks that are "hijacked" or leased by professional spam or
cyber-crime operations (used for dissemination of malware, trojan downloaders,
botnet controllers). The DROP and EDROP lists are a tiny subset of the SBL,
designed for use by firewalls and routing equipment to filter out the malicious
traffic from these netblocks.
*Source :* https://www.spamhaus.org/drop/
For this how to we will use the Alias feature and a firewall block rule.
The lists for this example are located here:
* `DROP list <https://www.spamhaus.org/drop/drop.txt>`__
* `EDROP list <https://www.spamhaus.org/drop/edrop.txt>`__
-------------------------------------
Step 1 - Create an Alias for Spamhaus
-------------------------------------
Go to **Firewall->Aliases->All** and press the **Add a new alias** button in the
top right corner of the form.
Enter the following data:
+-----------------+-----------------------------------------+-----------------------------+
| **Name** | spamhaus_drop | *Name of our alias* |
+-----------------+-----------------------------------------+-----------------------------+
| **Description** | Spamhaus DROP | *Freely chosen description* |
+-----------------+-----------------------------------------+-----------------------------+
| **Type** | URL Table (IPs) | *URL type* |
+-----------------+-----------------------------------------+-----------------------------+
| **Host(s)** | https://www.spamhaus.org/drop/drop.txt | *Don't Route Or Peer List* |
+-----------------+-----------------------------------------+-----------------------------+
Set the update frequency to 1 for each day.
Press **Save** and then **Add a new alias**.
+-----------------+-----------------------------------------+-------------------------------------+
| **Name** | spamhaus_edrop | *Name of our alias* |
+-----------------+-----------------------------------------+-------------------------------------+
| **Description** | Spamhaus EDROP | *Freely chosen description* |
+-----------------+-----------------------------------------+-------------------------------------+
| **Type** | URL Table (IPs) | *URL type* |
+-----------------+-----------------------------------------+-------------------------------------+
| **Host(s)** | https://www.spamhaus.org/drop/edrop.txt | *Extended Don't Route Or Peer List* |
+-----------------+-----------------------------------------+-------------------------------------+
Set the update frequency to 1 for each day.
Press **Save** and then **Apply changes**.
.. image:: images/spamhaus_drop_edrop.png
:scale: 100%
---------------------------------------
Step 2 - Firewall Rules Inbound Traffic
---------------------------------------
We will block incoming connections and outgoing connections for the drop and edrop lists.
To do so we will start with inbound traffic on the WAN interface.
Go to **Firewall->Rules** Select the **WAN** tab and press the **+** icon in the
lower right corner.
Enter the following configuration and leave all other parameters on default values:
=================== ============== =============================================
**Action** Block *Choose block to drop the incoming traffic*
**Interface** WAN *Should be the default value*
**TCP/IP Version** IPv4 *For our example we use IPv4*
**Source** spamhaus_drop *Our alias for the DROP list*
**Category** Spamhaus *Freely chosen Category*
**Description** Block DROP *Freely chosen description*
=================== ============== =============================================
**Save** and repeat this action for the EDROP list:
=================== =============== =============================================
**Action** Block *Choose block to drop the incoming traffic*
**Interface** WAN *Should be the default value*
**TCP/IP Version** IPv4 *For our example we use IPv4*
**Source** spamhaus_edrop *Our alias for the DROP list*
**Category** Spamhaus *Freely chosen Category*
**Description** Block EDROP *Freely chosen description*
=================== =============== =============================================
.. image:: images/spamhaus_wan_rules.png
:scale: 100%
**Save**
----------------------------------------
Step 3 - Firewall Rules Outbound Traffic
----------------------------------------
Now do the same for outbound traffic traffic on the LAN interface.
Go to **Firewall->Rules** Select the **LAN** tab and press the **+** icon in the
lower right corner.
=================== ============== =============================================
**Action** Block *Choose block to drop the incoming traffic*
**Interface** LAN *Should be the default value*
**TCP/IP Version** IPv4 *For our example we use IPv4*
**Destination** spamhaus_drop *Our alias for the DROP list*
**Category** Spamhaus *Freely chosen Category*
**Description** Block DROP *Freely chosen description*
=================== ============== =============================================
**Save** and add the EDROP list:
=================== =============== =============================================
**Action** Block *Choose block to drop the incoming traffic*
**Interface** LAN *Should be the default value*
**TCP/IP Version** IPv4 *For our example we use IPv4*
**Destination** spamhaus_edrop *Our alias for the DROP list*
**Category** Spamhaus *Freely chosen Category*
**Description** Block EDROP *Freely chosen description*
=================== =============== =============================================
**Save** and **Apply changes**
.. image:: images/spamhaus_lan.png
:scale: 100%
**DONE**
---------------
Check pf Tables
---------------
To list the ip addresses that are currently in the DROP and EDROP lists go to
**Firewall->Diagnostics->pfTables** and select the list you want to see:
.. image:: images/spamhaus_pftable.png
:scale: 100%

View File

@ -0,0 +1,99 @@
==========
FreeRADIUS
==========
------------
Installation
------------
First of all, you have to install the FreeRADIUS plugin (os-freeradius) from the plugins view.
.. image:: ../images/menu_plugins.png
After a page reload you will get a new menu entry under services for FreeRADIUS.
Select and a submenu will pop up with the entries **General, User** and **Client**:
----------------
General Settings
----------------
.. image:: images/freeradius_general.png
:Enable:
To enable the service, you have to check this box.
:Enable VLAN assignment:
If you check this box, the RADIUS packets will have some unencrypted tags
for the network device to allow dynamic VLAN assignment.
In this case, the authentication is still encrypted but some metadata will be readable.
You need to enable this checkbox, if you want to set a VLAN on a switchport,
which depends on the authenticated user.
-----
Users
-----
.. image:: images/freeradius_users.png
A user is an entity, which is meant to authenticate against the RADIUS server
(computer or human).
To create a user, click the `+` button.
.. image:: images/freeradius_edit_user.png
:Enabled:
This user will be written to disk and can be used.
You can toggle this value to temporary disable users.
:Username:
The name which the user will use to authenticate.
:Password:
The password the user will use to authenticate.
:Description:
Internal information for you to use to find the user.
This setting can be used to add some infos like a department.
:IP Address and Subnetmask:
If you want to use FreeRADIUS for point to point links,
you can add an IP address here which will be assigned to the client.
The same is valid for Subnetmask.
:VLAN ID:
A layer 2 device like a switch, which supports 802.1X authentication
can use this Field to dynamically assign an VLAN number to a switchport
based on the authentication result. This is especially useful if you
are having moving users (for example if an employee can attach his
computer to a docking station at a desk and the switch will assign
the VLAN ID of the employee to the switchport.
Be aware that the Layer 2 device has to be able to read this information,
which means that **you have to enable corresponding option in General**
-------
Clients
-------
.. image:: images/freeradius_clients.png
A client in RADIUS is a intermediate device / network device like a VPN
gateway, a switch or an access point.
To create a new client, click the `+` button:
.. image:: images/freeradius_edit_client.png
:Enabled:
This client will be written to disk and can be used.
You can toggle this value to temporary disable clients.
:Name:
A name used for the client.
:Secret:
The secret is used to provide a trust relationship between the
client and the FreeRADIUS server. This password should be strong
as you only have to type it twice (once in the FreeRADIUS configuration
and once in your client configuration) or even copy it.
If the passwords do not match, FreeRADIUS will reject all attempts to
authenticate.
:IP Address or Network with CIDR:
This is the IP address of the Client (not the authenticating device).
For example this could be the IP address of your switch.

View File

@ -0,0 +1,62 @@
=============================
Organize PF Rules by Category
=============================
OPNsense firewall rules can be organized per category.
These categories can be freely chosen or selected.
.. Note::
This feature was added in version 16.1.1. Always keep your system up to date.
---------------------------
Adding a category to a rule
---------------------------
To add a category to a rule, open or create a new rule and scroll to **Category**.
Then just add you category, if this is the first rule with a category no selection
options will be visible.
.. image:: images/Rule_Category.png
:scale: 100%
---------------------------------
Firewall Rules Filter by category
---------------------------------
Only when there are rules with a defined category, the **Filter by category**
becomes visible at the bottom of the table.
If you click it is will look like this:
.. image:: images/Filter_by_Category.png
:scale: 100%
If you have a large number of categories, then just start typing and in search
box to make a quick selection.
----------------
Before Selection
----------------
Take a look at this simple rule set before selecting our "My IP's" category.
.. image:: images/Rules_Full.png
:scale: 100%
--------------------
And after selection
--------------------
Now when selecting our test category it will look like this:
.. image:: images/Filter_Category_Result.png
:scale: 100%
That is all there is to it to organize your rules without messing anything up.
------------
Multi Select
------------
In a later release of OPNsense 16.1 multi selection has been added.
This features makes it possible to select rules from more than one category.
Example:
.. image:: images/fw_category_multiselect.png
:scale: 100%

View File

@ -0,0 +1,604 @@
=====================
Setup a Guest Network
=====================
This how to will explain how to setup a guest network using the captive portal.
Guest Networks are widely used to allow guests controlled internet access at
hotels, RV Parks or businesses.
.. image:: images/opnsense_hotspot_controller.png
:scale: 100%
.. Note::
For the example we expect the GUESTNET interface to be connected with your
actual guest network switch or access point. This tutorial does not explain
how to setup a wireless network.
----------
Businesses
----------
Businesses usually want to share internet access with their guest and show them
a landing page with a welcome message and some usage guidelines (policy). At the
same time it is important to make sure guests won't be able to access the company's
local network and limit the maximum internet usage.
-------------------
Hotels and RV Parks
-------------------
Hotels and RV parks usually utilize a captive portal to allow guests (paid) access
to internet for a limited duration. Guests need to login using a voucher they can
either buy or obtain for free at the reception. OPNsense has build-in support for
vouchers and can easily create them on the fly. With this example we will show
you how to setup the Guest Network for this purpose and setup a reception account
for creating new vouchers.
--------
Advanced
--------
The Captive portal can also be combined with the category based web filtering of
the proxy. This tutorial will explain how to combine both features.
-------------
Prerequisites
-------------
We will start configuration with a fresh OPNsense install, updated to the latest
patch level (16.1.5_1 in our example). You will need a system with a minimum of
3 ports (LAN/WAN/GUESTNET) for this tutorial.
------------
Good to know
------------
As the Hotel/RV Parks setup is almost identical to the business setup we will start
with that and after finishing add/change the specifics to match the Hotel Guest setup.
----------------------------
Step 1 - Configure Interface
----------------------------
For the Guest Network we will add a new interface.
Go to **Interfaces->Assignments** And use the **+** to add a new interface.
Press **Save**. The new interface will be called **OPT1**, click on [OPT1] in the
left menu to change its settings.
Select **Enable Interface** and fill in the following data for our example:
============================== ================= ==============================================
**Description** GUESTNET *A descriptive name for the interface*
**Block Private networks** unselected
**Block bogon networks** unselected
**IPv4 Configuration Type** Static IPv4 *Set a static IPv4 address for the example*
**IPv6 configuration Type** None
**MAC address** (Leave Blank)
**MTU** (Leave Blank)
**MSS** (Leave Blank)
**Speed and duplex** Default *You may also select the speed when known*
**Static IPv4 address** 192.168.200.1/24 *We will use this segment for our guests*
**IPv4 Upstream Gateway** None
============================== ================= ==============================================
Press **Save** and then **Apply changes**.
------------------------------
Step 2 - Configure DHCP Server
------------------------------
Go to **Services->DHCP->Server** and click on the tab **GUESTNET**.
Fill in the following to setup the DHCP server for our guest net (leave everything
else on its default setting):
================ ==================================== =======================================
**Enable** Checked *Enable the DCHP server on GUESTNET*
**Range** 192.168.200.100 to 192.168.200.200 *Serve ip's from this range*
**DNS servers** 192.168.200.1 *Supply a DNS with the lease*
**Gateway** 192.168.200.1 *Supply a gateway with the lease*
================ ==================================== =======================================
Click **Save**.
---------------------------
Step 3 - Add Firewall Rules
---------------------------
Go to **Firewall->Rules** to add a new rule.
Now add the following rules (in order of prevalence):
Allow DNS
---------
Allow the guests access to the DNS forwarder.
Rule content (leave all other options default):
============================ ===================== =====================================
**Action** Pass *Allow this traffic*
**Interface** GUESTNET *The GuestNet Interface*
**Protocol** TCP/UDP
**Source** GUESTNET net
**Destination** GUESTNET address
**Destination port range** DNS/DNS *from DNS to DNS*
**Category** GuestNet Basic Rules *Category used for grouping rules*
**Description** Allow DNS
============================ ===================== =====================================
Click **Save**.
Allow Captive Portal Login
--------------------------
============================ ============================ =====================================
**Action** Pass *Allow this traffic*
**Interface** GUESTNET *The GuestNet Interface*
**Protocol** TCP
**Source** GUESTNET net
**Destination** GUESTNET address
**Destination port range** 8000/10000 *(other) used for the cp zones*
**Category** GuestNet Basic Rules *Category used for grouping rules*
**Description** Allow Captive Portal Login
============================ ============================ =====================================
Click **Save**.
Block Local Networks
--------------------
============================ ============================ =====================================
**Action** Block *Block this traffic*
**Interface** GUESTNET *The GuestNet Interface*
**Protocol** any
**Source** GUESTNET net
**Destination** LAN net
**Category** GuestNet Basic Rules *Category used for grouping rules*
**Description** Block Local Networks
============================ ============================ =====================================
Click **Save**.
============================ ============================ =====================================
**Action** Block *Block this traffic*
**Interface** GUESTNET *The GuestNet Interface*
**Protocol** any
**Source** GUESTNET net
**Destination** GUESTNET address
**Category** GuestNet Basic Rules *Category used for grouping rules*
**Description** Block Firewall Access
============================ ============================ =====================================
Click **Save**.
.. Note::
These rules are used to block access to our local LAN network and firewall access
from the Guests. If you have multiple local networks then you need to block
each of them with multiple rules or use a bigger subnet to cover them all.
Allow Guest Networks
--------------------
============================ ===================== =====================================
**Action** Pass *Allow this traffic*
**Interface** GUESTNET *The GuestNet Interface*
**Protocol** any
**Source** GUESTNET net
**Destination** any
**Destination port range** any
**Category** GuestNet Basic Rules *Category used for grouping rules*
**Description** Allow Guest Network
============================ ===================== =====================================
Click **Save** and then **Apply changes**
Your rules should look similar to the screenshot below:
.. image:: images/guestnet_fwrules.png
:scale: 100%
------------------------------
Step 4 - Create Captive Portal
------------------------------
Go to **Services->Captive Portal->Administration**
To add a new Zone press the **+** in the lower right corner of the form.
.. Note::
When using multiple interfaces with the captive portal then each interface can
have its own zone or multiple interfaces can share a zone.
For the *Business* setup we will start with the following settings:
============================ ================ =========================================
**Enabled** Checked
**Interfaces** GUESTNET *Remove the default and add GUESTNET*
**Authenticate using** (blank) *Remove any default setting*
**Idle timeout** 0 *Disable Idle Timeout*
**Hard timeout** 0 *No hard timeout*
**Concurrent user logins** Unchecked *A user may only login once*
**SSL certificate** none *Use plain http*
**Hostname** (leave blank) *Used for redirecting login page*
**Allowed addresses** (leave blank)
**Custom template** none *Use default template*
**Description** Guest Network *Choose a description for the zone*
============================ ================ =========================================
**Save** and the **Apply**
------------------------
Step 5 - Create Template
------------------------
The template feature is one of the most powerful features of OPNsense's Captive
Portal solution and it's very easy to work with.
Lets create a custom landing page, to do so click on the tab **Templates** and
click on the download icon in the lower right corner ( |download| ).
.. image:: images/template_download.png
:scale: 100%
Now download the default template, we will use this to create our own.
Unpack the template zip file, you should have something similar to this:
.. image:: images/template_filelisting.png
:scale: 100%
Most files of the template can be modified, but some are default and may not be
changes. Upon upload any changes to the files listed in **exclude.list** will be
ignored. Currently these include the bootstrap java scripting and some fonts.
With the captive portal enabled the default screen looks like:
.. image:: images/default_login_no_authenticator.png
:scale: 100%
Lets change this default with a new logo and a welcome message, to this:
.. image:: images/mycompany_login.png
To do so use your favourite editor and open the **index.html** file to make the
changes.
Lets make the following changes to the template:
#. Change the logo to **company-logo.png**
#. Remove the navigation bar on the top
#. Remove the height and width from the **<img>** tag
#. Add a welcome text
#. Make a link to the company website
Find the following part:
.. code-block:: guess
<header class="page-head">
<nav class="navbar navbar-default" >
<div class="container-fluid">
<div class="navbar-header">
<a class="navbar-brand" href="#">
<img class="brand-logo" src="images/default-logo.png" height="30" width="150">
</a>
</div>
</div>
</nav>
</header>
And change to:
.. code-block:: guess
<header class="page-head">
<div align="center">
<a href="#">
<img class="brand-logo" src="images/company-logo.png">
</a>
<h1>Welcome to My Company Guest Network.</h1>
<h2>Feel free to use the guest network for profesional usage</h2>
<h3>See our website for more details: <a href="https://www.opnsense.org">My Company</a></h3>
</div>
</header>
Copy the company logo to the image directory.
Now zip the template directory and upload the new template by pressing the **+**
on the Template tab.
:download:`Download the example Template (full) <resources/mycompany_cptemplate.zip>`
Enter a **Template Name**, for this example we use **Company**.
Hit Upload ( |upload| )
.. |download| image:: images/btn_download.png
:scale: 100%
.. |upload| image:: images/btn_upload.png
:scale: 100%
To enable the captive portal on the GUESTNET interface just click on **Apply**.
-------------------------------
Step 6 - Limit Guests Bandwidth
-------------------------------
For our example we will reserve 10Mbps down and 1Mbps Up for the Guest Network's
Internet Access. This bandwidth will be shared evenly between connected clients.
.. Note::
With sharing evenly we mean that if 10 users at the same time try to use
as much bandwidth as possible then everyone gets 1/10th. So in our example
that would be 1Mbps down stream (download). It is also possible to limit
the traffic per user see also :doc:`shaper`
Go to: **Firewall->Traffic Shaper->Settings**.
Create a pipe for the Download by pressing the **+** in the lower right corner of
the form and enter the following details:
====================== ===================
**Enabled** Checked
**bandwidth** 10
**bandwidth Metric** Mbit/s
**mask** Destination
**Description** pipe_10Mbps_down
====================== ===================
Click on **Save changes**.
And add another pipe for the upload traffic.
====================== ===================
**Enabled** Checked
**bandwidth** 1
**bandwidth Metric** Mbit/s
**mask** Destination
**Description** pipe_1Mbps_up
====================== ===================
Click on **Save changes**.
Create the traffic shaper rules.Click on the tab **Rules** and press the **+**
to do so.
First toggle the advanced mode (upper left corner of the form) and then fill in
the following details (leave everything not specified on defaults):
================= ==================================
**sequence** (leave on default)
**interface** WAN
**interface 2** GUESTNET
**direction** in
**target** pipe_10Mbps_down
**description** Limit Guests download to 10Mbps
================= ==================================
Click **Save changes**.
================= ==================================
**sequence** (leave on default)
**interface** WAN
**interface 2** GUESTNET
**direction** out
**target** pipe_1Mbps_up
**description** Limit Guests upload to 1Mbps
================= ==================================
Click **Save changes**.
Now click on **Apply** to apply the changes.
-------------------------------
Step 7 - Test Business GuestNet
-------------------------------
Connect your PC or laptop to the Guest Network and start your favourite browser.
Enter an address to browse to and you will be presented with the Login form we
created with the template in the previous step. Click on login and start browsing.
To test your traffic shaper go to a speed test site such as http://www.speedtest.net/
After testing your result should be similar to this (if your internet connection
has sufficient bandwidth).
.. image:: images/cp-traffic-shaping.png
:scale: 100%
.. Note::
Keep in mind we have only one connected client in this test, so all reserved
bandwidth will be available for our client.
-------------------
Royal Hotel Example
-------------------
From this point we will implement the Hotel/RV Park solution. You need to follow
step 1-7 first and choose the template you like to use for your guests.
This example will be for our "Royal Hotel".
---------------------------
Step 8 - Add Voucher Server
---------------------------
To add a Voucher Server go to: **System->Access->Servers** and click on
**Add server** in the top right corner of the screen.
Fill in:
======================= =========== =====================================
**Descriptive name** Vouchers *The name for your voucher server*
**Type** Voucher
======================= =========== =====================================
Click on **Save**.
------------------------
Step 9 - Create Vouchers
------------------------
Go back to the Captive portal and select Vouchers (**Services->Captive Portal->Vouchers**).
Click on **Create Vouchers** in the lower right corner of the form.
Lets create 1 Day vouchers for our guests:
.. image:: images/create_vouchers.png
:scale: 100%
Enter the Validity (1 day), the number of Vouchers and a Groupname (Wifi day pass f.i.).
For the example we create 10 vouchers. Click on **Generate**.
A file will be generated called **wifi day pass.csv**.
The content of this file looks like this:
.. code-block:: guess
username,password,vouchergroup,validity
"IgJw@Pqf","MLi+Sb7Ak#","Wifi day pass","86400"
"++?f[@i[","!m*)e(@;F,","Wifi day pass","86400"
"bbtK9mBk","f/jCDL3:)b","Wifi day pass","86400"
"iD%L[jLJ","I#FoZ#g!AY","Wifi day pass","86400"
"+4bA\E[I","CNavt@0ck+","Wifi day pass","86400"
"+,fg/\Sv","#22iIL-iQA","Wifi day pass","86400"
":;Pc\N#s","Y\HuG9vAN$","Wifi day pass","86400"
"00nLb=0Q","0*C_\_Nb_x","Wifi day pass","86400"
"PA$J0YHF","kp!q%9;m)g","Wifi day pass","86400"
"a,mCxbya","LcnCb#g/di","Wifi day pass","86400"
The content are:
=================== ========================================================
**username** *Username the guest needs to login with*
**password** *Password the guest needs to login with*
**vouchergroup** *The name of the group you created*
**validity** *The time the voucher will be valid in seconds*
=================== ========================================================
.. Warning::
For security reasons the plain text password for the vouchers are NOT stored
on the firewall.
This file can be used for creating nice guest vouchers (on paper) by just merging
the cvs data with word, open office or any other dtp/text editor.
Create something like this:
.. image:: images/cp_royalhotel_voucher.png
:scale: 100%
You can select a database to and remove it entirely. This way you can
create a voucher database for the arrival date of guest per guest group
(week, midweek, weekend, etc.) and delete the full database when the guests have
left.
.. Note::
When a voucher is activated the time will be used regardless of the user being
logged in or out. For a "used time" solution use a Radius server look at
:doc:`accounting`
--------------------------------
Step 10 - Voucher Authentication
--------------------------------
Enable the voucher authentication by changing the zone settings.
Go to the tab **Zones** and select the Guest Network by clicking on the pencil icon
right next to it.
Change **Authenticate using** from an empty field to **Vouchers**.
When done click **Save changes** and the **Apply** to apply the new settings.
Now users will see the login form as part of your template:
.. image:: images/cp_voucher_login.png
:scale: 100%
--------------
Check Sessions
--------------
To check the active sessions go to **Services->Captive Portal->Sessions**
Our current session looks like this:
.. image:: images/cp_active_sessions.png
:scale: 100%
You can drop an active session by clicking on the trashcan.
.. Note::
Notice the selection box at the upper right corner, with this you can select
the right zone when you have configured more than one.
--------------------
Check Voucher Status
--------------------
You can check the validity and active status of a voucher by going to the voucher
page of the captive portal (**Services->Captive Protal->Vouchers**) and select
the correct database (Wifi day pass in our example).
.. image:: images/cp_active_vouchers.png
:scale: 100%
.. Note::
The state valid means it is activated but still valid.
------------------------
Advanced - Session popup
------------------------
Lets create a Session Popup so user can see some details about there session and
Logout. For this feature we will use OPNsense's build-in api calls.
In particular we will use the following api call (for zone id 0):
.. code-block:: guess
/api/captiveportal/access/status/0/
The response on this api call looks like this (for an active session):
.. code-block:: json
{"userName":"IgJw@Pqf",
"macAddress":"10:dd:b1:bc:75:46",
"acc_session_timeout":14095,
"authenticated_via":"Vouchers",
"packets_out":2834,
"bytes_in":512869,
"last_accessed":1457527526,
"zoneid":0,
"sessionId":"npd5bd6SIVQeMfIbWBdong==","
startTime":1457526930.1719,
"bytes_out":1322351,
"ipAddress":"192.168.200.100",
"packets_in":3181,
"clientState":"AUTHORIZED"}
It would go a bit to far to explain standard html and java scripting used for
our simple popup, but a full demo template can be downloaded:
:download:`Download the example Template (with popup) <resources/template_popup.zip>`
The demo includes a new file called **session_popup.html** with all the logic to
show the time left on the voucher and a logout button. As well as a simple update
to our index.html page to call the popup on a successful login. The latter looks
like this (shown with a bit of context):
.. code-block:: javascript
// redirect on successful login
if (data['clientState'] == 'AUTHORIZED') {
window.open("session_popup.html","Session Status & Logout","width=400, height=400");
.. image:: images/captiveportal_popup.png
:scale: 100%
-----------------------------
Advanced - CLI Session Status
-----------------------------
OPNsense has a very powerful CLI that is particularly useful for debugging purposes.
For this example we will use the cli to list the status off all active sessions.
Type the following on the cli prompt to do so (for zone id 0):
.. code-block:: guess
configctl captiveportal list_clients 0
The output will be something similar to this:
.. image:: images/cli_list_captiveportalsessions.png
:scale: 100%

View File

@ -0,0 +1,201 @@
=======
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 an ACL
----------------------------
In this step an ACL will has to be created which is later used to decide
which traffic from a frontend belongs to which backend.
To create a new ACL, you have to create one by clicking the `+` button:
.. 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 ACL
**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 Action
--------------------------------
As promised in the previous step, the ACLs will be used. An Action will link
multiple ACLs with a Backend.
An Action is created using the `+` button.
.. image:: images/haproxy_actions.png
A form dialog opens and we can fill it out like the following:
.. image:: images/haproxy_edit_action.png
.. Note::
You can map using 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 Frontend.
A Frontend is a a group of bound ports which are used for incoming connections.
From this Frontend we need to know which backend the request will routed to.
For this, the previously configured action is needed.
To create a new Frontend, click the `+` button:
.. 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 configure the previously configured actions, so HAProxy
knows where the requests should be sent to.
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.

View File

@ -0,0 +1,85 @@
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 "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

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 108 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 87 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 71 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Some files were not shown because too many files have changed in this diff Show More