Skip to content

Instantly share code, notes, and snippets.

@duebbert
Forked from kevinvalk/msysgit2unix-socket.py
Last active June 18, 2025 13:45
Show Gist options
  • Select an option

  • Save duebbert/4298b5f4eb7cc064b09e9d865dd490c9 to your computer and use it in GitHub Desktop.

Select an option

Save duebbert/4298b5f4eb7cc064b09e9d865dd490c9 to your computer and use it in GitHub Desktop.

Revisions

  1. duebbert revised this gist Jul 11, 2017. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion msysgit2unix-socket.py
    Original file line number Diff line number Diff line change
    @@ -229,7 +229,7 @@ def cleanup():
    for pair in config.proxies:
    MSysGit2UnixSocketServer(pair[0], pair[1])

    # daemonize()
    daemonize()

    # Redundant cleanup :)
    atexit.register(cleanup)
  2. duebbert revised this gist Jul 11, 2017. 1 changed file with 0 additions and 2 deletions.
    2 changes: 0 additions & 2 deletions msysgit2unix-socket.py
    Original file line number Diff line number Diff line change
    @@ -103,7 +103,6 @@ def handle_close(self):
    def handle_read(self):
    data = self.recv(config.upstream_buffer_size)
    if data:
    print(data)
    self.downstream_dispatcher.send(data)


    @@ -123,7 +122,6 @@ def handle_close(self):
    def handle_read(self):
    data = self.recv(config.downstream_buffer_size)
    if data:
    print(data)
    self.upstream_dispatcher.send(data)


  3. duebbert revised this gist Jul 11, 2017. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion msysgit2unix-socket.py
    Original file line number Diff line number Diff line change
    @@ -1,4 +1,4 @@
    #!/usr/bin/python
    #!/usr/bin/python3

    """
    msysGit to Unix socket proxy
  4. duebbert revised this gist Jul 11, 2017. 1 changed file with 26 additions and 25 deletions.
    51 changes: 26 additions & 25 deletions msysgit2unix-socket.py
    Original file line number Diff line number Diff line change
    @@ -85,12 +85,12 @@ def __init__(self, downstream_dispatcher, upstream_path):
    self.out_buffer = b''
    self.downstream_dispatcher = downstream_dispatcher
    self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
    self.connect((b'localhost', UpstreamHandler.load_tcp_port_from_msysgit_socket_file(upstream_path)))
    self.connect(('localhost', UpstreamHandler.load_tcp_port_from_msysgit_socket_file(upstream_path)))

    @staticmethod
    def load_tcp_port_from_msysgit_socket_file(path):
    with open(path, 'r') as f:
    m = re.search(b'>([0-9]+)', f.readline())
    m = re.search('>([0-9]+)', f.readline())
    return int(m.group(1))

    def handle_connect(self):
    @@ -103,6 +103,7 @@ def handle_close(self):
    def handle_read(self):
    data = self.recv(config.upstream_buffer_size)
    if data:
    print(data)
    self.downstream_dispatcher.send(data)


    @@ -122,6 +123,7 @@ def handle_close(self):
    def handle_read(self):
    data = self.recv(config.downstream_buffer_size)
    if data:
    print(data)
    self.upstream_dispatcher.send(data)


    @@ -142,31 +144,30 @@ def handle_accept(self):
    sock, addr = pair
    DownstreamHandler(sock, self.upstream_socket_path)


    def build_config():
    class ProxyAction(argparse.Action):
    def __call__(self, parser, namespace, values, option_string=None):
    proxies = []
    for value in values:
    src_dst = value.partition(':')
    if src_dst[1] == b'':
    raise parser.error(b'Unable to parse sockets proxy pair "%s".' % value)
    if src_dst[1] == '':
    raise parser.error('Unable to parse sockets proxy pair "%s".' % value)
    proxies.append([src_dst[0], src_dst[2]])
    setattr(namespace, self.dest, proxies)

    parser = argparse.ArgumentParser(
    description='Transforms msysGit compatible sockets to Unix sockets for the Windows Linux Subsystem.')
    parser.add_argument(b'--downstream-buffer-size', default=8192, type=int, metavar=b'N',
    help=b'Maximum number of bytes to read at a time from the Unix socket.')
    parser.add_argument(b'--upstream-buffer-size', default=8192, type=int, metavar=b'N',
    help=b'Maximum number of bytes to read at a time from the msysGit socket.')
    parser.add_argument(b'--listen-backlog', default=100, type=int, metavar=b'N',
    help=b'Maximum number of simultaneous connections to the Unix socket.')
    parser.add_argument(b'--timeout', default=60, type=int, help=b'Timeout.', metavar=b'N')
    parser.add_argument(b'--pidfile', default=b'/tmp/msysgit2unix-socket.pid', metavar=b'FILE',
    help=b'Where to write the PID file.')
    parser.add_argument(b'proxies', nargs=b'+', action=ProxyAction, metavar='source:destination',
    help=b'A pair of a source msysGit and a destination Unix sockets.')
    parser.add_argument('--downstream-buffer-size', default=8192, type=int, metavar='N',
    help='Maximum number of bytes to read at a time from the Unix socket.')
    parser.add_argument('--upstream-buffer-size', default=8192, type=int, metavar='N',
    help='Maximum number of bytes to read at a time from the msysGit socket.')
    parser.add_argument('--listen-backlog', default=100, type=int, metavar='N',
    help='Maximum number of simultaneous connections to the Unix socket.')
    parser.add_argument('--timeout', default=60, type=int, help='Timeout.', metavar='N')
    parser.add_argument('--pidfile', default='/tmp/msysgit2unix-socket.pid', metavar='FILE',
    help='Where to write the PID file.')
    parser.add_argument('proxies', nargs='+', action=ProxyAction, metavar='source:destination',
    help='A pair of a source msysGit and a destination Unix sockets.')
    return parser.parse_args()


    @@ -176,10 +177,10 @@ def daemonize():
    if pid > 0:
    sys.exit()
    except OSError:
    sys.stderr.write(b'Fork #1 failed.')
    sys.stderr.write('Fork #1 failed.')
    sys.exit(1)

    os.chdir(b'/')
    os.chdir('/')
    os.setsid()
    os.umask(0)

    @@ -188,7 +189,7 @@ def daemonize():
    if pid > 0:
    sys.exit()
    except OSError:
    sys.stderr.write(b'Fork #2 failed.')
    sys.stderr.write('Fork #2 failed.')
    sys.exit(1)

    sys.stdout.flush()
    @@ -203,7 +204,7 @@ def daemonize():

    pid = str(os.getpid())
    with open(config.pidfile, 'w+') as f:
    f.write(b'%s\n' % pid)
    f.write('%s\n' % pid)

    def cleanup():
    try:
    @@ -213,28 +214,28 @@ def cleanup():
    if os.path.exists(config.pidfile):
    os.remove(config.pidfile)
    except Exception as e:
    sys.stderr.write(b'%s' % (e))
    sys.stderr.write('%s' % (e))

    if __name__ == b'__main__':
    if __name__ == '__main__':
    config = build_config()

    if os.path.exists(config.pidfile):
    # Check if process is really running, if not run cleanup
    f = open(config.pidfile, 'r')
    if PidExists(int(f.readline().strip())):
    sys.stderr.write(b'%s: Already running (or at least pidfile "%s" already exists).\n' % (sys.argv[0], config.pidfile))
    sys.stderr.write('%s: Already running (or at least pidfile "%s" already exists).\n' % (sys.argv[0], config.pidfile))
    sys.exit(0)
    else:
    cleanup()

    for pair in config.proxies:
    MSysGit2UnixSocketServer(pair[0], pair[1])

    daemonize()
    # daemonize()

    # Redundant cleanup :)
    atexit.register(cleanup)
    signal.signal(signal.SIGINT, cleanup)
    signal.signal(signal.SIGTERM, cleanup)

    asyncore.loop(config.timeout, True)
    asyncore.loop(config.timeout, True)
  5. @kevinvalk kevinvalk revised this gist Jan 2, 2017. 1 changed file with 50 additions and 10 deletions.
    60 changes: 50 additions & 10 deletions msysgit2unix-socket.py
    Original file line number Diff line number Diff line change
    @@ -44,7 +44,37 @@
    import signal
    import socket
    import sys
    import errno
    import atexit

    # NOTE: Taken from http://stackoverflow.com/a/6940314
    def PidExists(pid):
    """Check whether pid exists in the current process table.
    UNIX only.
    """
    if pid < 0:
    return False
    if pid == 0:
    # According to "man 2 kill" PID 0 refers to every process
    # in the process group of the calling process.
    # On certain systems 0 is a valid PID but we have no way
    # to know that in a portable fashion.
    raise ValueError('invalid PID 0')
    try:
    os.kill(pid, 0)
    except OSError as err:
    if err.errno == errno.ESRCH:
    # ESRCH == No such process
    return False
    elif err.errno == errno.EPERM:
    # EPERM clearly means there's a process to deny access to
    return True
    else:
    # According to "man 2 kill" possible error values are
    # (EINVAL, EPERM, ESRCH)
    raise
    else:
    return True

    class UpstreamHandler(asyncore.dispatcher_with_send):
    """
    @@ -87,6 +117,7 @@ def __init__(self, downstream_socket, upstream_path):

    def handle_close(self):
    self.close()
    self.upstream_dispatcher.close()

    def handle_read(self):
    data = self.recv(config.downstream_buffer_size)
    @@ -174,27 +205,36 @@ def daemonize():
    with open(config.pidfile, 'w+') as f:
    f.write(b'%s\n' % pid)


    def cleanup():
    for pair in config.proxies:
    os.remove(pair[1])
    os.remove(config.pidfile)
    sys.exit(0)

    try:
    for pair in config.proxies:
    if os.path.exists(pair[1]):
    os.remove(pair[1])
    if os.path.exists(config.pidfile):
    os.remove(config.pidfile)
    except Exception as e:
    sys.stderr.write(b'%s' % (e))

    if __name__ == b'__main__':
    config = build_config()

    if os.path.exists(config.pidfile):
    sys.stderr.write(
    b'%s: Already running (or at least pidfile "%s" already exists).\n' % (sys.argv[0], config.pidfile))
    sys.exit(0)
    # Check if process is really running, if not run cleanup
    f = open(config.pidfile, 'r')
    if PidExists(int(f.readline().strip())):
    sys.stderr.write(b'%s: Already running (or at least pidfile "%s" already exists).\n' % (sys.argv[0], config.pidfile))
    sys.exit(0)
    else:
    cleanup()

    for pair in config.proxies:
    MSysGit2UnixSocketServer(pair[0], pair[1])

    daemonize()

    # Redundant cleanup :)
    atexit.register(cleanup)
    signal.signal(signal.SIGINT, cleanup)
    signal.signal(signal.SIGTERM, cleanup)

    asyncore.loop(config.timeout, True)

  6. @FlorinAsavoaie FlorinAsavoaie created this gist Nov 15, 2016.
    200 changes: 200 additions & 0 deletions msysgit2unix-socket.py
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,200 @@
    #!/usr/bin/python

    """
    msysGit to Unix socket proxy
    ============================
    This small script is intended to help use msysGit sockets with the new Windows Linux Subsystem (aka Bash for Windows).
    It was specifically designed to pass SSH keys from the KeeAgent module of KeePass secret management application to the
    ssh utility running in the WSL (it only works with Linux sockets). However, my guess is that it will have uses for other
    applications as well.
    In order to efficiently use it, I add it at the end of the ~/.bashrc file, like this:
    export SSH_AUTH_SOCK="/tmp/.ssh-auth-sock"
    ~/bin/msysgit2unix-socket.py /mnt/c/Users/User/keeagent.sock:$SSH_AUTH_SOCK
    Command line usage: msysgit2unix-socket.py [-h] [--downstream-buffer-size N]
    [--upstream-buffer-size N] [--listen-backlog N]
    [--timeout N] [--pidfile FILE]
    source:destination [source:destination ...]
    Positional arguments:
    source:destination A pair of a source msysGit and a destination Unix
    sockets.
    Optional arguments:
    -h, --help show this help message and exit
    --downstream-buffer-size N
    Maximum number of bytes to read at a time from the
    Unix socket.
    --upstream-buffer-size N
    Maximum number of bytes to read at a time from the
    msysGit socket.
    --listen-backlog N Maximum number of simultaneous connections to the Unix
    socket.
    --timeout N Timeout.
    --pidfile FILE Where to write the PID file.
    """

    import argparse
    import asyncore
    import os
    import re
    import signal
    import socket
    import sys


    class UpstreamHandler(asyncore.dispatcher_with_send):
    """
    This class handles the connection to the TCP socket listening on localhost that makes the msysGit socket.
    """
    def __init__(self, downstream_dispatcher, upstream_path):
    asyncore.dispatcher.__init__(self)
    self.out_buffer = b''
    self.downstream_dispatcher = downstream_dispatcher
    self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
    self.connect((b'localhost', UpstreamHandler.load_tcp_port_from_msysgit_socket_file(upstream_path)))

    @staticmethod
    def load_tcp_port_from_msysgit_socket_file(path):
    with open(path, 'r') as f:
    m = re.search(b'>([0-9]+)', f.readline())
    return int(m.group(1))

    def handle_connect(self):
    pass

    def handle_close(self):
    self.close()
    self.downstream_dispatcher.close()

    def handle_read(self):
    data = self.recv(config.upstream_buffer_size)
    if data:
    self.downstream_dispatcher.send(data)


    class DownstreamHandler(asyncore.dispatcher_with_send):
    """
    This class handles the connections that are being accepted on the Unix socket.
    """
    def __init__(self, downstream_socket, upstream_path):
    asyncore.dispatcher.__init__(self, downstream_socket)
    self.out_buffer = b''
    self.upstream_dispatcher = UpstreamHandler(self, upstream_path)

    def handle_close(self):
    self.close()

    def handle_read(self):
    data = self.recv(config.downstream_buffer_size)
    if data:
    self.upstream_dispatcher.send(data)


    class MSysGit2UnixSocketServer(asyncore.dispatcher):
    """
    This is the "server" listening for connections on the Unix socket.
    """
    def __init__(self, upstream_socket_path, unix_socket_path):
    asyncore.dispatcher.__init__(self)
    self.upstream_socket_path = upstream_socket_path
    self.create_socket(socket.AF_UNIX, socket.SOCK_STREAM)
    self.bind(unix_socket_path)
    self.listen(config.listen_backlog)

    def handle_accept(self):
    pair = self.accept()
    if pair is not None:
    sock, addr = pair
    DownstreamHandler(sock, self.upstream_socket_path)


    def build_config():
    class ProxyAction(argparse.Action):
    def __call__(self, parser, namespace, values, option_string=None):
    proxies = []
    for value in values:
    src_dst = value.partition(':')
    if src_dst[1] == b'':
    raise parser.error(b'Unable to parse sockets proxy pair "%s".' % value)
    proxies.append([src_dst[0], src_dst[2]])
    setattr(namespace, self.dest, proxies)

    parser = argparse.ArgumentParser(
    description='Transforms msysGit compatible sockets to Unix sockets for the Windows Linux Subsystem.')
    parser.add_argument(b'--downstream-buffer-size', default=8192, type=int, metavar=b'N',
    help=b'Maximum number of bytes to read at a time from the Unix socket.')
    parser.add_argument(b'--upstream-buffer-size', default=8192, type=int, metavar=b'N',
    help=b'Maximum number of bytes to read at a time from the msysGit socket.')
    parser.add_argument(b'--listen-backlog', default=100, type=int, metavar=b'N',
    help=b'Maximum number of simultaneous connections to the Unix socket.')
    parser.add_argument(b'--timeout', default=60, type=int, help=b'Timeout.', metavar=b'N')
    parser.add_argument(b'--pidfile', default=b'/tmp/msysgit2unix-socket.pid', metavar=b'FILE',
    help=b'Where to write the PID file.')
    parser.add_argument(b'proxies', nargs=b'+', action=ProxyAction, metavar='source:destination',
    help=b'A pair of a source msysGit and a destination Unix sockets.')
    return parser.parse_args()


    def daemonize():
    try:
    pid = os.fork()
    if pid > 0:
    sys.exit()
    except OSError:
    sys.stderr.write(b'Fork #1 failed.')
    sys.exit(1)

    os.chdir(b'/')
    os.setsid()
    os.umask(0)

    try:
    pid = os.fork()
    if pid > 0:
    sys.exit()
    except OSError:
    sys.stderr.write(b'Fork #2 failed.')
    sys.exit(1)

    sys.stdout.flush()
    sys.stderr.flush()

    si = open('/dev/null', 'r')
    so = open('/dev/null', 'a+')
    se = open('/dev/null', 'a+')
    os.dup2(si.fileno(), sys.stdin.fileno())
    os.dup2(so.fileno(), sys.stdout.fileno())
    os.dup2(se.fileno(), sys.stderr.fileno())

    pid = str(os.getpid())
    with open(config.pidfile, 'w+') as f:
    f.write(b'%s\n' % pid)


    def cleanup():
    for pair in config.proxies:
    os.remove(pair[1])
    os.remove(config.pidfile)
    sys.exit(0)


    if __name__ == b'__main__':
    config = build_config()

    if os.path.exists(config.pidfile):
    sys.stderr.write(
    b'%s: Already running (or at least pidfile "%s" already exists).\n' % (sys.argv[0], config.pidfile))
    sys.exit(0)

    for pair in config.proxies:
    MSysGit2UnixSocketServer(pair[0], pair[1])

    daemonize()
    signal.signal(signal.SIGTERM, cleanup)

    asyncore.loop(config.timeout, True)