OLD | NEW |
1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
2 # Copyright 2010 Google Inc. All Rights Reserved. | 2 # Copyright 2010 Google Inc. All Rights Reserved. |
3 # | 3 # |
4 # Licensed under the Apache License, Version 2.0 (the "License"); | 4 # Licensed under the Apache License, Version 2.0 (the "License"); |
5 # you may not use this file except in compliance with the License. | 5 # you may not use this file except in compliance with the License. |
6 # You may obtain a copy of the License at | 6 # You may obtain a copy of the License at |
7 # | 7 # |
8 # http://www.apache.org/licenses/LICENSE-2.0 | 8 # http://www.apache.org/licenses/LICENSE-2.0 |
9 # | 9 # |
10 # Unless required by applicable law or agreed to in writing, software | 10 # Unless required by applicable law or agreed to in writing, software |
(...skipping 25 matching lines...) Expand all Loading... |
36 $ sudo ./replay.py --up 128KByte/s --down 4Mbit/s --delay_ms=100 archive.wpr | 36 $ sudo ./replay.py --up 128KByte/s --down 4Mbit/s --delay_ms=100 archive.wpr |
37 | 37 |
38 # 1% packet loss rate | 38 # 1% packet loss rate |
39 $ sudo ./replay.py --packet_loss_rate=0.01 archive.wpr | 39 $ sudo ./replay.py --packet_loss_rate=0.01 archive.wpr |
40 """ | 40 """ |
41 | 41 |
42 import json | 42 import json |
43 import logging | 43 import logging |
44 import optparse | 44 import optparse |
45 import os | 45 import os |
| 46 import socket |
46 import sys | 47 import sys |
47 import traceback | 48 import traceback |
48 | 49 |
49 import cachemissarchive | 50 import cachemissarchive |
50 import customhandlers | 51 import customhandlers |
51 import dnsproxy | 52 import dnsproxy |
52 import httparchive | 53 import httparchive |
53 import httpclient | 54 import httpclient |
54 import httpproxy | 55 import httpproxy |
55 import platformsettings | 56 import platformsettings |
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
141 httpproxy.HttpsProxyServer, | 142 httpproxy.HttpsProxyServer, |
142 archive_fetch, custom_handlers, options.certfile, | 143 archive_fetch, custom_handlers, options.certfile, |
143 host=host, port=options.ssl_port, **options.shaping_http) | 144 host=host, port=options.ssl_port, **options.shaping_http) |
144 | 145 |
145 | 146 |
146 def AddTrafficShaper(server_manager, options, host): | 147 def AddTrafficShaper(server_manager, options, host): |
147 if options.shaping_dummynet: | 148 if options.shaping_dummynet: |
148 ssl_port = options.ssl_shaping_port if options.ssl else None | 149 ssl_port = options.ssl_shaping_port if options.ssl else None |
149 kwargs = dict( | 150 kwargs = dict( |
150 host=host, port=options.shaping_port, ssl_port=ssl_port, | 151 host=host, port=options.shaping_port, ssl_port=ssl_port, |
151 use_loopback=not options.server_mode, **options.shaping_dummynet) | 152 use_loopback=not options.server_mode and host == '127.0.0.1', |
| 153 **options.shaping_dummynet) |
152 if not options.dns_forwarding: | 154 if not options.dns_forwarding: |
153 kwargs['dns_port'] = None | 155 kwargs['dns_port'] = None |
154 server_manager.Append(trafficshaper.TrafficShaper, **kwargs) | 156 server_manager.Append(trafficshaper.TrafficShaper, **kwargs) |
155 | 157 |
156 | 158 |
157 class OptionsWrapper(object): | 159 class OptionsWrapper(object): |
158 """Add checks, updates, and methods to option values. | 160 """Add checks, updates, and methods to option values. |
159 | 161 |
160 Example: | 162 Example: |
161 options, args = option_parser.parse_args() | 163 options, args = option_parser.parse_args() |
(...skipping 21 matching lines...) Expand all Loading... |
183 ) | 185 ) |
184 NET_CHOICES = [key for key, values in _NET_CONFIGS] | 186 NET_CHOICES = [key for key, values in _NET_CONFIGS] |
185 | 187 |
186 def __init__(self, options, parser): | 188 def __init__(self, options, parser): |
187 self._options = options | 189 self._options = options |
188 self._parser = parser | 190 self._parser = parser |
189 self._nondefaults = set([ | 191 self._nondefaults = set([ |
190 name for name, value in parser.defaults.items() | 192 name for name, value in parser.defaults.items() |
191 if getattr(options, name) != value]) | 193 if getattr(options, name) != value]) |
192 self._CheckConflicts() | 194 self._CheckConflicts() |
| 195 self._CheckValidIp('host') |
193 self._MassageValues() | 196 self._MassageValues() |
194 | 197 |
195 def _CheckConflicts(self): | 198 def _CheckConflicts(self): |
196 """Give an error if mutually exclusive options are used.""" | 199 """Give an error if mutually exclusive options are used.""" |
197 for option, bad_options in self._CONFLICTING_OPTIONS: | 200 for option, bad_options in self._CONFLICTING_OPTIONS: |
198 if option in self._nondefaults: | 201 if option in self._nondefaults: |
199 for bad_option in bad_options: | 202 for bad_option in bad_options: |
200 if bad_option in self._nondefaults: | 203 if bad_option in self._nondefaults: |
201 self._parser.error('Option --%s cannot be used with --%s.' % | 204 self._parser.error('Option --%s cannot be used with --%s.' % |
202 (bad_option, option)) | 205 (bad_option, option)) |
203 | 206 |
| 207 def _CheckValidIp(self, name): |
| 208 """Give an error if option |name| is not a valid IPv4 address.""" |
| 209 value = getattr(self._options, name) |
| 210 if value: |
| 211 try: |
| 212 socket.inet_aton(value) |
| 213 except: |
| 214 self._parser.error('Option --%s must be a valid IPv4 address.' % name) |
| 215 |
204 def _ShapingKeywordArgs(self, shaping_key): | 216 def _ShapingKeywordArgs(self, shaping_key): |
205 """Return the shaping keyword args for |shaping_key|. | 217 """Return the shaping keyword args for |shaping_key|. |
206 | 218 |
207 Args: | 219 Args: |
208 shaping_key: one of 'dummynet', 'dns', 'http'. | 220 shaping_key: one of 'dummynet', 'dns', 'http'. |
209 Returns: | 221 Returns: |
210 {} # if shaping_key does not apply, or options have default values. | 222 {} # if shaping_key does not apply, or options have default values. |
211 {k: v, ...} | 223 {k: v, ...} |
212 """ | 224 """ |
213 kwargs = {} | 225 kwargs = {} |
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
279 'replay will load and append entries to archive file', | 291 'replay will load and append entries to archive file', |
280 options.cache_miss_file) | 292 options.cache_miss_file) |
281 cache_misses = cachemissarchive.CacheMissArchive.Load( | 293 cache_misses = cachemissarchive.CacheMissArchive.Load( |
282 options.cache_miss_file) | 294 options.cache_miss_file) |
283 else: | 295 else: |
284 cache_misses = cachemissarchive.CacheMissArchive( | 296 cache_misses = cachemissarchive.CacheMissArchive( |
285 options.cache_miss_file) | 297 options.cache_miss_file) |
286 if options.server: | 298 if options.server: |
287 AddDnsForward(server_manager, options.server) | 299 AddDnsForward(server_manager, options.server) |
288 else: | 300 else: |
289 host = platformsettings.get_server_ip_address(options.server_mode) | 301 host = options.host |
| 302 if not host: |
| 303 host = platformsettings.get_server_ip_address(options.server_mode) |
290 real_dns_lookup = dnsproxy.RealDnsLookup( | 304 real_dns_lookup = dnsproxy.RealDnsLookup( |
291 name_servers=[platformsettings.get_original_primary_nameserver()]) | 305 name_servers=[platformsettings.get_original_primary_nameserver()]) |
292 if options.record: | 306 if options.record: |
293 httparchive.HttpArchive.AssertWritable(replay_filename) | 307 httparchive.HttpArchive.AssertWritable(replay_filename) |
294 if options.append and os.path.exists(replay_filename): | 308 if options.append and os.path.exists(replay_filename): |
295 http_archive = httparchive.HttpArchive.Load(replay_filename) | 309 http_archive = httparchive.HttpArchive.Load(replay_filename) |
296 logging.info('Appending to %s (loaded %d existing responses)', | 310 logging.info('Appending to %s (loaded %d existing responses)', |
297 replay_filename, len(http_archive)) | 311 replay_filename, len(http_archive)) |
298 else: | 312 else: |
299 http_archive = httparchive.HttpArchive() | 313 http_archive = httparchive.HttpArchive() |
300 else: | 314 else: |
301 http_archive = httparchive.HttpArchive.Load(replay_filename) | 315 http_archive = httparchive.HttpArchive.Load(replay_filename) |
302 logging.info('Loaded %d responses from %s', | 316 logging.info('Loaded %d responses from %s', |
303 len(http_archive), replay_filename) | 317 len(http_archive), replay_filename) |
304 server_manager.AppendRecordCallback(real_dns_lookup.ClearCache) | 318 server_manager.AppendRecordCallback(real_dns_lookup.ClearCache) |
305 server_manager.AppendRecordCallback(http_archive.clear) | 319 server_manager.AppendRecordCallback(http_archive.clear) |
306 | 320 |
307 if options.dns_forwarding: | 321 if options.dns_forwarding: |
308 if not options.server_mode: | 322 if not options.server_mode and host == '127.0.0.1': |
309 AddDnsForward(server_manager, host) | 323 AddDnsForward(server_manager, host) |
310 AddDnsProxy(server_manager, options, host, real_dns_lookup, http_archive) | 324 AddDnsProxy(server_manager, options, host, real_dns_lookup, http_archive) |
311 if options.ssl and options.certfile is None: | 325 if options.ssl and options.certfile is None: |
312 options.certfile = os.path.join(os.path.dirname(__file__), 'wpr_cert.pem') | 326 options.certfile = os.path.join(os.path.dirname(__file__), 'wpr_cert.pem') |
313 http_proxy_address = platformsettings.get_httpproxy_ip_address( | 327 http_proxy_address = options.host |
314 options.server_mode) | 328 if not http_proxy_address: |
| 329 http_proxy_address = platformsettings.get_httpproxy_ip_address( |
| 330 options.server_mode) |
315 AddWebProxy(server_manager, options, http_proxy_address, real_dns_lookup, | 331 AddWebProxy(server_manager, options, http_proxy_address, real_dns_lookup, |
316 http_archive, cache_misses) | 332 http_archive, cache_misses) |
317 AddTrafficShaper(server_manager, options, host) | 333 AddTrafficShaper(server_manager, options, host) |
318 | 334 |
319 exit_status = 0 | 335 exit_status = 0 |
320 try: | 336 try: |
321 server_manager.Run() | 337 server_manager.Run() |
322 except KeyboardInterrupt: | 338 except KeyboardInterrupt: |
323 logging.info('Shutting down.') | 339 logging.info('Shutting down.') |
324 except (dnsproxy.DnsProxyException, | 340 except (dnsproxy.DnsProxyException, |
(...skipping 137 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
462 dest='dns_private_passthrough', | 478 dest='dns_private_passthrough', |
463 help='Don\'t forward DNS requests that resolve to private network ' | 479 help='Don\'t forward DNS requests that resolve to private network ' |
464 'addresses. CAUTION: With this option important services like ' | 480 'addresses. CAUTION: With this option important services like ' |
465 'Kerberos will resolve to the HTTP proxy address.') | 481 'Kerberos will resolve to the HTTP proxy address.') |
466 harness_group.add_option('-x', '--no-dns_forwarding', default=True, | 482 harness_group.add_option('-x', '--no-dns_forwarding', default=True, |
467 action='store_false', | 483 action='store_false', |
468 dest='dns_forwarding', | 484 dest='dns_forwarding', |
469 help='Don\'t forward DNS requests to the local replay server. ' | 485 help='Don\'t forward DNS requests to the local replay server. ' |
470 'CAUTION: With this option an external mechanism must be used to ' | 486 'CAUTION: With this option an external mechanism must be used to ' |
471 'forward traffic to the replay server.') | 487 'forward traffic to the replay server.') |
| 488 harness_group.add_option('--host', default=None, |
| 489 action='store', |
| 490 type='str', |
| 491 help='The IP address to bind all servers to. Defaults to 0.0.0.0 or ' |
| 492 '127.0.0.1, depending on --server_mode and platform.') |
472 harness_group.add_option('-o', '--port', default=80, | 493 harness_group.add_option('-o', '--port', default=80, |
473 action='store', | 494 action='store', |
474 type='int', | 495 type='int', |
475 help='Port number to listen on.') | 496 help='Port number to listen on.') |
476 harness_group.add_option('--ssl_port', default=443, | 497 harness_group.add_option('--ssl_port', default=443, |
477 action='store', | 498 action='store', |
478 type='int', | 499 type='int', |
479 help='SSL port number to listen on.') | 500 help='SSL port number to listen on.') |
480 harness_group.add_option('--shaping_port', default=None, | 501 harness_group.add_option('--shaping_port', default=None, |
481 action='store', | 502 action='store', |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
513 elif len(args) != 1: | 534 elif len(args) != 1: |
514 option_parser.error('Must specify a replay_file') | 535 option_parser.error('Must specify a replay_file') |
515 else: | 536 else: |
516 replay_filename = args[0] | 537 replay_filename = args[0] |
517 | 538 |
518 return replay(options, replay_filename) | 539 return replay(options, replay_filename) |
519 | 540 |
520 | 541 |
521 if __name__ == '__main__': | 542 if __name__ == '__main__': |
522 sys.exit(main()) | 543 sys.exit(main()) |
OLD | NEW |