Saltstack Official UFW Formula
Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.

224 lines
7.2KB

  1. from salt.exceptions import CommandExecutionError, CommandNotFoundError
  2. import re
  3. import socket
  4. def _unchanged(name, msg):
  5. return {'name': name, 'result': True, 'comment': msg, 'changes': {}}
  6. def _test(name, msg):
  7. return {'name': name, 'result': None, 'comment': msg, 'changes': {}}
  8. def _error(name, msg):
  9. return {'name': name, 'result': False, 'comment': msg, 'changes': {}}
  10. def _changed(name, msg, **changes):
  11. return {'name': name, 'result': True, 'comment': msg, 'changes': changes}
  12. def _resolve(host):
  13. # Commenting out as network from_addr or to_addr could be IPv6 which
  14. # might not start with a number and causes errors with gethostbyname
  15. return host
  16. # let's just see if it starts with a number or a colon, for simplicity
  17. #if re.match(r'^[0-9:]', host):
  18. #return host
  19. #return socket.gethostbyname(host)
  20. def _as_rule(method, app, interface, protocol, from_addr, from_port, to_addr, to_port, comment):
  21. cmd = [method]
  22. if app is not None:
  23. cmd.append("from")
  24. if from_addr is not None:
  25. cmd.append(from_addr)
  26. else:
  27. cmd.append("any")
  28. cmd.append("to")
  29. if to_addr is not None:
  30. cmd.append(to_addr)
  31. else:
  32. cmd.append("any")
  33. cmd.append("app")
  34. cmd.append(app)
  35. elif interface is not None:
  36. cmd.append("in")
  37. cmd.append("on")
  38. cmd.append(interface)
  39. else:
  40. if protocol is not None:
  41. cmd.append("proto")
  42. cmd.append(protocol)
  43. cmd.append("from")
  44. if from_addr is not None:
  45. cmd.append(_resolve(from_addr))
  46. else:
  47. cmd.append("any")
  48. if from_port is not None:
  49. cmd.append("port")
  50. cmd.append(_resolve(from_port))
  51. cmd.append("to")
  52. if to_addr is not None:
  53. cmd.append(to_addr)
  54. else:
  55. cmd.append("any")
  56. if to_port is not None:
  57. cmd.append("port")
  58. cmd.append(to_port)
  59. if comment is not None:
  60. cmd.append("comment")
  61. cmd.append(comment)
  62. real_cmd = ' '.join(cmd)
  63. return real_cmd
  64. def _add_rule(method, name, app=None, interface=None, protocol=None,
  65. from_addr=None, from_port=None, to_addr=None, to_port=None, comment=None):
  66. if app and app.strip('"\' ') == '*':
  67. app = None
  68. if to_port and to_port.strip('"\' ') == '*':
  69. to_port = None
  70. rule = _as_rule(method, app=app, interface=interface, protocol=protocol,
  71. from_addr=from_addr, from_port=from_port, to_addr=to_addr, to_port=to_port, comment=comment)
  72. try:
  73. out = __salt__['ufw.add_rule'](rule)
  74. except (CommandExecutionError, CommandNotFoundError) as e:
  75. if method.startswith('insert 1 deny') and "Invalid position '1'" in e.message:
  76. # This is probably the first rule to be added, so try again without "insert 1"
  77. return _add_rule('deny', name, app, interface, protocol, from_addr, from_port, to_addr, to_port, comment)
  78. return _error(name, e.message)
  79. adds = False
  80. inserts = False
  81. updates = False
  82. for line in out.split('\n'):
  83. if re.match('^Skipping', line):
  84. return _unchanged(name, "{0} is already configured".format(name))
  85. break
  86. if re.match('^Rule(s)? added', line):
  87. adds = True
  88. break
  89. if re.match('^Rule(s)? inserted', line):
  90. inserts = True
  91. break
  92. if re.match('^Rule(s)? updated', line):
  93. updates = True
  94. break
  95. if __opts__['test']:
  96. return _test(name, "{0} would have been configured".format(name))
  97. break
  98. if method.startswith('insert 1 deny') and "Invalid position '1'" in line:
  99. # This is probably the first rule to be added, so try again without "insert 1"
  100. return _add_rule('deny', name, app, interface, protocol, from_addr, from_port, to_addr, to_port, comment)
  101. return _error(name, line)
  102. if adds:
  103. return _changed(name, "{0} added".format(name), rule=rule)
  104. elif inserts:
  105. return _changed(name, "{0} inserted".format(name), rule=rule)
  106. elif updates:
  107. return _changed(name, "{0} updated".format(name), rule=rule)
  108. else:
  109. return _unchanged(name, "{0} was already configured".format(name))
  110. def enabled(name, **kwargs):
  111. if __salt__['ufw.is_enabled']():
  112. return _unchanged(name, "UFW is already enabled")
  113. try:
  114. __salt__['ufw.set_enabled'](True)
  115. except (CommandExecutionError, CommandNotFoundError) as e:
  116. return _error(name, e.message)
  117. if __opts__['test']:
  118. return _test(name, "UFW would have been enabled")
  119. else:
  120. return _changed(name, "UFW is enabled", enabled=True)
  121. def default_incoming(name, default):
  122. rule = "default {0} incoming".format(default)
  123. if __opts__['test']:
  124. return _test(name, "{0}: {1}".format(name, rule))
  125. current = __salt__['ufw.get_default_incoming']()
  126. if default != current:
  127. try:
  128. out = __salt__['ufw.add_rule'](rule)
  129. except (CommandExecutionError, CommandNotFoundError) as e:
  130. return _error(name, e.message)
  131. for line in out.split('\n'):
  132. if line.startswith("Default incoming policy changed to"):
  133. return _changed(name, "{0} set to {1}".format(name, default), rule=rule)
  134. return _error(name, line)
  135. return _unchanged(name, "{0} was already set to {1}".format(name, default))
  136. def default_outgoing(name, default):
  137. rule = "default {0} outgoing".format(default)
  138. if __opts__['test']:
  139. return _test(name, "{0}: {1}".format(name, rule))
  140. current = __salt__['ufw.get_default_outgoing']()
  141. if default != current:
  142. try:
  143. out = __salt__['ufw.add_rule'](rule)
  144. except (CommandExecutionError, CommandNotFoundError) as e:
  145. return _error(name, e.message)
  146. for line in out.split('\n'):
  147. if line.startswith("Default outgoing policy changed to"):
  148. return _changed(name, "{0} set to {1}".format(name, default), rule=rule)
  149. return _error(name, line)
  150. return _unchanged(name, "{0} was already set to {1}".format(name, default))
  151. def deny(name, app=None, interface=None, protocol=None,
  152. from_addr=None, from_port=None, to_addr=None, to_port=None, comment=None):
  153. return _add_rule('insert 1 deny', name, app, interface, protocol, from_addr, from_port, to_addr, to_port, comment)
  154. def limit(name, app=None, interface=None, protocol=None,
  155. from_addr=None, from_port=None, to_addr=None, to_port=None, comment=None):
  156. return _add_rule('limit', name, app, interface, protocol, from_addr, from_port, to_addr, to_port, comment)
  157. def allow(name, app=None, interface=None, protocol=None,
  158. from_addr=None, from_port=None, to_addr=None, to_port=None, comment=None):
  159. return _add_rule('allow', name, app, interface, protocol, from_addr, from_port, to_addr, to_port, comment)
  160. def allowed(name, app=None, interface=None, protocol=None,
  161. from_addr=None, from_port=None, to_addr=None, to_port=None, comment=None):
  162. """
  163. allow() is aliased to allowed() to maintain backwards compatibility.
  164. """
  165. return allow(name, app, interface, protocol, from_addr, from_port, to_addr, to_port, comment)