Saltstack Official IPTables Formula
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

232 lines
6.3KB

  1. # -*- coding: utf-8 -*-
  2. from os import chmod,remove
  3. from time import time
  4. from subprocess import Popen,PIPE
  5. def get_tables(family="ipv4"):
  6. ''' List iptables tables
  7. :param family: iptables ip family version. type: str
  8. '''
  9. if family == "ipv4":
  10. cmd = 'iptables-save'
  11. elif family == "ipv6":
  12. cmd = 'ip6tables-save'
  13. else:
  14. return "Invalid ip family specified. Use either ipv4 or ipv6"
  15. tables = []
  16. try:
  17. tables_list = Popen(cmd, shell=True, stdout=PIPE)
  18. while True:
  19. line = tables_list.stdout.readline().decode()
  20. if line != '':
  21. if line[0] == "*":
  22. tables.append(line.rstrip()[1:])
  23. else:
  24. break
  25. except:
  26. return "Error getting list of tables"
  27. return tables
  28. def get_chains(family="ipv4", table="filter"):
  29. ''' List iptables chains
  30. :param family: iptables ip family version. type: str
  31. :param table: Lookup chains for this table. type: str
  32. '''
  33. if family == "ipv4":
  34. cmd = 'iptables-save'
  35. elif family == "ipv6":
  36. cmd = 'ip6tables-save'
  37. else:
  38. return "Invalid ip family specified. Use either ipv4 or ipv6"
  39. cmd += ' -t ' + table
  40. chains = []
  41. try:
  42. chains_list = Popen(cmd, shell=True, stdout=PIPE)
  43. while True:
  44. line = chains_list.stdout.readline()
  45. if line != '':
  46. if line[0] == ":":
  47. chains.append(line.rstrip()[1:].split(' ')[0])
  48. else:
  49. break
  50. except:
  51. return "Error getting list of chains"
  52. return chains
  53. def get_structure(family="ipv4"):
  54. ''' Get structure of all chains in all tables
  55. :param family: iptables ip family version. type: str
  56. '''
  57. if family == "ipv4":
  58. cmd = 'iptables-save'
  59. elif family == "ipv6":
  60. cmd = 'ip6tables-save'
  61. else:
  62. return "Invalid ip family specified. Use either ipv4 or ipv6"
  63. tables = []
  64. tables_list = Popen(cmd, shell=True, stdout=PIPE)
  65. while True:
  66. line = tables_list.stdout.readline()
  67. if line != '':
  68. line = line.rstrip().lstrip()
  69. if line[0] == "*":
  70. elem = {}
  71. table_name = line[1:].split(' ')[0]
  72. elem[table_name] = []
  73. if line[0] == ":":
  74. elem[table_name].append(line[1:].split(' ')[0])
  75. if line == "COMMIT":
  76. tables.append(elem)
  77. else:
  78. break
  79. return tables
  80. def run_script(script):
  81. ''' Execute local script
  82. :param script: script to be executed, storad localy: str
  83. '''
  84. chmod(script, 0o700)
  85. process = Popen([script],stdout=PIPE,stderr=PIPE)
  86. process.wait()
  87. code = process.returncode
  88. remove(script)
  89. return code
  90. def flush_all(family="ipv4"):
  91. ''' Flush all chains in all tables
  92. :param family: iptables ip family version. type: str
  93. '''
  94. if family == "ipv4":
  95. cmd = 'iptables'
  96. rmmod = 'iptable_'
  97. elif family == "ipv6":
  98. cmd = 'ip6tables'
  99. rmmod = 'ip6table_'
  100. else:
  101. return "Invalid ip family specified. Use either ipv4 or ipv6"
  102. tables = get_structure(family)
  103. f_name = '/tmp/' + cmd + '-flush-' + str(time()).split('.')[0] + '.sh'
  104. with open(f_name, 'w') as f:
  105. f.write('#!/bin/sh\n')
  106. for table in tables:
  107. for var in enumerate(table):
  108. t_name = var[1]
  109. for chain in table[t_name]:
  110. f.write(cmd + ' -t ' + t_name + " -F " + chain + '\n')
  111. if chain not in ['INPUT','FORWARD','OUTPUT','PREROUTING','POSTROUTING']:
  112. f.write(cmd + ' -t ' + t_name + " -X " + chain + '\n')
  113. f.write('rmmod ' + rmmod + t_name + '\n')
  114. return run_script(f_name)
  115. def set_policy_all(family="ipv4", policy="ACCEPT"):
  116. ''' Set policy for all chains in all tables
  117. :param family: iptables ip family version. type: str
  118. :param policy: iptables chain policy. type: str
  119. '''
  120. if family == "ipv4":
  121. cmd = 'iptables'
  122. elif family == "ipv6":
  123. cmd = 'ip6tables'
  124. else:
  125. return "Invalid ip family specified. Use either ipv4 or ipv6"
  126. tables = get_structure(family)
  127. f_name = '/tmp/' + cmd + '-policy-' + str(time()).split('.')[0] + '.sh'
  128. with open(f_name, 'w') as f:
  129. f.write('#!/bin/sh\n')
  130. for table in tables:
  131. for var in enumerate(table):
  132. t_name = var[1]
  133. for chain in table[t_name]:
  134. f.write(cmd + ' -t ' + t_name + " -P " + chain + ' ' + policy + '\n')
  135. return run_script(f_name)
  136. def remove_stale_tables(config_file, family="ipv4"):
  137. ''' Remove tables which are not in config file
  138. to prevet flushing all the tables
  139. :param family: iptables ip family version. type: str
  140. :param config_file: iptables rules persistent config file. type: str
  141. '''
  142. if family == "ipv4":
  143. cmd = 'iptables'
  144. rmmod = 'iptable_'
  145. elif family == "ipv6":
  146. cmd = 'ip6tables'
  147. rmmod = 'ip6table_'
  148. else:
  149. return "Invalid ip family specified. Use either ipv4 or ipv6"
  150. runtime_tables = get_tables(family)
  151. config_tables = []
  152. for line in open(config_file, 'r'):
  153. if line != '':
  154. if line[0] == "*":
  155. config_tables.append(line.rstrip()[1:])
  156. runtime_tables.sort()
  157. config_tables.sort()
  158. diff = list(set(runtime_tables) - set(config_tables))
  159. if diff != []:
  160. tables = get_structure(family)
  161. f_name = '/tmp/' + cmd + '-flush-' + str(time()).split('.')[0] + '.sh'
  162. with open(f_name, 'w') as f:
  163. f.write('#!/bin/sh\n')
  164. for table in tables:
  165. for var in enumerate(table):
  166. t_name = var[1]
  167. if t_name in diff:
  168. for chain in table[t_name]:
  169. f.write(cmd + ' -t ' + t_name + " -F " + chain + '\n')
  170. if chain not in ['INPUT','FORWARD','OUTPUT','PREROUTING','POSTROUTING']:
  171. f.write(cmd + ' -t ' + t_name + " -X " + chain + '\n')
  172. f.write('rmmod ' + rmmod + t_name + '\n')
  173. return run_script(f_name)
  174. else:
  175. return