The main Bubble source repository. Contains the Bubble API server, the web UI, documentation and utilities. https://getbubblenow.com
Du kannst nicht mehr als 25 Themen auswählen Themen müssen entweder mit einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.
 
 
 
 

104 Zeilen
4.7 KiB

  1. #
  2. # Copyright (c) 2020 Bubble, Inc. All rights reserved. For personal (non-commercial) use, see license: https://bubblev.com/bubble-license/
  3. #
  4. # Parts of this are borrowed from tls_passthrough.py in the mitmproxy project. The mitmproxy license is reprinted here:
  5. #
  6. # Copyright (c) 2013, Aldo Cortesi. All rights reserved.
  7. #
  8. # Permission is hereby granted, free of charge, to any person obtaining a copy
  9. # of this software and associated documentation files (the "Software"), to deal
  10. # in the Software without restriction, including without limitation the rights
  11. # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  12. # copies of the Software, and to permit persons to whom the Software is
  13. # furnished to do so, subject to the following conditions:
  14. #
  15. # The above copyright notice and this permission notice shall be included in
  16. # all copies or substantial portions of the Software.
  17. #
  18. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  19. # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  20. # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  21. # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  22. # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  23. # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  24. # SOFTWARE.
  25. #
  26. from mitmproxy.proxy.protocol import TlsLayer, RawTCPLayer
  27. from mitmproxy.exceptions import TlsProtocolException
  28. from bubble_api import bubble_log, bubble_passthru
  29. import redis
  30. REDIS_DNS_PREFIX = 'bubble_dns_'
  31. REDIS_PASSTHRU_PREFIX = 'bubble_passthru_'
  32. REDIS_PASSTHRU_DURATION = 60 * 10
  33. REDIS = redis.Redis(host='127.0.0.1', port=6379, db=0)
  34. TLS_FAILURE_HISTORY = {}
  35. def passthru_cache_prefix(client_addr, server_addr):
  36. return REDIS_PASSTHRU_PREFIX + client_addr + '_' + server_addr
  37. class TlsFeedback(TlsLayer):
  38. """
  39. Monkey-patch _establish_tls_with_client to get feedback if TLS could be established
  40. successfully on the client connection (which may fail due to cert pinning).
  41. """
  42. def _establish_tls_with_client(self):
  43. client_address = self.client_conn.address[0]
  44. server_address = self.server_conn.address[0]
  45. try:
  46. super(TlsFeedback, self)._establish_tls_with_client()
  47. except TlsProtocolException as e:
  48. bubble_log('_establish_tls_with_client: TLS error for '+repr(server_address)+', enabling passthru')
  49. cache_key = passthru_cache_prefix(client_address, server_address)
  50. REDIS.delete(cache_key)
  51. TLS_FAILURE_HISTORY[cache_key] = True
  52. raise e
  53. def check_bubble_passthru(remote_addr, addr):
  54. fqdn = REDIS.get(REDIS_DNS_PREFIX + addr)
  55. if fqdn is None or len(fqdn) == 0:
  56. bubble_log('check_bubble_passthru: no FQDN found for addr '+repr(addr)+', checking raw addr')
  57. fqdn = b''
  58. fqdn = fqdn.decode()
  59. if bubble_passthru(remote_addr, addr, fqdn):
  60. bubble_log('check_bubble_passthru: bubble_passthru returned True for FQDN/addr '+repr(fqdn)+'/'+repr(addr)+', returning True')
  61. return True
  62. bubble_log('check_bubble_passthru: bubble_passthru returned False for FQDN/addr '+repr(fqdn)+'/'+repr(addr)+', returning False')
  63. return False
  64. def should_passthru(remote_addr, addr):
  65. bubble_log('should_passthru: examining addr='+repr(addr))
  66. cache_key = passthru_cache_prefix(remote_addr, addr)
  67. if cache_key in TLS_FAILURE_HISTORY and TLS_FAILURE_HISTORY[cache_key]:
  68. bubble_log('should_passthru: previous failure, returning True')
  69. return True
  70. else:
  71. bubble_log('should_passthru: no failure (failures='+repr(TLS_FAILURE_HISTORY)+'), returning True')
  72. passthru_string = REDIS.get(cache_key)
  73. if passthru_string is None or len(passthru_string) == 0:
  74. passthru = check_bubble_passthru(remote_addr, addr)
  75. REDIS.set(cache_key, str(passthru), nx=True, ex=REDIS_PASSTHRU_DURATION)
  76. passthru_string = str(passthru)
  77. else:
  78. bubble_log('should_passthru: found cached value, passthru_string='+str(passthru_string))
  79. passthru_string = passthru_string.decode()
  80. bubble_log('should_passthru: returning '+str(passthru_string == 'True'))
  81. return passthru_string == 'True'
  82. def next_layer(next_layer):
  83. if isinstance(next_layer, TlsLayer) and next_layer._client_tls:
  84. client_address = next_layer.client_conn.address[0]
  85. server_address = next_layer.server_conn.address[0]
  86. if should_passthru(client_address, server_address):
  87. bubble_log('next_layer: TLS passthru for ' + repr(next_layer.server_conn.address))
  88. next_layer_replacement = RawTCPLayer(next_layer.ctx, ignore=True)
  89. next_layer.reply.send(next_layer_replacement)
  90. else:
  91. next_layer.__class__ = TlsFeedback