diff options
| -rw-r--r-- | .gitignore | 1 | ||||
| -rw-r--r-- | Makefile | 5 | ||||
| -rw-r--r-- | config/.demo.yaml.swp | bin | 0 -> 12288 bytes | |||
| -rw-r--r-- | config/demo.yaml | 33 | ||||
| -rw-r--r-- | main.go | 3 | ||||
| -rwxr-xr-x | scripts/gen-shapeshifter-state.py | 62 | ||||
| -rwxr-xr-x | scripts/simplevpn.py | 79 | ||||
| -rw-r--r-- | scripts/templates/.eip-service.json.swp | bin | 0 -> 12288 bytes | |||
| -rw-r--r-- | scripts/templates/eip-service.json | 32 | 
9 files changed, 215 insertions, 0 deletions
| @@ -1 +1,2 @@  vpnweb +deploy/* @@ -5,6 +5,11 @@ demo:  clean:  	rm -f public/1/*  	rm public/ca.crt +gen-shapeshifter: +	scripts/gen-shapeshifter-state.py deploy/shapeshifter-state +gen-provider: +	mkdir -p deploy/public/3 +	python3 scripts/simplevpn.py config/demo.yaml scripts/templates/eip-service.json --obfs4_state deploy/shapeshifter-state > deploy/public/3/eip-service.json  populate:  	cp test/1/* public/1/  	cp test/files/ca.crt public/ diff --git a/config/.demo.yaml.swp b/config/.demo.yaml.swpBinary files differ new file mode 100644 index 0000000..b673bd7 --- /dev/null +++ b/config/.demo.yaml.swp diff --git a/config/demo.yaml b/config/demo.yaml new file mode 100644 index 0000000..5743304 --- /dev/null +++ b/config/demo.yaml @@ -0,0 +1,33 @@ +openvpn: + +    - auth: SHA1 +    - cipher: AES-256-CBC +    - keepalive: "10 30" +    - tls-cipher: DHE-RSA-AES128-SHA +    - tun-ipv6: true +    - dev: tun +    - sndbuf: 0 +    - rcvbuf: 0 +    - nobind: true +    - persist-key: true +    - key-direction: 1 +    - verb: 3 + +locations: + +    - Amsterdam: +        - name: Amsterdam +        - country_code: NL +        - hemisphere: N +        - timezone: -1 + + +gateways: + +    - pt.demo.bitmask.net: +        - host: pt.demo.bitmask.net +        - ip_address: 37.218.247.60 +        - location: Amsterdam +        - transports: +            - [ "openvpn", "tcp", "443"] +            - [ "obfs4", "tcp", "23042"] @@ -66,9 +66,12 @@ func main() {  	// add routes here  	http.HandleFunc("/1/cert", ch.certResponder) +	http.HandleFunc("/3/cert", ch.certResponder)  	httpFileHandler("/1/ca.crt", "./public/ca.crt")  	httpFileHandler("/1/configs.json", "./public/1/configs.json")  	httpFileHandler("/1/service.json", "./public/1/service.json") +	httpFileHandler("/3/service.json", "./public/3/service.json") +	httpFileHandler("/3/service.json", "./public/3/eip-service.json")  	pstr := ":" + strconv.Itoa(*port) diff --git a/scripts/gen-shapeshifter-state.py b/scripts/gen-shapeshifter-state.py new file mode 100755 index 0000000..e7b1ff2 --- /dev/null +++ b/scripts/gen-shapeshifter-state.py @@ -0,0 +1,62 @@ +#!/usr/bin/env python3 +""" +Generates the Curve25519 keypair that is needed by the shapeshifter-dispatcher +server. + +Depends on python3-axolotl-curve25519 package. +""" + +import base64 +import json +import os + +import pysodium +import binascii + +BRIDGE_PREAMBLE = "Bridge obfs4 <IP ADDRESS>:<PORT> <FINGERPRINT> cert=" +BRIDGE_END = " iat-mode=0" + + +def generate(statedir): +    try: +        os.makedirs(statedir) +    except Exception: +        pass +    print("[+] Generating shapeshifter parameters...") + +    public, private = pysodium.crypto_box_keypair() + +    priv_hex = binascii.b2a_hex(private) +    pub_hex = binascii.b2a_hex(public) +    node_id = os.urandom(20) +    node_id_hex = binascii.b2a_hex(node_id) +    drbg_seed = os.urandom(24) + +    def tostr(b): +        return b.decode('utf-8') + +    with open(statedir + '/obfs4_state.json', 'w') as state: +        state.write(json.dumps({ +            'node-id': tostr(node_id_hex), +            'private-key': tostr(priv_hex), +            'public-key': tostr(pub_hex), +            'drbg-seed': tostr(binascii.b2a_hex(drbg_seed)), +            'iat-mode': 0})) + +    cert = base64.b64encode(node_id + pub_hex) +    print("CERT:", cert) + +    with open(statedir + '/obfs4_cert.txt', 'w') as certf: +        certf.write(tostr(cert).rstrip('=')) + +    with open(statedir + '/obfs4_bridgeline.txt', 'w') as bridgef: +        bridgef.write(BRIDGE_PREAMBLE + tostr(cert) + BRIDGE_END) +    print("[+] done") + + +if __name__ == "__main__": +    import argparse +    parser = argparse.ArgumentParser() +    parser.add_argument("statedir") +    args = parser.parse_args() +    generate(args.statedir) diff --git a/scripts/simplevpn.py b/scripts/simplevpn.py new file mode 100755 index 0000000..7906e7c --- /dev/null +++ b/scripts/simplevpn.py @@ -0,0 +1,79 @@ +#!/usr/bin/env python3 +import argparse +import os + +import yaml + +from jinja2 import Template + + +class EIPConfig: +    def __init__(self): +        self.openvpn = dict() +        self.locations = dict() +        self.gateways = dict() +        self.obfs4_cert = "" + + +def parseConfig(provider_config): +    with open(provider_config) as conf: +        config = yaml.load(conf.read()) +    eip = EIPConfig() +    eip.openvpn.update(yamlListToDict(config['openvpn'])) + +    for loc in config['locations']: +        eip.locations.update(yamlIdListToDict(loc)) +    for gw in config['gateways']: +        eip.gateways.update(yamlIdListToDict(gw)) +    return eip + + +def yamlListToDict(values): +    vals = {} +    for d in values: +        for k, v in d.items(): +            vals[k] = v +    return vals + + +def yamlIdListToDict(data): +    _d = {} +    for identifier, values in data.items(): +        _d[identifier] = yamlListToDict(values) +    return _d + + +def patchObfs4Cert(config, cert): +    for gw in config.gateways: +        for options in config.gateways[gw]['transports']: +            opts = {} +            transport, _, _ = options +            if transport == "obfs4": +                opts['cert'] = cert +                opts['iat-mode'] = 0 +            options.append(opts) +    return config + + +if __name__ == "__main__": +    parser = argparse.ArgumentParser() +    parser.add_argument("provider_config") +    parser.add_argument("eip_template") +    parser.add_argument("--obfs4_state") +    args = parser.parse_args() + +    config = parseConfig(os.path.abspath(args.provider_config)) + +    if args.obfs4_state: +        obfs4_cert = open( +            args.obfs4_state + '/obfs4_cert.txt').read().rstrip() +    else: +        obfs4_cert = None +    patchObfs4Cert(config, obfs4_cert) + +    t = Template(open(args.eip_template).read()) + +    print(t.render( +        locations=config.locations, +        gateways=config.gateways, +        openvpn=config.openvpn)) diff --git a/scripts/templates/.eip-service.json.swp b/scripts/templates/.eip-service.json.swpBinary files differ new file mode 100644 index 0000000..284242a --- /dev/null +++ b/scripts/templates/.eip-service.json.swp diff --git a/scripts/templates/eip-service.json b/scripts/templates/eip-service.json new file mode 100644 index 0000000..8d1b0a1 --- /dev/null +++ b/scripts/templates/eip-service.json @@ -0,0 +1,32 @@ +{ +    "serial": 3, +    "version": 3, +    "locations": { {% for loc in locations %} +        "{{loc}}": { +            "name": "{{ locations[loc]["name"] }}", +            "country_code": "{{ locations[loc]["country_code"] }}", +            "hemisphere": "{{ locations[loc]["hemisphere"] }}", +            "timezone": {{ locations[loc]["timezone"] }}, +        },{% endfor %} +    }, +    "gateways": { {% for gw in gateways %} +        "{{gw}}": { +            "host": "{{ gateways[gw]["host"] }}", +            "ip_address": "{{ gateways[gw]["ip_address"] }}", +            "location": "{{ gateways[gw]["location"] }}", +            "capabilities": { +                "adblock": false, +                "filter_dns": false, +                "limited": false, +                "transport": [ {% for tr, proto, port, options in gateways[gw]["transports"] %} +                    {"type": "{{ tr }}", +                     "protocols": ["{{ proto }}"], +                     "ports": [{{ port }}],{% if options %} +                     "options": {{ options | tojson }},{% endif %} +                    },{% endfor %} +                ], +            }, +        },{% endfor %} +    }, +    "openvpn_configuration": {{ openvpn|tojson(indent=8) }} +} | 
