浏览代码

fix scp repo url parsing for ip v6 addrs, fixes #6526

added a negative lookahead/lookbehind to make sure an ipv6 addr
(enclosed in square brackets) does not get badly matched by the
regex part intended for hostnames and ipv4 addrs only.

the other part of that regex which is actually intended to match
ipv6 addrs only matches if they are enclosed in square brackets.

also added tests for ssh and scp style repo URLs with ipv6 addrs
in brackets.

also: made regex more readable, putting these 2 cases on separate lines.
Thomas Waldmann 3 年之前
父节点
当前提交
f24979bc09
共有 2 个文件被更改,包括 14 次插入4 次删除
  1. 8 4
      src/borg/helpers/parseformat.py
  2. 6 0
      src/borg/testsuite/helpers.py

+ 8 - 4
src/borg/helpers/parseformat.py

@@ -355,10 +355,14 @@ class Location:
     # note: scp_re is also use 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 + r"""                           # user@  (optional)
+            (?P<host>(                  # host can be ipv6 addr in brackets or something else
+                (?!\[)[^:/]+(?<!\])     # host: hostname, not containing : or /, also not ipv6: not in brackets
+                |
+                \[[0-9a-fA-F:.]+\])     # host: ipv6 addr in brackets
+            ):
+        )?                                                          # 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)