main.py 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. import subprocess, os, re, argparse
  2. from flask import Flask, render_template, redirect, request, url_for
  3. BANDWITH_UNITS = [
  4. "bit", # Bits per second
  5. "kbit", # Kilobits per second
  6. "mbit", # Megabits per second
  7. "gbit", # Gigabits per second
  8. "tbit", # Terabits per second
  9. "bps", # Bytes per second
  10. "kbps", # Kilobytes per second
  11. "mbps", # Megabytes per second
  12. "gbps", # Gigabytes per second
  13. "tbps" # Terabytes per second
  14. ]
  15. STANDARD_UNIT = "mbit"
  16. app = Flask(__name__)
  17. pattern = None
  18. dev_list = None
  19. def parse_arguments():
  20. parser = argparse.ArgumentParser(description='TC web GUI')
  21. parser.add_argument('--ip', type=str, required=False,
  22. help='The IP where the server is listening')
  23. parser.add_argument('--port', type=int, required=False,
  24. help='The port where the server is listening')
  25. parser.add_argument('--dev', type=str, nargs='*', required=False,
  26. help='The interfaces to restrict to')
  27. parser.add_argument('--regex',type=str, required=False,
  28. help='A regex to match interfaces')
  29. parser.add_argument('--debug',action='store_true',
  30. help='Run Flask in debug mode')
  31. return parser.parse_args()
  32. @app.route("/")
  33. def main():
  34. rules = get_active_rules()
  35. return render_template('main.html', rules=rules, units=BANDWITH_UNITS,
  36. standard_unit=STANDARD_UNIT)
  37. @app.route('/new_rule/<interface>', methods=['POST'])
  38. def new_rule(interface):
  39. delay = request.form['Delay']
  40. delay_variance = request.form['DelayVariance']
  41. loss = request.form['Loss']
  42. loss_correlation = request.form['LossCorrelation']
  43. duplicate = request.form['Duplicate']
  44. reorder = request.form['Reorder']
  45. reorder_correlation = request.form['ReorderCorrelation']
  46. corrupt = request.form['Corrupt']
  47. rate = request.form['Rate']
  48. rate_unit = request.form['rate_unit']
  49. # remove old setup
  50. command = 'tc qdisc del dev %s root netem' % interface
  51. command = command.split(' ')
  52. proc = subprocess.Popen(command)
  53. proc.wait()
  54. # apply new setup
  55. command = 'tc qdisc add dev %s root netem' % interface
  56. if rate != '':
  57. command += ' rate %s%s' % (rate, rate_unit)
  58. if delay != '':
  59. command += ' delay %sms' % delay
  60. if delay_variance != '':
  61. command += ' %sms' % delay_variance
  62. if loss != '':
  63. command += ' loss %s%%' % loss
  64. if loss_correlation != '':
  65. command += ' %s%%' % loss_correlation
  66. if duplicate != '':
  67. command += ' duplicate %s%%' % duplicate
  68. if reorder != '':
  69. command += ' reorder %s%%' % reorder
  70. if reorder_correlation != '':
  71. command += ' %s%%' % reorder_correlation
  72. if corrupt != '':
  73. command += ' corrupt %s%%' % corrupt
  74. print(command)
  75. command = command.split(' ')
  76. proc = subprocess.Popen(command)
  77. proc.wait()
  78. return redirect(url_for('main'))
  79. @app.route('/remove_rule/<interface>', methods=['POST'])
  80. def remove_rule(interface):
  81. # remove old setup
  82. command = 'tc qdisc del dev %s root netem' % interface
  83. command = command.split(' ')
  84. proc = subprocess.Popen(command)
  85. proc.wait()
  86. return redirect(url_for('main'))
  87. def get_active_rules():
  88. proc = subprocess.Popen(['tc', 'qdisc'], stdout=subprocess.PIPE)
  89. output = proc.communicate()[0].decode()
  90. lines = output.split('\n')[:-1]
  91. rules = []
  92. dev = set()
  93. for line in lines:
  94. arguments = line.split()
  95. rule = parse_rule(arguments)
  96. if rule['name'] and rule['name'] not in dev:
  97. rules.append(rule)
  98. dev.add(rule['name'])
  99. return rules
  100. def parse_rule(split_rule):
  101. rule = {'name': None,
  102. 'rate': None,
  103. 'delay': None,
  104. 'delayVariance': None,
  105. 'loss': None,
  106. 'lossCorrelation': None,
  107. 'duplicate': None,
  108. 'reorder': None,
  109. 'reorderCorrelation': None,
  110. 'corrupt': None}
  111. i = 0
  112. for argument in split_rule:
  113. if argument == 'dev':
  114. # Both regex pattern and dev name can be given
  115. # An interface could match the pattern and/or
  116. # be in the interface list
  117. if pattern is None and dev_list is None:
  118. rule['name'] = split_rule[i + 1]
  119. if pattern:
  120. if pattern.match(split_rule[i + 1]) :
  121. rule['name'] = split_rule[i + 1]
  122. if dev_list:
  123. if split_rule[i + 1] in dev_list:
  124. rule['name'] = split_rule[i + 1]
  125. elif argument == 'rate':
  126. rule['rate'] = split_rule[i + 1].split('Mbit')[0]
  127. elif argument == 'delay':
  128. rule['delay'] = split_rule[i + 1]
  129. if len(split_rule) > (i + 2) and 'ms' in split_rule[i + 2]:
  130. rule['delayVariance'] = split_rule[i + 2]
  131. elif argument == 'loss':
  132. rule['loss'] = split_rule[i + 1]
  133. if len(split_rule) > (i + 2) and '%' in split_rule[i + 2]:
  134. rule['lossCorrelation'] = split_rule[i + 2]
  135. elif argument == 'duplicate':
  136. rule['duplicate'] = split_rule[i + 1]
  137. elif argument == 'reorder':
  138. rule['reorder'] = split_rule[i + 1]
  139. if len(split_rule) > (i + 2) and '%' in split_rule[i + 2]:
  140. rule['reorderCorrelation'] = split_rule[i + 2]
  141. elif argument == 'corrupt':
  142. rule['corrupt'] = split_rule[i + 1]
  143. i += 1
  144. return rule
  145. if __name__ == "__main__":
  146. if os.geteuid() != 0:
  147. print("You need to have root privileges to run this script.\nPlease try again, this time using 'sudo'. Exiting.")
  148. exit(1)
  149. args = parse_arguments()
  150. if args.regex:
  151. pattern = re.compile(args.regex)
  152. if args.dev:
  153. dev_list = args.dev
  154. app_args = {}
  155. if args.ip:
  156. app_args['host'] = args.ip
  157. if args.port:
  158. app_args['port'] = args.port
  159. if not args.debug:
  160. app_args['debug'] = False
  161. app.debug = True
  162. app.run(**app_args)