PageRenderTime 48ms CodeModel.GetById 12ms RepoModel.GetById 0ms app.codeStats 0ms

/lib/puppet/type/firewall.rb

https://github.com/bambriy/puppetlabs-firewall
Ruby | 1084 lines | 877 code | 168 blank | 39 comment | 39 complexity | da8ca69cd8869fe6321d60830247796d MD5 | raw file
Possible License(s): Apache-2.0
  1. # See: #10295 for more details.
  2. #
  3. # This is a workaround for bug: #4248 whereby ruby files outside of the normal
  4. # provider/type path do not load until pluginsync has occured on the puppetmaster
  5. #
  6. # In this case I'm trying the relative path first, then falling back to normal
  7. # mechanisms. This should be fixed in future versions of puppet but it looks
  8. # like we'll need to maintain this for some time perhaps.
  9. $LOAD_PATH.unshift(File.join(File.dirname(__FILE__),"..",".."))
  10. require 'puppet/util/firewall'
  11. Puppet::Type.newtype(:firewall) do
  12. include Puppet::Util::Firewall
  13. @doc = <<-EOS
  14. This type provides the capability to manage firewall rules within
  15. puppet.
  16. **Autorequires:**
  17. If Puppet is managing the iptables or ip6tables chains specified in the
  18. `chain` or `jump` parameters, the firewall resource will autorequire
  19. those firewallchain resources.
  20. If Puppet is managing the iptables or iptables-persistent packages, and
  21. the provider is iptables or ip6tables, the firewall resource will
  22. autorequire those packages to ensure that any required binaries are
  23. installed.
  24. EOS
  25. feature :connection_limiting, "Connection limiting features."
  26. feature :hop_limiting, "Hop limiting features."
  27. feature :rate_limiting, "Rate limiting features."
  28. feature :recent_limiting, "The netfilter recent module"
  29. feature :snat, "Source NATing"
  30. feature :dnat, "Destination NATing"
  31. feature :interface_match, "Interface matching"
  32. feature :icmp_match, "Matching ICMP types"
  33. feature :owner, "Matching owners"
  34. feature :state_match, "Matching stateful firewall states"
  35. feature :reject_type, "The ability to control reject messages"
  36. feature :log_level, "The ability to control the log level"
  37. feature :log_prefix, "The ability to add prefixes to log messages"
  38. feature :mark, "Match or Set the netfilter mark value associated with the packet"
  39. feature :tcp_flags, "The ability to match on particular TCP flag settings"
  40. feature :pkttype, "Match a packet type"
  41. feature :socket, "Match open sockets"
  42. feature :isfragment, "Match fragments"
  43. feature :address_type, "The ability match on source or destination address type"
  44. feature :iprange, "The ability match on source or destination IP range "
  45. feature :ishasmorefrags, "Match a non-last fragment of a fragmented ipv6 packet - might be first"
  46. feature :islastfrag, "Match the last fragment of an ipv6 packet"
  47. feature :isfirstfrag, "Match the first fragment of a fragmented ipv6 packet"
  48. feature :ipsec_policy, "Match IPsec policy"
  49. feature :ipsec_dir, "Match IPsec policy direction"
  50. # provider specific features
  51. feature :iptables, "The provider provides iptables features."
  52. ensurable do
  53. desc <<-EOS
  54. Manage the state of this rule. The default action is *present*.
  55. EOS
  56. newvalue(:present) do
  57. provider.insert
  58. end
  59. newvalue(:absent) do
  60. provider.delete
  61. end
  62. defaultto :present
  63. end
  64. newparam(:name) do
  65. desc <<-EOS
  66. The canonical name of the rule. This name is also used for ordering
  67. so make sure you prefix the rule with a number:
  68. 000 this runs first
  69. 999 this runs last
  70. Depending on the provider, the name of the rule can be stored using
  71. the comment feature of the underlying firewall subsystem.
  72. EOS
  73. isnamevar
  74. # Keep rule names simple - they must start with a number
  75. newvalues(/^\d+[[:alpha:][:digit:][:punct:][:space:]]+$/)
  76. end
  77. newproperty(:action) do
  78. desc <<-EOS
  79. This is the action to perform on a match. Can be one of:
  80. * accept - the packet is accepted
  81. * reject - the packet is rejected with a suitable ICMP response
  82. * drop - the packet is dropped
  83. If you specify no value it will simply match the rule but perform no
  84. action unless you provide a provider specific parameter (such as *jump*).
  85. EOS
  86. newvalues(:accept, :reject, :drop)
  87. end
  88. # Generic matching properties
  89. newproperty(:source) do
  90. desc <<-EOS
  91. The source address. For example:
  92. source => '192.168.2.0/24'
  93. You can also negate a mask by putting ! in front. For example:
  94. source => '! 192.168.2.0/24'
  95. The source can also be an IPv6 address if your provider supports it.
  96. EOS
  97. munge do |value|
  98. begin
  99. @resource.host_to_mask(value)
  100. rescue Exception => e
  101. self.fail("host_to_ip failed for #{value}, exception #{e}")
  102. end
  103. end
  104. end
  105. # Source IP range
  106. newproperty(:src_range, :required_features => :iprange) do
  107. desc <<-EOS
  108. The source IP range. For example:
  109. src_range => '192.168.1.1-192.168.1.10'
  110. The source IP range is must in 'IP1-IP2' format.
  111. EOS
  112. newvalues(/^((25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)\.){3}(25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)-((25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)\.){3}(25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)/)
  113. end
  114. newproperty(:destination) do
  115. desc <<-EOS
  116. The destination address to match. For example:
  117. destination => '192.168.1.0/24'
  118. You can also negate a mask by putting ! in front. For example:
  119. destination => '! 192.168.2.0/24'
  120. The destination can also be an IPv6 address if your provider supports it.
  121. EOS
  122. munge do |value|
  123. begin
  124. @resource.host_to_mask(value)
  125. rescue Exception => e
  126. self.fail("host_to_ip failed for #{value}, exception #{e}")
  127. end
  128. end
  129. end
  130. # Destination IP range
  131. newproperty(:dst_range, :required_features => :iprange) do
  132. desc <<-EOS
  133. The destination IP range. For example:
  134. dst_range => '192.168.1.1-192.168.1.10'
  135. The destination IP range is must in 'IP1-IP2' format.
  136. EOS
  137. newvalues(/^((25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)\.){3}(25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)-((25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)\.){3}(25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)/)
  138. end
  139. newproperty(:sport, :array_matching => :all) do
  140. desc <<-EOS
  141. The source port to match for this filter (if the protocol supports
  142. ports). Will accept a single element or an array.
  143. For some firewall providers you can pass a range of ports in the format:
  144. <start_number>-<ending_number>
  145. For example:
  146. 1-1024
  147. This would cover ports 1 to 1024.
  148. EOS
  149. munge do |value|
  150. @resource.string_to_port(value, :proto)
  151. end
  152. def is_to_s(value)
  153. should_to_s(value)
  154. end
  155. def should_to_s(value)
  156. value = [value] unless value.is_a?(Array)
  157. value.join(',')
  158. end
  159. end
  160. newproperty(:dport, :array_matching => :all) do
  161. desc <<-EOS
  162. The destination port to match for this filter (if the protocol supports
  163. ports). Will accept a single element or an array.
  164. For some firewall providers you can pass a range of ports in the format:
  165. <start_number>-<ending_number>
  166. For example:
  167. 1-1024
  168. This would cover ports 1 to 1024.
  169. EOS
  170. munge do |value|
  171. @resource.string_to_port(value, :proto)
  172. end
  173. def is_to_s(value)
  174. should_to_s(value)
  175. end
  176. def should_to_s(value)
  177. value = [value] unless value.is_a?(Array)
  178. value.join(',')
  179. end
  180. end
  181. newproperty(:port, :array_matching => :all) do
  182. desc <<-EOS
  183. The destination or source port to match for this filter (if the protocol
  184. supports ports). Will accept a single element or an array.
  185. For some firewall providers you can pass a range of ports in the format:
  186. <start_number>-<ending_number>
  187. For example:
  188. 1-1024
  189. This would cover ports 1 to 1024.
  190. EOS
  191. munge do |value|
  192. @resource.string_to_port(value, :proto)
  193. end
  194. def is_to_s(value)
  195. should_to_s(value)
  196. end
  197. def should_to_s(value)
  198. value = [value] unless value.is_a?(Array)
  199. value.join(',')
  200. end
  201. end
  202. newproperty(:dst_type, :required_features => :address_type) do
  203. desc <<-EOS
  204. The destination address type. For example:
  205. dst_type => 'LOCAL'
  206. Can be one of:
  207. * UNSPEC - an unspecified address
  208. * UNICAST - a unicast address
  209. * LOCAL - a local address
  210. * BROADCAST - a broadcast address
  211. * ANYCAST - an anycast packet
  212. * MULTICAST - a multicast address
  213. * BLACKHOLE - a blackhole address
  214. * UNREACHABLE - an unreachable address
  215. * PROHIBIT - a prohibited address
  216. * THROW - undocumented
  217. * NAT - undocumented
  218. * XRESOLVE - undocumented
  219. EOS
  220. newvalues(:UNSPEC, :UNICAST, :LOCAL, :BROADCAST, :ANYCAST, :MULTICAST,
  221. :BLACKHOLE, :UNREACHABLE, :PROHIBIT, :THROW, :NAT, :XRESOLVE)
  222. end
  223. newproperty(:src_type, :required_features => :address_type) do
  224. desc <<-EOS
  225. The source address type. For example:
  226. src_type => 'LOCAL'
  227. Can be one of:
  228. * UNSPEC - an unspecified address
  229. * UNICAST - a unicast address
  230. * LOCAL - a local address
  231. * BROADCAST - a broadcast address
  232. * ANYCAST - an anycast packet
  233. * MULTICAST - a multicast address
  234. * BLACKHOLE - a blackhole address
  235. * UNREACHABLE - an unreachable address
  236. * PROHIBIT - a prohibited address
  237. * THROW - undocumented
  238. * NAT - undocumented
  239. * XRESOLVE - undocumented
  240. EOS
  241. newvalues(:UNSPEC, :UNICAST, :LOCAL, :BROADCAST, :ANYCAST, :MULTICAST,
  242. :BLACKHOLE, :UNREACHABLE, :PROHIBIT, :THROW, :NAT, :XRESOLVE)
  243. end
  244. newproperty(:proto) do
  245. desc <<-EOS
  246. The specific protocol to match for this rule. By default this is
  247. *tcp*.
  248. EOS
  249. newvalues(:tcp, :udp, :icmp, :"ipv6-icmp", :esp, :ah, :vrrp, :igmp, :ipencap, :ospf, :gre, :all)
  250. defaultto "tcp"
  251. end
  252. # tcp-specific
  253. newproperty(:tcp_flags, :required_features => :tcp_flags) do
  254. desc <<-EOS
  255. Match when the TCP flags are as specified.
  256. Is a string with a list of comma-separated flag names for the mask,
  257. then a space, then a comma-separated list of flags that should be set.
  258. The flags are: SYN ACK FIN RST URG PSH ALL NONE
  259. Note that you specify them in the order that iptables --list-rules
  260. would list them to avoid having puppet think you changed the flags.
  261. Example: FIN,SYN,RST,ACK SYN matches packets with the SYN bit set and the
  262. ACK,RST and FIN bits cleared. Such packets are used to request
  263. TCP connection initiation.
  264. EOS
  265. end
  266. # Iptables specific
  267. newproperty(:chain, :required_features => :iptables) do
  268. desc <<-EOS
  269. Name of the chain to use. Can be one of the built-ins:
  270. * INPUT
  271. * FORWARD
  272. * OUTPUT
  273. * PREROUTING
  274. * POSTROUTING
  275. Or you can provide a user-based chain.
  276. The default value is 'INPUT'.
  277. EOS
  278. defaultto "INPUT"
  279. newvalue(/^[a-zA-Z0-9\-_]+$/)
  280. end
  281. newproperty(:table, :required_features => :iptables) do
  282. desc <<-EOS
  283. Table to use. Can be one of:
  284. * nat
  285. * mangle
  286. * filter
  287. * raw
  288. * rawpost
  289. By default the setting is 'filter'.
  290. EOS
  291. newvalues(:nat, :mangle, :filter, :raw, :rawpost)
  292. defaultto "filter"
  293. end
  294. newproperty(:jump, :required_features => :iptables) do
  295. desc <<-EOS
  296. The value for the iptables --jump parameter. Normal values are:
  297. * QUEUE
  298. * RETURN
  299. * DNAT
  300. * SNAT
  301. * LOG
  302. * MASQUERADE
  303. * REDIRECT
  304. * MARK
  305. But any valid chain name is allowed.
  306. For the values ACCEPT, DROP and REJECT you must use the generic
  307. 'action' parameter. This is to enfore the use of generic parameters where
  308. possible for maximum cross-platform modelling.
  309. If you set both 'accept' and 'jump' parameters, you will get an error as
  310. only one of the options should be set.
  311. EOS
  312. validate do |value|
  313. unless value =~ /^[a-zA-Z0-9\-_]+$/
  314. raise ArgumentError, <<-EOS
  315. Jump destination must consist of alphanumeric characters, an
  316. underscore or a yphen.
  317. EOS
  318. end
  319. if ["accept","reject","drop"].include?(value.downcase)
  320. raise ArgumentError, <<-EOS
  321. Jump destination should not be one of ACCEPT, REJECT or DROP. Use
  322. the action property instead.
  323. EOS
  324. end
  325. end
  326. end
  327. # Interface specific matching properties
  328. newproperty(:iniface, :required_features => :interface_match) do
  329. desc <<-EOS
  330. Input interface to filter on.
  331. EOS
  332. newvalues(/^[a-zA-Z0-9\-\._\+]+$/)
  333. end
  334. newproperty(:outiface, :required_features => :interface_match) do
  335. desc <<-EOS
  336. Output interface to filter on.
  337. EOS
  338. newvalues(/^[a-zA-Z0-9\-\._\+]+$/)
  339. end
  340. # NAT specific properties
  341. newproperty(:tosource, :required_features => :snat) do
  342. desc <<-EOS
  343. When using jump => "SNAT" you can specify the new source address using
  344. this parameter.
  345. EOS
  346. end
  347. newproperty(:todest, :required_features => :dnat) do
  348. desc <<-EOS
  349. When using jump => "DNAT" you can specify the new destination address
  350. using this paramter.
  351. EOS
  352. end
  353. newproperty(:toports, :required_features => :dnat) do
  354. desc <<-EOS
  355. For DNAT this is the port that will replace the destination port.
  356. EOS
  357. end
  358. newproperty(:random, :required_features => :dnat) do
  359. desc <<-EOS
  360. When using a jump value of "MASQUERADE", "DNAT", "REDIRECT", or "SNAT"
  361. this boolean will enable randomized port mapping.
  362. EOS
  363. newvalues(:true, :false)
  364. end
  365. # Reject ICMP type
  366. newproperty(:reject, :required_features => :reject_type) do
  367. desc <<-EOS
  368. When combined with jump => "REJECT" you can specify a different icmp
  369. response to be sent back to the packet sender.
  370. EOS
  371. end
  372. # Logging properties
  373. newproperty(:log_level, :required_features => :log_level) do
  374. desc <<-EOS
  375. When combined with jump => "LOG" specifies the system log level to log
  376. to.
  377. EOS
  378. munge do |value|
  379. if value.kind_of?(String)
  380. value = @resource.log_level_name_to_number(value)
  381. else
  382. value
  383. end
  384. if value == nil && value != ""
  385. self.fail("Unable to determine log level")
  386. end
  387. value
  388. end
  389. end
  390. newproperty(:log_prefix, :required_features => :log_prefix) do
  391. desc <<-EOS
  392. When combined with jump => "LOG" specifies the log prefix to use when
  393. logging.
  394. EOS
  395. end
  396. # ICMP matching property
  397. newproperty(:icmp, :required_features => :icmp_match) do
  398. desc <<-EOS
  399. When matching ICMP packets, this is the type of ICMP packet to match.
  400. A value of "any" is not supported. To achieve this behaviour the
  401. parameter should simply be omitted or undefined.
  402. EOS
  403. validate do |value|
  404. if value == "any"
  405. raise ArgumentError,
  406. "Value 'any' is not valid. This behaviour should be achieved " \
  407. "by omitting or undefining the ICMP parameter."
  408. end
  409. end
  410. munge do |value|
  411. if value.kind_of?(String)
  412. # ICMP codes differ between IPv4 and IPv6.
  413. case @resource[:provider]
  414. when :iptables
  415. protocol = 'inet'
  416. when :ip6tables
  417. protocol = 'inet6'
  418. else
  419. self.fail("cannot work out protocol family")
  420. end
  421. value = @resource.icmp_name_to_number(value, protocol)
  422. else
  423. value
  424. end
  425. if value == nil && value != ""
  426. self.fail("cannot work out icmp type")
  427. end
  428. value
  429. end
  430. end
  431. newproperty(:state, :array_matching => :all, :required_features =>
  432. :state_match) do
  433. desc <<-EOS
  434. Matches a packet based on its state in the firewall stateful inspection
  435. table. Values can be:
  436. * INVALID
  437. * ESTABLISHED
  438. * NEW
  439. * RELATED
  440. EOS
  441. newvalues(:INVALID,:ESTABLISHED,:NEW,:RELATED)
  442. # States should always be sorted. This normalizes the resource states to
  443. # keep it consistent with the sorted result from iptables-save.
  444. def should=(values)
  445. @should = super(values).sort_by {|sym| sym.to_s}
  446. end
  447. def is_to_s(value)
  448. should_to_s(value)
  449. end
  450. def should_to_s(value)
  451. value = [value] unless value.is_a?(Array)
  452. value.join(',')
  453. end
  454. end
  455. newproperty(:ctstate, :array_matching => :all, :required_features =>
  456. :state_match) do
  457. desc <<-EOS
  458. Matches a packet based on its state in the firewall stateful inspection
  459. table, using the conntrack module. Values can be:
  460. * INVALID
  461. * ESTABLISHED
  462. * NEW
  463. * RELATED
  464. EOS
  465. newvalues(:INVALID,:ESTABLISHED,:NEW,:RELATED)
  466. # States should always be sorted. This normalizes the resource states to
  467. # keep it consistent with the sorted result from iptables-save.
  468. def should=(values)
  469. @should = super(values).sort_by {|sym| sym.to_s}
  470. end
  471. def is_to_s(value)
  472. should_to_s(value)
  473. end
  474. def should_to_s(value)
  475. value = [value] unless value.is_a?(Array)
  476. value.join(',')
  477. end
  478. end
  479. # Connection mark
  480. newproperty(:connmark, :required_features => :mark) do
  481. desc <<-EOS
  482. Match the Netfilter mark value associated with the packet. Accepts either of:
  483. mark/mask or mark. These will be converted to hex if they are not already.
  484. EOS
  485. munge do |value|
  486. int_or_hex = '[a-fA-F0-9x]'
  487. match = value.to_s.match("(#{int_or_hex}+)(/)?(#{int_or_hex}+)?")
  488. mark = @resource.to_hex32(match[1])
  489. # Values that can't be converted to hex.
  490. # Or contain a trailing slash with no mask.
  491. if mark.nil? or (mark and match[2] and match[3].nil?)
  492. raise ArgumentError, "MARK value must be integer or hex between 0 and 0xffffffff"
  493. end
  494. # There should not be a mask on connmark
  495. unless match[3].nil?
  496. raise ArgumentError, "iptables does not support masks on MARK match rules"
  497. end
  498. value = mark
  499. value
  500. end
  501. end
  502. # Connection limiting properties
  503. newproperty(:connlimit_above, :required_features => :connection_limiting) do
  504. desc <<-EOS
  505. Connection limiting value for matched connections above n.
  506. EOS
  507. newvalue(/^\d+$/)
  508. end
  509. newproperty(:connlimit_mask, :required_features => :connection_limiting) do
  510. desc <<-EOS
  511. Connection limiting by subnet mask for matched connections.
  512. IPv4: 0-32
  513. IPv6: 0-128
  514. EOS
  515. newvalue(/^\d+$/)
  516. end
  517. # Hop limiting properties
  518. newproperty(:hop_limit, :required_features => :hop_limiting) do
  519. desc <<-EOS
  520. Hop limiting value for matched packets.
  521. EOS
  522. newvalue(/^\d+$/)
  523. end
  524. # Rate limiting properties
  525. newproperty(:limit, :required_features => :rate_limiting) do
  526. desc <<-EOS
  527. Rate limiting value for matched packets. The format is:
  528. rate/[/second/|/minute|/hour|/day].
  529. Example values are: '50/sec', '40/min', '30/hour', '10/day'."
  530. EOS
  531. end
  532. newproperty(:burst, :required_features => :rate_limiting) do
  533. desc <<-EOS
  534. Rate limiting burst value (per second) before limit checks apply.
  535. EOS
  536. newvalue(/^\d+$/)
  537. end
  538. newproperty(:uid, :required_features => :owner) do
  539. desc <<-EOS
  540. UID or Username owner matching rule. Accepts a string argument
  541. only, as iptables does not accept multiple uid in a single
  542. statement.
  543. EOS
  544. end
  545. newproperty(:gid, :required_features => :owner) do
  546. desc <<-EOS
  547. GID or Group owner matching rule. Accepts a string argument
  548. only, as iptables does not accept multiple gid in a single
  549. statement.
  550. EOS
  551. end
  552. newproperty(:set_mark, :required_features => :mark) do
  553. desc <<-EOS
  554. Set the Netfilter mark value associated with the packet. Accepts either of:
  555. mark/mask or mark. These will be converted to hex if they are not already.
  556. EOS
  557. munge do |value|
  558. int_or_hex = '[a-fA-F0-9x]'
  559. match = value.to_s.match("(#{int_or_hex}+)(/)?(#{int_or_hex}+)?")
  560. mark = @resource.to_hex32(match[1])
  561. # Values that can't be converted to hex.
  562. # Or contain a trailing slash with no mask.
  563. if mark.nil? or (mark and match[2] and match[3].nil?)
  564. raise ArgumentError, "MARK value must be integer or hex between 0 and 0xffffffff"
  565. end
  566. # Old iptables does not support a mask. New iptables will expect one.
  567. iptables_version = Facter.fact('iptables_version').value
  568. mask_required = (iptables_version and Puppet::Util::Package.versioncmp(iptables_version, '1.4.1') >= 0)
  569. if mask_required
  570. if match[3].nil?
  571. value = "#{mark}/0xffffffff"
  572. else
  573. mask = @resource.to_hex32(match[3])
  574. if mask.nil?
  575. raise ArgumentError, "MARK mask must be integer or hex between 0 and 0xffffffff"
  576. end
  577. value = "#{mark}/#{mask}"
  578. end
  579. else
  580. unless match[3].nil?
  581. raise ArgumentError, "iptables version #{iptables_version} does not support masks on MARK rules"
  582. end
  583. value = mark
  584. end
  585. value
  586. end
  587. end
  588. newproperty(:pkttype, :required_features => :pkttype) do
  589. desc <<-EOS
  590. Sets the packet type to match.
  591. EOS
  592. newvalues(:unicast, :broadcast, :multicast)
  593. end
  594. newproperty(:isfragment, :required_features => :isfragment) do
  595. desc <<-EOS
  596. Set to true to match tcp fragments (requires type to be set to tcp)
  597. EOS
  598. newvalues(:true, :false)
  599. end
  600. newproperty(:recent, :required_features => :recent_limiting) do
  601. desc <<-EOS
  602. Enable the recent module. Takes as an argument one of set, update,
  603. rcheck or remove. For example:
  604. # If anyone's appeared on the 'badguy' blacklist within
  605. # the last 60 seconds, drop their traffic, and update the timestamp.
  606. firewall { '100 Drop badguy traffic':
  607. recent => 'update',
  608. rseconds => 60,
  609. rsource => true,
  610. rname => 'badguy',
  611. action => 'DROP',
  612. chain => 'FORWARD',
  613. }
  614. # No-one should be sending us traffic on eth0 from localhost
  615. # Blacklist them
  616. firewall { '101 blacklist strange traffic':
  617. recent => 'set',
  618. rsource => true,
  619. rname => 'badguy',
  620. destination => '127.0.0.0/8',
  621. iniface => 'eth0',
  622. action => 'DROP',
  623. chain => 'FORWARD',
  624. }
  625. EOS
  626. newvalues(:set, :update, :rcheck, :remove)
  627. munge do |value|
  628. value = "--" + value
  629. end
  630. end
  631. newproperty(:rdest, :required_features => :recent_limiting) do
  632. desc <<-EOS
  633. Recent module; add the destination IP address to the list.
  634. Must be boolean true.
  635. EOS
  636. newvalues(:true, :false)
  637. end
  638. newproperty(:rsource, :required_features => :recent_limiting) do
  639. desc <<-EOS
  640. Recent module; add the source IP address to the list.
  641. Must be boolean true.
  642. EOS
  643. newvalues(:true, :false)
  644. end
  645. newproperty(:rname, :required_features => :recent_limiting) do
  646. desc <<-EOS
  647. Recent module; The name of the list. Takes a string argument.
  648. EOS
  649. end
  650. newproperty(:rseconds, :required_features => :recent_limiting) do
  651. desc <<-EOS
  652. Recent module; used in conjunction with one of `recent => 'rcheck'` or
  653. `recent => 'update'`. When used, this will narrow the match to only
  654. happen when the address is in the list and was seen within the last given
  655. number of seconds.
  656. EOS
  657. end
  658. newproperty(:reap, :required_features => :recent_limiting) do
  659. desc <<-EOS
  660. Recent module; can only be used in conjunction with the `rseconds`
  661. attribute. When used, this will cause entries older than 'seconds' to be
  662. purged. Must be boolean true.
  663. EOS
  664. newvalues(:true, :false)
  665. end
  666. newproperty(:rhitcount, :required_features => :recent_limiting) do
  667. desc <<-EOS
  668. Recent module; used in conjunction with `recent => 'update'` or `recent
  669. => 'rcheck'. When used, this will narrow the match to only happen when
  670. the address is in the list and packets had been received greater than or
  671. equal to the given value.
  672. EOS
  673. end
  674. newproperty(:rttl, :required_features => :recent_limiting) do
  675. desc <<-EOS
  676. Recent module; may only be used in conjunction with one of `recent =>
  677. 'rcheck'` or `recent => 'update'`. When used, this will narrow the match
  678. to only happen when the address is in the list and the TTL of the current
  679. packet matches that of the packet which hit the `recent => 'set'` rule.
  680. This may be useful if you have problems with people faking their source
  681. address in order to DoS you via this module by disallowing others access
  682. to your site by sending bogus packets to you. Must be boolean true.
  683. EOS
  684. newvalues(:true, :false)
  685. end
  686. newproperty(:socket, :required_features => :socket) do
  687. desc <<-EOS
  688. If true, matches if an open socket can be found by doing a coket lookup
  689. on the packet.
  690. EOS
  691. newvalues(:true, :false)
  692. end
  693. newproperty(:ishasmorefrags, :required_features => :ishasmorefrags) do
  694. desc <<-EOS
  695. If true, matches if the packet has it's 'more fragments' bit set. ipv6.
  696. EOS
  697. newvalues(:true, :false)
  698. end
  699. newproperty(:islastfrag, :required_features => :islastfrag) do
  700. desc <<-EOS
  701. If true, matches if the packet is the last fragment. ipv6.
  702. EOS
  703. newvalues(:true, :false)
  704. end
  705. newproperty(:isfirstfrag, :required_features => :isfirstfrag) do
  706. desc <<-EOS
  707. If true, matches if the packet is the first fragment.
  708. Sadly cannot be negated. ipv6.
  709. EOS
  710. newvalues(:true, :false)
  711. end
  712. newproperty(:ipsec_policy, :required_features => :ipsec_policy) do
  713. desc <<-EOS
  714. Sets the ipsec policy type
  715. EOS
  716. newvalues(:none, :ipsec)
  717. end
  718. newproperty(:ipsec_dir, :required_features => :ipsec_dir) do
  719. desc <<-EOS
  720. Sets the ipsec policy direction
  721. EOS
  722. newvalues(:in, :out)
  723. end
  724. newproperty(:mask, :required_features => :mask) do
  725. desc <<-EOS
  726. Sets the mask to use when `recent` is enabled.
  727. EOS
  728. end
  729. newparam(:line) do
  730. desc <<-EOS
  731. Read-only property for caching the rule line.
  732. EOS
  733. end
  734. newproperty(:mac_source) do
  735. desc <<-EOS
  736. MAC Source
  737. EOS
  738. newvalues(/^([0-9a-f]{2}[:]){5}([0-9a-f]{2})$/i)
  739. end
  740. autorequire(:firewallchain) do
  741. reqs = []
  742. protocol = nil
  743. case value(:provider)
  744. when :iptables
  745. protocol = "IPv4"
  746. when :ip6tables
  747. protocol = "IPv6"
  748. end
  749. unless protocol.nil?
  750. table = value(:table)
  751. [value(:chain), value(:jump)].each do |chain|
  752. reqs << "#{chain}:#{table}:#{protocol}" unless ( chain.nil? || (['INPUT', 'OUTPUT', 'FORWARD'].include?(chain) && table == :filter) )
  753. end
  754. end
  755. reqs
  756. end
  757. # Classes would be a better abstraction, pending:
  758. # http://projects.puppetlabs.com/issues/19001
  759. autorequire(:package) do
  760. case value(:provider)
  761. when :iptables, :ip6tables
  762. %w{iptables iptables-persistent}
  763. else
  764. []
  765. end
  766. end
  767. validate do
  768. debug("[validate]")
  769. # TODO: this is put here to skip validation if ensure is not set. This
  770. # is because there is a revalidation stage called later where the values
  771. # are not set correctly. I tried tracing it - but have put in this
  772. # workaround instead to skip. Must get to the bottom of this.
  773. if ! value(:ensure)
  774. return
  775. end
  776. # First we make sure the chains and tables are valid combinations
  777. if value(:table).to_s == "filter" &&
  778. value(:chain) =~ /PREROUTING|POSTROUTING/
  779. self.fail "PREROUTING and POSTROUTING cannot be used in table 'filter'"
  780. end
  781. if value(:table).to_s == "nat" && value(:chain) =~ /INPUT|FORWARD/
  782. self.fail "INPUT and FORWARD cannot be used in table 'nat'"
  783. end
  784. if value(:table).to_s == "raw" &&
  785. value(:chain) =~ /INPUT|FORWARD|POSTROUTING/
  786. self.fail "INPUT, FORWARD and POSTROUTING cannot be used in table raw"
  787. end
  788. # Now we analyse the individual properties to make sure they apply to
  789. # the correct combinations.
  790. if value(:iniface)
  791. unless value(:chain).to_s =~ /INPUT|FORWARD|PREROUTING/
  792. self.fail "Parameter iniface only applies to chains " \
  793. "INPUT,FORWARD,PREROUTING"
  794. end
  795. end
  796. if value(:outiface)
  797. unless value(:chain).to_s =~ /OUTPUT|FORWARD|POSTROUTING/
  798. self.fail "Parameter outiface only applies to chains " \
  799. "OUTPUT,FORWARD,POSTROUTING"
  800. end
  801. end
  802. if value(:uid)
  803. unless value(:chain).to_s =~ /OUTPUT|POSTROUTING/
  804. self.fail "Parameter uid only applies to chains " \
  805. "OUTPUT,POSTROUTING"
  806. end
  807. end
  808. if value(:gid)
  809. unless value(:chain).to_s =~ /OUTPUT|POSTROUTING/
  810. self.fail "Parameter gid only applies to chains " \
  811. "OUTPUT,POSTROUTING"
  812. end
  813. end
  814. if value(:set_mark)
  815. unless value(:jump).to_s =~ /MARK/ &&
  816. value(:chain).to_s =~ /PREROUTING|OUTPUT/ &&
  817. value(:table).to_s =~ /mangle/
  818. self.fail "Parameter set_mark only applies to " \
  819. "the PREROUTING or OUTPUT chain of the mangle table and when jump => MARK"
  820. end
  821. end
  822. if value(:dport)
  823. unless value(:proto).to_s =~ /tcp|udp|sctp/
  824. self.fail "[%s] Parameter dport only applies to sctp, tcp and udp " \
  825. "protocols. Current protocol is [%s] and dport is [%s]" %
  826. [value(:name), should(:proto), should(:dport)]
  827. end
  828. end
  829. if value(:jump).to_s == "DNAT"
  830. unless value(:table).to_s =~ /nat/
  831. self.fail "Parameter jump => DNAT only applies to table => nat"
  832. end
  833. unless value(:todest)
  834. self.fail "Parameter jump => DNAT must have todest parameter"
  835. end
  836. end
  837. if value(:jump).to_s == "SNAT"
  838. unless value(:table).to_s =~ /nat/
  839. self.fail "Parameter jump => SNAT only applies to table => nat"
  840. end
  841. unless value(:tosource)
  842. self.fail "Parameter jump => SNAT must have tosource parameter"
  843. end
  844. end
  845. if value(:jump).to_s == "REDIRECT"
  846. unless value(:toports)
  847. self.fail "Parameter jump => REDIRECT missing mandatory toports " \
  848. "parameter"
  849. end
  850. end
  851. if value(:jump).to_s == "MASQUERADE"
  852. unless value(:table).to_s =~ /nat/
  853. self.fail "Parameter jump => MASQUERADE only applies to table => nat"
  854. end
  855. end
  856. if value(:log_prefix) || value(:log_level)
  857. unless value(:jump).to_s == "LOG"
  858. self.fail "Parameter log_prefix and log_level require jump => LOG"
  859. end
  860. end
  861. if value(:burst) && ! value(:limit)
  862. self.fail "burst makes no sense without limit"
  863. end
  864. if value(:action) && value(:jump)
  865. self.fail "Only one of the parameters 'action' and 'jump' can be set"
  866. end
  867. if value(:connlimit_mask) && ! value(:connlimit_above)
  868. self.fail "Parameter 'connlimit_mask' requires 'connlimit_above'"
  869. end
  870. if value(:mask) && ! value(:recent)
  871. self.fail "Mask can only be set if recent is enabled."
  872. end
  873. end
  874. end