firewalld
Version information
This version is compatible with:
- Puppet Enterprise 2018.1.x, 2017.3.x, 2017.2.x, 2017.1.x, 2016.5.x, 2016.4.x
- Puppet >= 4.0.0 < 6.0.0
- ,
This module has been deprecated by its author since Oct 21st 2019.
The reason given was: Migrated to Vox Pupuli
The author has suggested puppet-firewalld as its replacement.
Start using this module
Documentation
Module: firewalld
Description
This module manages firewalld, the userland interface that replaces iptables and ships with RHEL7. The module manages firewalld itself as well as providing types and providers for managing firewalld zones, ports, and rich rules.
Compatibility
Latest versions of this module (3.0+) are only supported on Puppet 4.0+. 2.2.0 is the latest version to run on Puppet 3.x, important patches (security bugs..etc) will be accepted in the 2.x until Puppet 3.x is offically end-of-life, but new features will only be accepted in 3.x.
Usage
class { 'firewalld': }
Parameters
package
: Name of the package to install (default firewalld)package_ensure
: Default 'installed', can be any supported ensure type for the package resourceconfig_package
: Name of the GUI package, default firewall-configinstall_gui
: Whether or not to install the config_package (default: false)service_ensure
: Whether the service should be running or not (default: running)service_enable
: Whether to enable the servicedefault_zone
: Optional, set the default zone for interfaces (default: undef)log_denied
: Optional, (firewalld-0.4.3.2-8+) Log denied packets, can be one ofoff
,all
,multicast
,unicast
,broadcast
(default: undef)zones
: A hash of firewalld zones to configureports
: A hash of firewalld ports to configureservices
: A hash of firewalld services to configurerich_rules
: A hash of firewalld rich rules to configurecustom_services
: A hash of firewalld custom services to configuredirect_rules
: A hash of firewalld direct rules to configuredirect_chains
: A hash of firewalld direct chains to configuredirect_passthroughs
: A hash of firewalld direct passthroughs to configurepurge_direct_rules
: True or false, whether to purge firewalld direct rulespurge_direct_chains
: True or false, whether to purge firewalld direct chainspurge_direct_passthroughs
: True or false, whether to purge firewalld direct passthroughs
Resource Types
The firewalld module contains types and providers to manage zones, services, ports, and rich rules by interfacing with the firewall-cmd
command. The following types are currently supported. Note that all zone, service, port, and rule management is done in --permanent
mode, and a complete reload will be triggered anytime something changes.
This module supports a number of resource types
- firewalld_zone
- firewalld_port
- firewalld_service
- firewalld_ipset
- firewalld_rich_rule
- firewalld_direct_chain
- firewalld_direct_rule
- firewalld_direct_passthrough
Note, it is always recommended to include the ::firewalld
class if you are going to use any of these resources from another Puppet class (eg: a profile) as it sets up the relationships between the firewalld
service resource and the exec resource to reload the firewall upon change. Without the firewalld
class included then the firewall will not be reloaded upon change. The recommended pattern is to put all resources into hiera and let the firewalld
class set them up. Examples of both forms are presented for the resource types below.
Firewalld Zones
Firewalld zones can be managed with the firewalld_zone
resource type.
Example in Class:
firewalld_zone { 'restricted':
ensure => present,
target => '%%REJECT%%',
purge_rich_rules => true,
purge_services => true,
purge_ports => true,
}
Example in Hiera:
firewalld::zones:
restricted:
ensure: present
target: '%%REJECT%%'
purge_rich_rules: true
purge_services: true
purge_ports: true
Parameters
target
: Specify the target of the zone.interfaces
: An array of interfaces for this zonesources
: An array of sources for the zoneicmp_blocks
: An array of ICMP blocks for the zonemasquerade
: If set totrue
orfalse
specifies whether or not to add masquerading to the zonepurge_rich_rules
: Optional, and defaulted to false. When true any configured rich rules found in the zone that do not match what is in the Puppet catalog will be purged.purge_services
: Optional, and defaulted to false. When true any configured services found in the zone that do not match what is in the Puppet catalog will be purged. Warning: This includes the default ssh service, if you need SSH to access the box, make sure you add the service through either a rich firewall rule, port, or service (see below) or you will lock yourself out!purge_ports
: Optional, and defaulted to false. When true any configured ports found in the zone that do not match what is in the Puppet catalog will be purged. Warning: As with services, this includes the default ssh port. If you fail to specify the appropriate port, rich rule, or service, you will lock yourself out.
Firewalld rich rules
Firewalld rich rules are managed using the firewalld_rich_rule
resource type
firewalld_rich_rules will autorequire
the firewalld_zone specified in the zone
parameter so there is no need to add dependencies for this
Example in Class:
firewalld_rich_rule { 'Accept SSH from barny':
ensure => present,
zone => 'restricted',
source => '192.168.1.2/32',
service => 'ssh',
action => 'accept',
}
Example in Hiera:
firewalld::rich_rules:
'Accept SSH from barny':
ensure: present
zone: restricted
source: '192.168.1.2/32'
service: 'ssh'
action: 'accept'
Parameters
-
zone
: Name of the zone this rich rule belongs to -
family
: Protocol family, defaults toipv4
-
source
: Source address information. This can be a hash containing the keysaddress or ipset
andinvert
, or a string containing just the IP addresssource => '192.168.2.1', source => { 'address' => '192.168.1.1', 'invert' => true } source => { 'ipset' => 'whitelist', 'invert' => true } source => { 'ipset' => 'blacklist' }
-
dest
: Destination address information. This can be a hash containing the keysaddress or ipset
andinvert
, or a string containing just the IP addressdest => '192.168.2.1', dest => { 'address' => '192.168.1.1', 'invert' => true } dest => { 'ipset' => 'whitelist', 'invert' => true } dest => { 'ipset' => 'blacklist' }
-
log
: When set totrue
will enable logging, optionally this can be hash withprefix
,level
andlimit
log => { 'level' => 'debug', 'prefix' => 'foo' }, log => true,
-
audit
: When set totrue
will enable auditing, optionally this can be hash withlimit
audit => { 'limit' => '3/s' }, audit => true,
-
action
: A string containing the actionaccept
,reject
ordrop
. Forreject
it can be optionally supplied as a hash containingtype
action => 'accept' action => { 'action' => 'reject', 'type' => 'bad' }
The following paramters are the element of the rich rule, only one may be used.
-
service
: Name of the service -
protocol
: Protocol of the rich rule -
port
: A hash containingport
andprotocol
valuesport => { 'port' => 80, 'protocol' => 'tcp', },
-
icmp_block
: Specify anicmp-block
for the rule -
masquerade
: Set totrue
orfalse
to enable masquerading -
forward_port
: Set forward-port, this should be a hash containingport
,protocol
,to_port
,to_addr
forward_port => { 'port' => '8080', 'protocol' => 'tcp', 'to_addr' => '10.2.1.1', 'to_port' => '8993' },
Firewalld Custom Service
The firewalld::custom_service
defined type creates and manages custom services. It makes the service usable by firewalld, but does not add it to any zones. To do that, use the firewalld::service type.
Example in Class:
firewalld::custom_service{'puppet':
short => 'puppet,
description => 'Puppet Client access Puppet Server',
port => [
{
'port' => '8140',
'protocol' => 'tcp',
},
{
'port' => '8140',
'protocol' => 'udp',
},
],
module => ['nf_conntrack_netbios_ns'],
destination => {
'ipv4' => '127.0.0.1',
'ipv6' => '::1'
}
}
Example in Hiera:
firewalld::custom_services:
puppet:
short: 'puppet'
description: 'Puppet Client access Puppet Server'
port:
- port: 8140
protocol: 'tcp'
module: 'nf_conntrack_netbios_ns'
destination:
ipv4: '127.0.0.1'
ipv6: '::1'
This resource will create the following XML service definition in /etc/firewalld/services/XZY.xml
<?xml version="1.0" encoding="utf-8"?>
<service>
<short>puppet</short>
<description>Puppet Client access Puppet Server</description>
<port protocol="tcp" port="8140" />
<port protocol="udp" port="8140" />
<module name="nf_conntrack_netbios_ns"/>
<destination ipv4="127.0.0.1" ipv6="::1"/>
</service>
and you will also see 'puppet' in the service list when you issue firewall-cmd --permanent --get-services
Parameters
-
short
: (namevar) The short name of the service (what you see in the firewalld command line output) -
description
: (Optional) A short description of the service -
port
: (Optional) The protocol / port definitions for this service. Specified as an array of hashes, where each hash defines a protocol and/or port associated with this service. Each hash requires both port and protocol keys, even if the value is an empty string. Specifying a port only works for TCP & UDP, otherwise leave it empty and the entire protocol will be allowed. Valid protocols are tcp, udp, or any protocol defined in /etc/protocolsport => [{'port' => '1234', 'protocol' => 'tcp'}], port => [{'port' => '4321', 'protocol' => 'udp'}, {'protocol' => 'rdp'}],
The port
parameter can also take a range of ports separated by a colon, for example:
port => [ {'port' => '8000:8002', 'protocol' => 'tcp']} ]
will produce;
<port protocol="tcp" port="8000" />
<port protocol="tcp" port="8001" />
<port protocol="tcp" port="8002" />
-
module
: (Optional) An array of strings specifying netfilter kernel helper modules associated with this service -
destination
: (Optional) A hash specifying the destination network as a network IP address (optional with /mask), or a plain IP address. Valid hash keys are 'ipv4' and 'ipv6', with values corresponding to the IP / mask associated with each of those protocols. The use of hostnames is possible but not recommended, because these will only be resolved at service activation and transmitted to the kernel.destination => {'ipv4' => '127.0.0.1', 'ipv6' => '::1'}, destination => {'ipv4' => '192.168.0.0/24'},
-
config_dir
: The location where the service definition XML files will be stored. Defaults to /etc/firewalld/services
Firewalld Service
The firewalld_service
type is used to add or remove both built in and custom services from zones.
firewalld_service will autorequire
the firewalld_zone specified in the zone
parameter and the firewalld::custom_service
specified in the service
parameter, so there is no need to add dependencies for this
Example in Class:
firewalld_service { 'Allow SSH from the external zone':
ensure => 'present',
service => 'ssh',
zone => 'external',
}
Example in Hiera:
firewalld::services:
'Allow SSH from the external zone':
ensure: present
service: ssh
zone: external
dhcp:
ensure: absent
service: dhcp
zone: public
dhcpv6-client:
ensure: present
service: dhcpv6-client
zone: public
Parameters
-
service
: Name of the service to manage -
zone
: Name of the zone in which you want to manage the service
Firewalld Ipsets
Firewalld IPsets (on supported versions of firewalld) can be managed using the firewalld_ipset
resource type
Example:
firewalld_ipset { 'whitelist':
ensure => present,
entries => [ '192.168.0.1', '192.168.0.2' ]
}
Example in Hiera:
firewalld::ipsets:
whitelist:
entries:
- 192.168.0.1
- 192.168.0.2
Parameters
entries
: An array of entries for the IPsettype
: Type of ipset (default:hash:ip
)options
: A hash of options for the IPset (eg:{ "family" => "ipv6"}
)
Note that type
and options
are parameters used when creating the IPset and are not managed after creation - to change the type or options of an ipset you must delete the existing ipset first.
Firewalld Ports
Firewalld ports can be managed with the firewalld_port
resource type.
firewalld_port will autorequire
the firewalld_zone specified in the zone
parameter so there is no need to add dependencies for this
Example:
firewalld_port { 'Open port 8080 in the public zone':
ensure => present,
zone => 'public',
port => 8080,
protocol => 'tcp',
}
Example in Hiera:
firewalld::ports:
'Open port 8080 in the public zone':
ensure: present
zone: public
port: 8080
protocol: 'tcp'
Parameters
-
zone
: Name of the zone this port belongs to -
port
: A hash containingport
andprotocol
values
port => {
'port' => 8080,
'protocol' => 'tcp',
},
Firewalld Direct Chains
Direct chains can be managed with the firewalld_direct_chain
type
Example:
firewalld_direct_chain {'Add custom chain LOG_DROPS':
name => 'LOG_DROPS',
ensure => present,
inet_protocol => 'ipv4',
table => 'filter',
}
The title can also be mapped to the types namevars using a colon delimited string, so the above can also be represented as
firewall_direct_chain { 'ipv4:filter:LOG_DROPS':
ensure => present,
}
Example in hiera
firewalld::direct_chains:
'Add custom chain LOG_DROPS':
name: LOG_DROPS
ensure: present
inet_protocol: ipv4
table: filter
Parameters
name
: name of the chain, egLOG_DROPS
(namevar)inet_protocol
: ipv4 or ipv6, defaults to ipv4 (namevar)table
: The table (eg: filter) to apply the chain (namevar)
Firewalld Direct Rules
Direct rules can be applied using the firewalld_direct_rule
type
Example:
firewalld_direct_rule {'Allow outgoing SSH connection':
ensure => 'present',
inet_protocol => 'ipv4',
table => 'filter',
chain => 'OUTPUT',
priority => 1,
args => '-p tcp --dport=22 -j ACCEPT',
}
Example in hiera
firewalld::direct_rules:
'Allow outgoing SSH connection':
ensure: present
inet_protocol: ipv4
table: filter
chain: OUTPUT
priority: 1
args: '-p tcp --dport=22 -j ACCEPT'
Parameters
name
: Resource name in Puppetensure
: present or absentinet_protocol
: ipv4 or ipv6, defaults to ipv4table
: Table (eg: filter) which to apply the rulechain
: Chain (eg: OUTPUT) which to apply the rulepriority
: The priority number of the rule (e.g: 0, 1, 2, ... 99)args
: Any iptables, ip6tables and ebtables command line arguments
Firewalld Direct Passthroughs
Direct passthroughs can be applied using the firewalld_direct_passthrough
type
Example:
firewalld_direct_passthrough {'Forward traffic from OUTPUT to OUTPUT_filter':
ensure => 'present',
inet_protocol => 'ipv4',
args => '-A OUTPUT -j OUTPUT_filter'
}
Example in hiera
firewalld::direct_passthroughs:
'Forward traffic from OUTPUT to OUTPUT_filter':
ensure: present
inet_protocol: ipv4
args: '-A OUTPUT -j OUTPUT_filter'
Parameters
name
: Resource name in Puppetensure
: present or absentinet_protocol
: ipv4 or ipv6, defaults to ipv4args
: Name of the passthroughhrough to add (e.g: -A OUTPUT -j OUTPUT_filter)
Author
- Written and maintained by Craig Dunn craig@craigdunn.org @crayfishx
- Sponsored by Baloise Group http://baloise.github.io
Types in this module release
3.4.0
- Feature: Added
$log_denied
parameter for configuring the logging of dropped packets using the--set-log-denied
feature (firewalld 0.4.3.2-8) (https://github.com/crayfishx/puppet-firewalld/issues/153)
3.3.2
- Bugfix: Corrected issue with setting default zones on Debian systems running dash instead of bash (https://github.com/crayfishx/puppet-firewalld/pull/144)
- Bugfix: Various typos in error messages fixed (https://github.com/crayfishx/puppet-firewalld/pull/145)
- Bugfix: Fixed issue with
firewalld_zone
provider in later versions of firewalld where the command stops returning a zones sources in alphanumeric order causing issues for Puppet to determine if the resource attribute is in sync (https://github.com/crayfishx/puppet-firewalld/pull/144) - Bugfix: Fixed issue where
firewalld_zone
did not addicmp_block
entires on creation, requiring another Puppet run (https://github.com/crayfishx/puppet-firewalld/issues/139)
3.3.1
- Bugfix: Dependency fix for adding a default zone in the same puppet run as creating the zone. This solves the issue of firewalld failing to set the default zone because firewalld hasn't reloaded yet and it can't see the zone as active. (https://github.com/crayfishx/puppet-firewalld/issues/135)
3.3.0
- Feature: added the
firewalld_ipset
type to manage IPsets (https://github.com/crayfishx/puppet-firewalld/issues/108) - Feature: added
masquerade
attribute tofirewalld_zone
to manage masquerading on zones (https://github.com/crayfishx/puppet-firewalld/issues/129) - Feature: added
ipset
option to rich rules source option - Various documentation bugfixes
3.2.1
- Bugfix: Fix for when custom_service ports are defined as integers, (https://github.com/crayfishx/puppet-firewalld/issues/122)
- Documentation fixes
3.2.0
- Feature: allow for port ranges to be defined with
custom_service
declarations (https://github.com/crayfishx/puppet-firewalld/issues/107) - Feature: added
default_zone
to the firewalld base class to allow for a default zone to be defined (https://github.com/crayfishx/puppet-firewalld/pull/118) - Bugfix: Fix to
firewalld_rich_rule
types when firewalld is in a down state (https://github.com/crayfishx/puppet-firewalld/issues/112) - Bugfix: Better service availability checking when purging rules (https://github.com/crayfishx/puppet-firewalld/issues/101)
- Bugfix: Handle later versions of firewalld where the target is returned as
REJECT
instead of%%REJECT%%
- this is a backwards compatible fix (https://github.com/crayfishx/puppet-firewalld/issues/111) - Numerous documentation typo fixes
3.1.8
-
Bugfix: Change how types and providers reference other providers by referencing the
Puppet::Type
API rather than trying to load them withrequire
. This addresses some intermitent problems with Puppets autoloading and registering of types that caused exceptions in Puppet 4.5.0+ in some circumstances, depending on the ordering of the manifest evaluation. See https://github.com/crayfishx/puppet-firewalld/issues/93 and https://tickets.puppetlabs.com/browse/PUP-6922 -
Documentation fixes (#100)
3.1.7
- Bugfix: This release addresses an issue configuring firewalld on a system where the package is not yet installed. The logic used to determine the state of the firewall is run before the package provider can install the package causing catalog application to fail. Fixed https://github.com/crayfishx/puppet-firewalld/issues/96
3.1.6
- Bugfix: #94. puppet types generate failed with the following error
Error: /etc/puppetlabs/code/environments/production/modules/firewalld/lib/puppet/type/firewalld_direct_chain.rb: title patterns that use procs are not supported.
Since procs are not actually needed in this title pattern they have been removed to stop this error.
3.1.5
- Bugfix: #90 -
firewalld_service
fails to remove services in offline mode. see https://github.com/crayfishx/puppet-firewalld/issues/90 - Internal: Provider tests for the state of firewalld on initiation to decide which command to use (
firewall-cmd
orfirewall-offline-cmd
) rather than relying on catching an exception inexecute_firewall()
3.1.4
- Bugfix:
--get-icmptypes
running against--zone
when it is a global option. https://github.com/crayfishx/puppet-firewalld/issues/86
3.1.3
- Bugfix (CRITICAL) : Purging not respecting --noop mode. https://github.com/crayfishx/puppet-firewalld/pull/84
- Bugfix : firewalld_direct_zones with single quotes in the arguments causes a misconfigured XML file. https://github.com/crayfishx/puppet-firewalld/pull/83
3.1.2
- Bugfix: use relative file location for requiring
lib/puppet/type/firewalld_direct_*
, https://github.com/crayfishx/puppet-firewalld/pull/80
3.1.1
- Bugfix: use relative file location for requiring
lib/puppet/provider/firewalld
, this addresses https://github.com/crayfishx/puppet-firewalld/issues/78
3.1.0
- Feature: firewalld::custom_service now accepts a
filename
parameter, defaults to the value ofshort
for backwards compatibility. Note that this change will be short lived and replaced by a name pattern in 4.0.0. See issue https://github.com/crayfishx/puppet-firewalld/issues/75 - Multiple fixes to purging of firewalld resources, if enabled, running configuration will always be purged by a firewall restart if there are any resources found to be purgable. This addresses https://github.com/crayfishx/puppet-firewalld/issues/26
- Bugfix: 2 Puppet runs required to create a custom service and attach to a zone, fixed. See https://github.com/crayfishx/puppet-firewalld/issues/27
- Bugfix: Added resource chains (as in 2.x) to set relationships between service, resources and the exec to reload firewall, this fixes an issue where resources declared in Puppet (eg: from the profile) do not automatically get their dependencies set. See https://github.com/crayfishx/puppet-firewalld/issues/38
3.0.2
- Bugfix release
- Fixed issue #68, direct_rules and passthroughs badly configured
3.0.1
- Puppet forge metadata changes, no functional changes.
3.0.0
- BREAK: Puppet manifests now written for the new parser, must use Puppet 4 or 3.x + Future parser
- custom_services now configurable in hiera
- BREAK: #58 Reloads by default now use --reload, not --complete-reload (separate resource provided for that)
- Bugfix #64 : invert => true for source and destinations on rich rules fixed.
- New types and providers for direct chains, rules and passthroughs
- Provider will attempt to call firewall-offline-cmd if an exception is raised suggesting the service is down (see #46)
- Overhaul of internals for the providers
- Many more tests added
2.2.0
- #43 firewall-config package is not installed by default, can be enabled with the install_gui param
- #33 Protocol element now managed by firewalld_rich_rile
- #13 ELEMENTS constant changed to a method to stop ruby warnings
2.0.0
- Fix: #25 - purge_ports for firewalld_zone now works as expected
- BREAK: port parameter for firewalld_port now only accepts a port, not a hash as previously documented.
Dependencies
- puppetlabs/stdlib (>=4.2.0 <5.0.0)
Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "{}" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright 2015 Craig Dunn <craig@craigdunn.org> Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.