Bläddra i källkod

Merge pull request #6529 from ThomasWaldmann/fix-ipv6-url-parsing-master

fix scp repo url parsing for ip v6 addrs, fixes #6526
TW 3 år sedan
förälder
incheckning
6d55324b72
2 ändrade filer med 26 tillägg och 11 borttagningar
  1. 20 11
      src/borg/helpers/parseformat.py
  2. 6 0
      src/borg/testsuite/helpers.py

+ 20 - 11
src/borg/helpers/parseformat.py

@@ -341,24 +341,33 @@ class Location:
             (?P<archive>[^/]+)                              # archive name must not contain "/"
         )?$"""                                              # must match until the end
 
+    # host NAME, or host IP ADDRESS (v4 or v6, v6 must be in square brackets)
+    host_re = r"""
+        (?P<host>(
+            (?!\[)[^:/]+(?<!\])     # hostname or v4 addr, not containing : or / (does not match v6 addr: no brackets!)
+            |
+            \[[0-9a-fA-F:.]+\])     # ipv6 address in brackets
+        )
+    """
+
     # regexes for misc. kinds of supported location specifiers:
     ssh_re = re.compile(r"""
-        (?P<proto>ssh)://                                   # ssh://
-        """ + optional_user_re + r"""                       # user@  (optional)
-        (?P<host>([^:/]+|\[[0-9a-fA-F:.]+\]))(?::(?P<port>\d+))?  # host or host:port or [ipv6] or [ipv6]:port
-        """ + abs_path_re + optional_archive_re, re.VERBOSE)  # path or path::archive
+        (?P<proto>ssh)://                                       # ssh://
+        """ + optional_user_re + host_re + r"""                 # user@  (optional), host name or address
+        (?::(?P<port>\d+))?                                     # :port (optional)
+        """ + abs_path_re + optional_archive_re, re.VERBOSE)    # path or path::archive
 
     file_re = re.compile(r"""
-        (?P<proto>file)://                                  # file://
-        """ + file_path_re + optional_archive_re, re.VERBOSE)  # servername/path, path or path::archive
+        (?P<proto>file)://                                      # file://
+        """ + file_path_re + optional_archive_re, re.VERBOSE)   # servername/path, path or path::archive
 
-    # note: scp_re is also use for local paths
+    # note: scp_re is also used for local paths
     scp_re = re.compile(r"""
         (
-            """ + optional_user_re + r"""                   # user@  (optional)
-            (?P<host>([^:/]+|\[[0-9a-fA-F:.]+\])):          # host: (don't match / or [ipv6] in host to disambiguate from file:)
-        )?                                                  # user@host: part is optional
-        """ + scp_path_re + optional_archive_re, re.VERBOSE)  # path with optional archive
+            """ + optional_user_re + host_re + r"""             # user@  (optional), host name or address
+            :                                                   # : (required!)
+        )?                                                      # user@host: part is optional
+        """ + scp_path_re + optional_archive_re, re.VERBOSE)    # path with optional archive
 
     # get the repo from BORG_REPO env and the optional archive from param.
     # if the syntax requires giving REPOSITORY (see "borg mount"),

+ 6 - 0
src/borg/testsuite/helpers.py

@@ -100,6 +100,10 @@ class TestLocationWithoutEnv:
         assert repr(Location('ssh://user@[2001:db8::192.0.2.1]/some/path')) == \
             "Location(proto='ssh', user='user', host='2001:db8::192.0.2.1', port=None, path='/some/path', archive=None)"
         assert Location('ssh://user@[2001:db8::192.0.2.1]/some/path').to_key_filename() == keys_dir + '2001_db8__192_0_2_1__some_path'
+        assert repr(Location('ssh://user@[2a02:0001:0002:0003:0004:0005:0006:0007]/some/path')) == \
+            "Location(proto='ssh', user='user', host='2a02:0001:0002:0003:0004:0005:0006:0007', port=None, path='/some/path', archive=None)"
+        assert repr(Location('ssh://user@[2a02:0001:0002:0003:0004:0005:0006:0007]:1234/some/path')) == \
+            "Location(proto='ssh', user='user', host='2a02:0001:0002:0003:0004:0005:0006:0007', port=1234, path='/some/path', archive=None)"
 
     def test_file(self, monkeypatch, keys_dir):
         monkeypatch.delenv('BORG_REPO', raising=False)
@@ -132,6 +136,8 @@ class TestLocationWithoutEnv:
         assert repr(Location('user@[2001:db8::192.0.2.1]:/some/path')) == \
             "Location(proto='ssh', user='user', host='2001:db8::192.0.2.1', port=None, path='/some/path', archive=None)"
         assert Location('user@[2001:db8::192.0.2.1]:/some/path').to_key_filename() == keys_dir + '2001_db8__192_0_2_1__some_path'
+        assert repr(Location('user@[2a02:0001:0002:0003:0004:0005:0006:0007]:/some/path')) == \
+            "Location(proto='ssh', user='user', host='2a02:0001:0002:0003:0004:0005:0006:0007', port=None, path='/some/path', archive=None)"
 
     def test_smb(self, monkeypatch, keys_dir):
         monkeypatch.delenv('BORG_REPO', raising=False)