URI: 
       tAdd IP address whitelisting feature - electrum-personal-server - Maximally lightweight electrum server for a single user
  HTML git clone https://git.parazyd.org/electrum-personal-server
   DIR Log
   DIR Files
   DIR Refs
   DIR README
       ---
   DIR commit 5a255e406a578622f074259ece66e9d047d8ac98
   DIR parent 4dc8422e6e18ef09e771aed53b7a334c9d376d2e
  HTML Author: chris-belcher <chris-belcher@users.noreply.github.com>
       Date:   Wed, 23 May 2018 16:52:34 +0100
       
       Add IP address whitelisting feature
       
       Diffstat:
         M README.md                           |      10 ++++++----
         M config.cfg_sample                   |       7 ++++++-
         M server.py                           |      23 ++++++++++++++++++-----
       
       3 files changed, 30 insertions(+), 10 deletions(-)
       ---
   DIR diff --git a/README.md b/README.md
       t@@ -78,18 +78,20 @@ headers; and locks Electrum to connect only to your server, disabling the GUI
        button to stop accidental connections. This helps avoid a user accidentally
        ruining their privacy by connecting to public Electrum servers.
        
       -Electrum Personal Server also works on [testnet bitcoin](https://en.bitcoin.it/wiki/Testnet). The Electrum wallet can be started in testnet mode with the command line flag `--testnet`.
       +Electrum Personal Server also works on [testnet](https://en.bitcoin.it/wiki/Testnet) and [regtest](https://bitcoin.org/en/glossary/regression-test-mode). The Electrum wallet can be started in testnet mode with the command line flag `--testnet` or `--regtest`.
        
        
        #### Exposure to the Internet
        
        Other people should not be connecting to your server. They won't be
        able to synchronize their wallet, and they could potentially learn all your
       -wallet addresses.
       +wallet addresses. They should also not be packet sniffing the connection
       +because it is not encrypted securely.
        
        By default the server will accept connections only from `localhost` so you
       -should either run Electrum wallet from the same computer or use a SSH tunnel
       -from another computer.
       +should either run Electrum wallet from the same computer, or use an encrypted
       +SSH tunnel from another computer, or use the IP address whitelisting feature to
       +connect over your own LAN.
        
        #### How is this different from other Electrum servers ?
        
   DIR diff --git a/config.cfg_sample b/config.cfg_sample
       t@@ -48,10 +48,15 @@ gap_limit = 25
        [electrum-server]
        # 0.0.0.0 to accept connections from any IP
        #127.0.0.1 to accept from only localhost
       -# recommend you accept localhost only, for connecting remotely use a ssh tunnel
        host = 127.0.0.1
        port = 50002
        
       +# space-separated whitelist of IP addresses
       +# accepts CIDR notation eg 192.168.0.0/16 or 2a01:4f8:1f1::/120
       +# star (*) means all are accepted
       +# generally requires host binding (above) to be 0.0.0.0
       +ip_whitelist = *
       +
        #uses the default one, which is fine because by default nobody should be
        # allowed to connect to your server or scan your packets
        #to generate another certificate see https://github.com/spesmilo/electrum-server/blob/ce1b11d7f5f7a70a3b6cc7ec1d3e552436e54ffe/HOWTO.md#step-8-create-a-self-signed-ssl-cert
   DIR diff --git a/server.py b/server.py
       t@@ -4,6 +4,7 @@ import socket, time, json, datetime, struct, binascii, ssl, os, os.path
        from configparser import ConfigParser, NoSectionError, NoOptionError
        from collections import defaultdict
        import traceback, sys, platform
       +from ipaddress import ip_network, ip_address
        
        from electrumpersonalserver.jsonrpc import JsonRpc, JsonRpcError
        import electrumpersonalserver.hashes as hashes
       t@@ -295,8 +296,8 @@ def create_server_socket(hostport):
            log("Listening for Electrum Wallet on " + str(hostport))
            return server_sock
        
       -def run_electrum_server(hostport, rpc, txmonitor, poll_interval_listening,
       -        poll_interval_connected, certfile, keyfile):
       +def run_electrum_server(rpc, txmonitor, hostport, ip_whitelist,
       +        poll_interval_listening, poll_interval_connected, certfile, keyfile):
            log("Starting electrum server")
            server_sock = create_server_socket(hostport)
            server_sock.settimeout(poll_interval_listening)
       t@@ -306,12 +307,16 @@ def run_electrum_server(hostport, rpc, txmonitor, poll_interval_listening,
                    while sock == None:
                        try:
                            sock, addr = server_sock.accept()
       +                    if not any([ip_address(addr[0]) in ipnet
       +                            for ipnet in ip_whitelist]):
       +                        debug(addr[0] + " not in whitelist, closing")
       +                        raise ConnectionRefusedError()
                            sock = ssl.wrap_socket(sock, server_side=True,
                                certfile=certfile, keyfile=keyfile,
                                ssl_version=ssl.PROTOCOL_SSLv23)
                        except socket.timeout:
                            on_heartbeat_listening(txmonitor)
       -                except ssl.SSLError:
       +                except (ConnectionRefusedError, ssl.SSLError):
                            sock.close()
                            sock = None
        
       t@@ -504,14 +509,22 @@ def main():
                    return
                hostport = (config.get("electrum-server", "host"),
                        int(config.get("electrum-server", "port")))
       +        ip_whitelist = []
       +        for ip in config.get("electrum-server", "ip_whitelist").split(" "):
       +            if ip == "*":
       +                #matches everything
       +                ip_whitelist.append(ip_network("0.0.0.0/0"))
       +                ip_whitelist.append(ip_network("::0/0"))
       +            else:
       +                ip_whitelist.append(ip_network(ip, strict=False))
                poll_interval_listening = int(config.get("bitcoin-rpc",
                    "poll_interval_listening"))
                poll_interval_connected = int(config.get("bitcoin-rpc",
                    "poll_interval_connected"))
                certfile = config.get("electrum-server", "certfile")
                keyfile = config.get("electrum-server", "keyfile")
       -        run_electrum_server(hostport, rpc, txmonitor, poll_interval_listening,
       -            poll_interval_connected, certfile, keyfile)
       +        run_electrum_server(rpc, txmonitor, hostport, ip_whitelist,
       +            poll_interval_listening, poll_interval_connected, certfile, keyfile)
        
        if __name__ == "__main__":
            main()