Skip to content

Commit

Permalink
add --source-address command-line option (closes #2206)
Browse files Browse the repository at this point in the history
  • Loading branch information
mikf committed Jan 21, 2022
1 parent 698f352 commit de75459
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 7 deletions.
14 changes: 14 additions & 0 deletions docs/configuration.rst
Original file line number Diff line number Diff line change
Expand Up @@ -463,6 +463,20 @@ Description
otherwise ``http://`` is assumed.


extractor.*.source-address
--------------------------
Type
* ``string``
* ``list`` with 1 ``string`` and 1 ``integer`` as elements
Example
* ``"192.168.178.20"``
* ``["192.168.178.20", 8080]``
Description
Client-side IP address to bind to.

| Can be either a simple ``string`` with just the local IP address
| or a ``list`` with IP and explicit port number as elements.
extractor.*.user-agent
----------------------
Type
Expand Down
44 changes: 37 additions & 7 deletions gallery_dl/extractor/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,14 @@ def _init_session(self):
headers = session.headers
headers.clear()

source_address = self.config("source-address")
if source_address:
if isinstance(source_address, str):
source_address = (source_address, 0)
else:
source_address = (source_address[0], source_address[1])

This comment has been minimized.

Copy link
@rautamiekka

rautamiekka Jan 23, 2022

Contributor

Not sure of the point of this block, but I think you could do either of these instead:

                source_address = tuple(source_address[:2])
                source_address = tuple(*source_address)

This comment has been minimized.

Copy link
@mikf

mikf Jan 23, 2022

Author Owner

It is supposed to ensure source_address is a 2-tuple and not a list.
It is essentially the same as tuple(source_address[:2]), but it crashes when there aren't 2 or more elements.

session.mount("http://", SourceAdapter(source_address))

browser = self.config("browser") or self.browser
if browser and isinstance(browser, str):
browser, _, platform = browser.lower().partition(":")
Expand All @@ -235,10 +243,12 @@ def _init_session(self):
platform = "Macintosh; Intel Mac OS X 11.5"

if browser == "chrome":
_emulate_browser_chrome(session, platform)
_emulate_browser_chrome(session, platform, source_address)
else:
_emulate_browser_firefox(session, platform)
_emulate_browser_firefox(session, platform, source_address)
else:
if source_address:
session.mount("https://", SourceAdapter(source_address))
headers["User-Agent"] = self.config("user-agent", (
"Mozilla/5.0 (Windows NT 10.0; Win64; x64; "
"rv:91.0) Gecko/20100101 Firefox/91.0"))
Expand Down Expand Up @@ -605,26 +615,44 @@ def update(cls, instances):
)


class SourceAdapter(HTTPAdapter):

def __init__(self, source_address):
self.source_address = source_address
HTTPAdapter.__init__(self)

def init_poolmanager(self, *args, **kwargs):
kwargs["source_address"] = self.source_address
return HTTPAdapter.init_poolmanager(self, *args, **kwargs)

def proxy_manager_for(self, *args, **kwargs):
kwargs["source_address"] = self.source_address
return HTTPAdapter.proxy_manager_for(self, *args, **kwargs)


class HTTPSAdapter(HTTPAdapter):

def __init__(self, ciphers):
def __init__(self, ciphers, source_address=None):
context = self.ssl_context = ssl.create_default_context()
context.options |= (ssl.OP_NO_SSLv2 | ssl.OP_NO_SSLv3 |
ssl.OP_NO_TLSv1 | ssl.OP_NO_TLSv1_1)
context.set_ecdh_curve("prime256v1")
context.set_ciphers(ciphers)
self.source_address = source_address
HTTPAdapter.__init__(self)

def init_poolmanager(self, *args, **kwargs):
kwargs["ssl_context"] = self.ssl_context
kwargs["source_address"] = self.source_address
return HTTPAdapter.init_poolmanager(self, *args, **kwargs)

def proxy_manager_for(self, *args, **kwargs):
kwargs["ssl_context"] = self.ssl_context
kwargs["source_address"] = self.source_address
return HTTPAdapter.proxy_manager_for(self, *args, **kwargs)


def _emulate_browser_firefox(session, platform):
def _emulate_browser_firefox(session, platform, source_address):
headers = session.headers
headers["User-Agent"] = ("Mozilla/5.0 (" + platform + "; rv:91.0) "
"Gecko/20100101 Firefox/91.0")
Expand Down Expand Up @@ -654,11 +682,12 @@ def _emulate_browser_firefox(session, platform):
"DHE-RSA-AES256-SHA:"
"AES128-SHA:"
"AES256-SHA:"
"DES-CBC3-SHA"
"DES-CBC3-SHA",
source_address
))


def _emulate_browser_chrome(session, platform):
def _emulate_browser_chrome(session, platform, source_address):
if platform.startswith("Macintosh"):
platform = platform.replace(".", "_") + "_2"

Expand Down Expand Up @@ -690,7 +719,8 @@ def _emulate_browser_chrome(session, platform):
"AES256-GCM-SHA384:"
"AES128-SHA:"
"AES256-SHA:"
"DES-CBC3-SHA"
"DES-CBC3-SHA",
source_address
))


Expand Down
5 changes: 5 additions & 0 deletions gallery_dl/option.py
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,11 @@ def build_parser():
dest="proxy", metavar="URL", action=ConfigAction,
help="Use the specified proxy",
)
general.add_argument(
"--source-address",
dest="source-address", metavar="IP", action=ConfigAction,
help="Client-side IP address to bind to",
)
general.add_argument(
"--clear-cache",
dest="clear_cache", metavar="MODULE",
Expand Down

0 comments on commit de75459

Please sign in to comment.