diff --git a/LICENSE b/LICENSE deleted file mode 120000 index 4761def..0000000 --- a/LICENSE +++ /dev/null @@ -1 +0,0 @@ -UNLICENSE \ No newline at end of file diff --git a/UNLICENSE b/UNLICENSE deleted file mode 100644 index 68a49da..0000000 --- a/UNLICENSE +++ /dev/null @@ -1,24 +0,0 @@ -This is free and unencumbered software released into the public domain. - -Anyone is free to copy, modify, publish, use, compile, sell, or -distribute this software, either in source code form or as a compiled -binary, for any purpose, commercial or non-commercial, and by any -means. - -In jurisdictions that recognize copyright laws, the author or authors -of this software dedicate any and all copyright interest in the -software to the public domain. We make this dedication for the benefit -of the public at large and to the detriment of our heirs and -successors. We intend this dedication to be an overt act of -relinquishment in perpetuity of all present and future rights to this -software under copyright law. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR -OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, -ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -OTHER DEALINGS IN THE SOFTWARE. - -For more information, please refer to diff --git a/web/__init__.py b/web/__init__.py index 92da140..afc1256 100644 --- a/web/__init__.py +++ b/web/__init__.py @@ -54,6 +54,9 @@ def create_app(test_config=None): from . import ipsets app.register_blueprint(ipsets.blueprint, url_prefix='/ipsets') + from . import nat + app.register_blueprint(nat.blueprint, url_prefix='/nat') + from . import rules app.register_blueprint(rules.blueprint, url_prefix='/rules') diff --git a/web/ipsets.py b/web/ipsets.py index 203a78e..63f8c04 100644 --- a/web/ipsets.py +++ b/web/ipsets.py @@ -15,27 +15,18 @@ def index(): return flask.Response('forbidden', status=403, mimetype='text/plain') with db.locked(): + ipsets = db.read('ipsets') + networks = db.read('networks') if flask.request.method == 'POST': - # read network data from NetBox, merge in custom definitions and dump the lot - ipsets = db.read('networks') - formdata = zip(*(flask.request.form.getlist(e) for e in ('name', 'ip', 'ip6', 'nat', 'vpn'))) - for name, ip, ip6, nat, vpn in formdata: - # drop sets with empty names - if not name: - continue - # assign IPs for custom networks only - if name not in ipsets: - ipsets[name] = { 'ip': ip.split(), 'ip6': ip6.split() } - # assign NAT and VPN for all networks - ipsets[name] |= { 'nat': nat, 'vpn': vpn } + form = flask.request.form + ipsets = {} + for name, ip, ip6 in zip(form.getlist('name'), form.getlist('ip'), form.getlist('ip6')): + if name and name not in networks: + ipsets[name] = { + 'ip': ip.split(), + 'ip6': ip6.split() + } db.write('ipsets', ipsets) system.run(system.save_config) return flask.redirect(flask.url_for('ipsets.index')) - - # read network data from NetBox and merge in custom definitions - ipsets = db.read('networks') - for name, data in db.read('ipsets').items(): - # keep static IPs if there are any, otherwise set custom flag for this set - ipsets[name] = data | ipsets.get(name, {'custom': True}) - return flask.render_template('ipsets/index.html', ipsets=ipsets) diff --git a/web/nat.py b/web/nat.py new file mode 100644 index 0000000..3172125 --- /dev/null +++ b/web/nat.py @@ -0,0 +1,26 @@ +import flask +import flask_login + +from . import db +from . import system + +blueprint = flask.Blueprint('nat', __name__) + +@blueprint.route('/', methods=('GET', 'POST')) +@flask_login.login_required +def index(): + if not flask_login.current_user.is_admin: + return flask.Response('forbidden', status=403, mimetype='text/plain') + + with db.locked(): + nat = { network: "" for network in db.read('networks') } + nat |= db.read('nat') + if flask.request.method == 'POST': + form = flask.request.form + for network, address in form.items(): + if network in nat: + nat[network] = address + db.write('nat', nat) + system.run(system.save_config) + return flask.redirect(flask.url_for('nat.index')) + return flask.render_template('nat/index.html', nat=nat) diff --git a/web/rules.py b/web/rules.py index 349dd5f..04cecb4 100644 --- a/web/rules.py +++ b/web/rules.py @@ -46,6 +46,8 @@ def edit(index): with db.locked(): ipsets = db.read('ipsets') + for network, data in db.read('networks').items(): + ipsets[network] = {'ip': data.get('ip', []), 'ip6': data.get('ip6', [])} return flask.render_template('rules/edit.html', index=index, rule=db.load('rules')[index], ipsets=ipsets) except IndexError as e: return flask.Response(f'invalid rule: {index}', status=400, mimetype='text/plain') @@ -53,24 +55,24 @@ def edit(index): def can_toggle(user, rule): return user.is_admin or not user.groups.isdisjoint(rule.get('managers', ())) -@blueprint.route('/manage', methods=('GET', 'POST')) +@blueprint.route('/manage') @flask_login.login_required def manage(): - with db.locked(): - rules = db.read('rules') - allowed = set(rule['name'] for rule in rules if can_toggle(flask_login.current_user, rule)) - if flask.request.method == 'POST': - # check that all posted rules are allowed for this user - posted = set(flask.request.form.getlist('rule')) - if posted - allowed: - return flask.Response('forbidden', status=403, mimetype='text/plain') + rules = [rule|{'index': index} for index, rule in enumerate(db.load('rules')) + if can_toggle(flask_login.current_user, rule)] + return flask.render_template('rules/manage.html', rules=rules) - # set status for posted rules - enabled = set(flask.request.form.getlist('enabled')) - for rule in rules: - if rule['name'] in posted: - rule['enabled'] = (rule['name'] in enabled) +@blueprint.route('/toggle//') +@flask_login.login_required +def toggle(index, enable): + try: + with db.locked(): + rules = db.read('rules') + if not can_toggle(flask_login.current_user, rules[index]): + return flask.Response('forbidden', status=403, mimetype='text/plain') + rules[index]['enabled'] = (enable == 'true') db.write('rules', rules) - system.run(system.save_config) - return flask.redirect(flask.url_for('rules.manage')) - return flask.render_template('rules/manage.html', rules=[rule for rule in rules if rule['name'] in allowed]) + system.run(system.save_config) + return flask.redirect(flask.url_for('rules.manage')) + except IndexError as e: + return flask.Response(f'invalid rule: {index}', status=400, mimetype='text/plain') diff --git a/web/system.py b/web/system.py index 3bb66b9..8d2d699 100644 --- a/web/system.py +++ b/web/system.py @@ -19,10 +19,6 @@ import ldap3 from . import db -def init_app(app): - app.cli.add_command(generate) - app.cli.add_command(push) - def mail(rcpt, subject, body): try: msg = email.message.EmailMessage() @@ -35,6 +31,10 @@ def mail(rcpt, subject, body): except Exception as e: syslog.syslog(f'error sending mail: {e}') +def init_app(app): + app.cli.add_command(generate) + app.cli.add_command(push) + def run(fun, args=()): def task(): if os.fork() == 0: @@ -42,52 +42,65 @@ def run(fun, args=()): fun(*args) multiprocessing.Process(target=task).start() -# Generate configuration files and create a config tarball. +def ipset_add(ipsets, name, ip=None, ip6=None): + ipsets[name].update(ip or ()) + ipsets[f'{name}/6'].update(ip6 or ()) + def save_config(): + # Format strings for creating firewall config files. + nft_set = 'set {name} {{\n type ipv{family}_addr; flags interval; {elements}\n}}\n\n' + nft_map = 'map {name} {{\n type ipv4_addr : interval ipv4_addr; flags interval; {elements}\n}}\n\n' + nft_forward = '# {index}. {name}\n{text}\n\n' + wg_intf = '[Interface]\nListenPort = {port}\nPrivateKey = {key}\n\n' + wg_peer = '# {user}\n[Peer]\nPublicKey = {key}\nAllowedIPs = {ips}\n\n' + output = None try: - # Just load required settings here but keep the database unlocked + # Just load the settings here but keep the database unlocked # while we load group memberships from LDAP. with db.locked(): - ipsets = db.read('ipsets') settings = db.read('settings') + groups = db.read('groups') - # Build LDAP query for users and groups. - filters = [ - '(objectClass=user)', # only users - '(objectCategory=person)', # that are people - '(!(userAccountControl:1.2.840.113556.1.4.803:=2))', # with enabled accounts - ] - if group := settings.get('user_group'): - filters += [f'(memberOf:1.2.840.113556.1.4.1941:={group})'] # in given group, recursively - - # Run query and store group membership data. - server = ldap3.Server(settings['ldap_host'], use_ssl=True) - ldap = ldap3.Connection(server, settings['ldap_user'], settings['ldap_pass'], auto_bind=True) + # For each user build a list of networks they have access to, based on + # group membership in AD. Only query groups associated with at least one + # network, and query each group only once. + user_networks = collections.defaultdict(set) + ldap = ldap3.Connection(ldap3.Server(settings.get('ldap_host'), use_ssl=True), + settings.get('ldap_user'), settings.get('ldap_pass'), auto_bind=True) ldap.search(settings.get('ldap_base_dn', ''), - f'(&{"".join(filters)})', # conjuction (&(…)(…)(…)) of queries - attributes=['userPrincipalName', 'memberOf']) - user_groups = { e.userPrincipalName.value: set(e.memberOf) for e in ldap.entries } + '(&(objectClass=user)(objectCategory=person)' + # only people + '(!(userAccountControl:1.2.840.113556.1.4.803:=2))' + # with enabled accounts + f'(memberOf:1.2.840.113556.1.4.1941:={settings.get("user_group", "")}))', # in given group, recursively + attributes=['userPrincipalName', 'memberOf']) + for entry in ldap.entries: + for group in entry.memberOf: + if group in groups: + user_networks[entry.userPrincipalName.value].add(groups[group]) - # Now read the settings again while keeping the database locked until - # config files are generated, and increment version before unlocking. + # Now read the settings again and lock the database while generating + # config files, then increment version before unlocking. with db.locked(): - ipsets = db.read('ipsets') - wireguard = db.read('wireguard') settings = db.read('settings') - version = settings['version'] = int(settings.get('version') or '0') + 1 + version = settings['version'] = int(settings.get('version', 0)) + 1 - # Update IP sets with VPN addresses based on AD group membership. - vpn_groups = set([e['vpn'] for e in ipsets.values() if e.get('vpn')]) - group_networks = { - group: [name for name, data in ipsets.items() if data['vpn'] == group] for group in vpn_groups - } + # Populate IP sets. + ipsets = collections.defaultdict(set) + # Sets corresponding to VLANs in NetBox. Prefixes for these sets are configured on firewall nodes with ansible. + for name, network in db.read('networks').items(): + ipset_add(ipsets, name) + # Sets defined by user in friwall app. + for name, network in db.read('ipsets').items(): + ipset_add(ipsets, name, network.get('ip'), network.get('ip6')) + + # Add registered VPN addresses for each network based on + # LDAP group membership. + wireguard = db.read('wireguard') for ip, key in wireguard.items(): - for group in user_groups.get(key.get('user', ''), ()): - for network in group_networks.get(group, ()): - ipsets[network]['ip'].append(f'{ip}/32') - if ip6 := key.get('ip6'): - ipsets[network]['ip6'].append(ip6) + ip4 = [f'{ip}/32'] + ip6 = [f'{key["ip6"]}'] if key.get('ip6') else None + for network in user_networks.get(key.get('user', ''), ()): + ipset_add(ipsets, network, ip4, ip6) # Create config files. output = pathlib.Path.home() / 'config' / f'{version}' @@ -101,70 +114,51 @@ def save_config(): # Print nftables sets. with open(output / 'etc/nftables.d/sets.nft', 'w', encoding='utf-8') as f: - nft_set = 'set {name} {{\n type ipv4_addr; flags interval; {ips}\n}}\n' - nft_set6 = 'set {name}/6 {{\n type ipv6_addr; flags interval; {ips}\n}}\n' - def make_set(ips): - # return "elements = { ip1, ip2, … }", prefixed with "# " if no ips - return f'{"" if ips else "# "}elements = {{ {", ".join(ips)} }}' - for name, data in ipsets.items(): - f.write(nft_set.format(name=name, ips=make_set(data.get('ip', ())))) - f.write(nft_set6.format(name=name, ips=make_set(data.get('ip6', ())))) - f.write('\n') + for name, ips in ipsets.items(): + f.write(nft_set.format( + name=name, + family='6' if name.endswith('/6') else '4', + elements=f'{"" if ips else "# "}elements = {{ {", ".join(ips)} }}')) # Print static NAT (1:1) rules. with open(output / 'etc/nftables.d/netmap.nft', 'w', encoding='utf-8') as f: - nft_map = 'map {name} {{\n type ipv4_addr : interval ipv4_addr; flags interval; elements = {{\n{ips}\n }}\n}}\n' - def make_map(ips, reverse=False): - # return "{ from1: to1, from2: to2, … }" with possibly reversed from and to - return ',\n'.join(f"{b if reverse else a}: {a if reverse else b}" for a, b in ips) - if netmap := db.read('netmap'): # { private range: public range… } - f.write(nft_map.format(name='netmap-out', ips=make_map(netmap.items()))) - f.write('\n') - f.write(nft_map.format(name='netmap-in', ips=make_map(netmap.items(), reverse=True))) + netmap = db.read('netmap') # { private range: public range… } + if netmap: + f.write(nft_map.format( + name='netmap-out', + elements='elements = {' + ',\n'.join(f'{a}: {b}' for a, b in netmap.items()) + '}')) + f.write(nft_map.format( + name='netmap-in', + elements='elements = {' + ',\n'.join(f'{b}: {a}' for a, b in netmap.items()) + '}')) # Print dynamic NAT rules. with open(output / 'etc/nftables.d/nat.nft', 'w', encoding='utf-8') as f: - nft_nat = 'iif @inside oif @outside ip saddr @{name} snat to {nat}\n' - for name, data in ipsets.items(): - if nat := data.get('nat'): - f.write(nft_nat.format(name=name, nat=nat)) + nat = db.read('nat') # { network name: public range… } + for network, address in nat.items(): + if address: + f.write(f'iif @inside oif @outside ip saddr @{network} snat to {address}\n') # Print forwarding rules. with open(output / 'etc/nftables.d/forward.nft', 'w', encoding='utf-8') as f: - # Forwarding rules for VPN users. - if vpn_networks := sorted(name for name, data in ipsets.items() if data.get('vpn')): - nft_forward = 'iif @inside oif @inside ip saddr @{name} ip daddr @{name} accept\n' - nft_forward6 = 'iif @inside oif @inside ip6 saddr @{name}/6 ip6 daddr @{name}/6 accept\n' - f.write('# forward from the VPN interface to physical networks and back\n') - for name in vpn_networks: - f.write(nft_forward.format(name=name)) - for name in vpn_networks: - f.write(nft_forward6.format(name=name)) - f.write('\n') - - # Custom forwarding rules. - nft_rule = '# {index}. {name}\n{text}\n\n' for index, rule in enumerate(db.read('rules')): if rule.get('enabled') and rule.get('text'): - f.write(nft_rule.format(index=index, name=rule.get('name', ''), text=rule['text'])) + f.write(nft_forward.format(index=index, name=rule.get('name', ''), text=rule['text'])) # Print wireguard config. with open(output / 'etc/wireguard/wg.conf', 'w', encoding='utf-8') as f: - # Server configuration. - wg_intf = '[Interface]\nListenPort = {port}\nPrivateKey = {key}\n\n' - f.write(wg_intf.format(port=settings.get('wg_port') or 51820, key=settings.get('wg_key'))) - - # Client configuration. - wg_peer = '# {user}\n[Peer]\nPublicKey = {key}\nAllowedIPs = {ips}\n\n' + f.write(wg_intf.format( + port=settings.get('wg_port', 51820), + key=settings.get('wg_key'))) for ip, data in wireguard.items(): f.write(wg_peer.format( user=data.get('user'), key=data.get('key'), ips=', '.join(filter(None, [ip, data.get('ip6')])))) - # Make a temporary config archive and move it to the final location, - # so we avoid sending incomplete tars. + # Make a config archive in a temporary place, so we don’t send incomplete tars. tar_file = shutil.make_archive(f'{output}-tmp', 'gztar', root_dir=output, owner='root', group='root') + + # Move config archive to the final destination. os.rename(tar_file, f'{output}.tar.gz') # If we get here, write settings with the new version. diff --git a/web/templates/base.html b/web/templates/base.html index add9ed1..2da3f8f 100644 --- a/web/templates/base.html +++ b/web/templates/base.html @@ -27,13 +27,11 @@ h1 > a { color: unset; text-decoration: none; } -input:read-only { - border-style: dotted; -} pre { background-color: #eeeeee; - border: 1px solid #cccccc; + border: 1px solid black; padding: 0.5em; + margin: 0; } th { text-align: left; @@ -41,9 +39,6 @@ th { th, td { padding-right: 1em; } -th { - border-bottom: 1px solid black; -} ul.keys { margin: 0 0.5em 0.5em; padding-left: 1em; @@ -53,8 +48,6 @@ ul.keys a { } -{% block header %}{% endblock %} - FRIwall {% if current_user.is_authenticated %} diff --git a/web/templates/index.html b/web/templates/index.html index 01320ba..27b8375 100644 --- a/web/templates/index.html +++ b/web/templates/index.html @@ -14,14 +14,18 @@
Status
status opek v požarnem zidu -
Omrežja -
območja IP, naslovi NAT in skupine za VPN -
Pravila -
pravila za posredovanje prometa -
Netmap -
statične 1:1 preslikave naslovov za strežniška omrežja
Nastavitve
nastavitve aplikacije FRIwall +
Območja IP +
definicije območij IP +
Urejanje pravil +
pravila za posredovanje prometa +
NAT +
javni naslovi za pisarniška omrežja +
Netmap +
statične 1:1 preslikave naslovov za strežniška omrežja +
Skupine +
preslikave uporabnikov LDAP v pisarniška omrežja
{% endif %} diff --git a/web/templates/ipsets/index.html b/web/templates/ipsets/index.html index 7164f87..6e80bad 100644 --- a/web/templates/ipsets/index.html +++ b/web/templates/ipsets/index.html @@ -1,41 +1,25 @@ {% extends 'base.html' %} -{% block header %} - -{% endblock %} {% block content %}

-Urejate območja IP za posredovalna pravila na požarnem zidu. - -

-NAT se izvaja za notranja omrežja, kjer je nastavljen. Če nastavimo skupino AD, bodo omrežju dodane naprave, ki so jih v VPN povezali uporabniki v tej skupini. Vse naprave v posameznem omrežju so dostopne med sabo in za njih veljajo ista posredovalna pravila. - -

-Imen in naslovnih prostorov fizičnih omrežij ne moremo spreminjati. Za svoja omrežja lahko definiramo vsa polja. Omrežje odstranimo tako, da mu pobrišemo ime. +Urejate območja IP. Za vsako območje lahko dodate enega ali več obsegov IP in/ali IPv6, ločenih s presledki.

- +
- -{% for name, data in ipsets.items() %} + +{% for name, addresses in ipsets.items() %} - -
OmrežjeIPIPv6NATVPN +ImeIPIPv6
- - - - + + + {% endfor %}
- - - - + + +

diff --git a/web/templates/nat/index.html b/web/templates/nat/index.html new file mode 100644 index 0000000..1c2244d --- /dev/null +++ b/web/templates/nat/index.html @@ -0,0 +1,19 @@ +{% extends 'base.html' %} + +{% block content %} +

+Urejate naslove NAT za pisarniška omrežja. + +

+ + +{% for office, address in nat.items() %} + +
+ +{% endfor %} +
+

+

+ +{% endblock %} diff --git a/web/templates/rules/edit.html b/web/templates/rules/edit.html index 36b487c..2e26e1e 100644 --- a/web/templates/rules/edit.html +++ b/web/templates/rules/edit.html @@ -1,70 +1,36 @@ {% extends 'base.html' %} -{% block header %} - -{% endblock %} {% block content %}

-Urejate pravilo #{{ index }} (seznam pravil). Pravila so vključena v nftables filter chain na požarnem zidu. Povzetek filtrov najdemo v dokumentaciji. +Urejate pravilo #{{ index }}. V pravilih lahko uporabljate imena območij IP, prikazana spodaj. Seznam pravil. +


- +

- -
+Uporabniki, ki lahko o(ne)mogočijo pravilo
{% for manager in rule.managers %}
{% endfor %} - +

- +

-
- -

-Promet z naslova src iz zunanjega omrežja na naslov dst na notranjem dovolimo z - -

iif @outside oif @inside ip saddr src ip daddr dst accept
- -

-Za naslova src in dst lahko uporabimo definirana omrežja, prikazana v spodnji tabeli. Za omrežje net uporabimo oznaki @net in @net/6 za naslove IPv4 in IPv6. Da npr. preprečimo povezave iz omrežja classroom izven omrežja FRI, uporabimo pravili - -

iif @inside ip saddr @classroom ip daddr != @fri drop
-iif @inside ip6 saddr @classroom/6 ip6 daddr != @fri/6 drop
- - +
- -{% for name, data in ipsets.items() %} +{% for network, addresses in ipsets.items() %} -
Omrežje -IP -IPv6 -VPN +ObmočjeIPIPv6
{{ name }} -{{ data.ip|join('
')|safe }} -
{{ data.ip6|join('
')|safe }} -
{{ data.vpn }} +{{ network }} +{{ addresses.ip|join('
')|safe }} +
{{ addresses.ip6|join('
')|safe }} {% endfor %}
diff --git a/web/templates/rules/index.html b/web/templates/rules/index.html index fe62c35..a0a638b 100644 --- a/web/templates/rules/index.html +++ b/web/templates/rules/index.html @@ -2,12 +2,10 @@ {% block content %}

-Urejate posredovalna pravila. Pravila razvrstimo s stolpcem N. Če vrednost pobrišemo, pravilo odstranimo. +Urejate prioritete pravil za požarni zid. Pravilo odstranite tako, da izbrišete pripadajočo številko. V zadnji vrstici lahko dodate novo pravilo.

- - {% for rule in rules %} @@ -17,7 +15,7 @@ Urejate posredovalna pravila. Pravila razvrstimo s stolpcem N. Če vred {% endfor %}
NPravilo
- +

diff --git a/web/templates/rules/manage.html b/web/templates/rules/manage.html index bc770fb..4ceaaf0 100644 --- a/web/templates/rules/manage.html +++ b/web/templates/rules/manage.html @@ -1,33 +1,20 @@ {% extends 'base.html' %} -{% block header %} - -{% endblock %} - {% block content %}

Tu lahko vklopite in izklopite posamezna pravila za požarni zid. -

{% for rule in rules %}
- - -{{ rule.name }} +{% if rule.enabled %} + {{ rule.name }} izklopi +{% else %} + {{ rule.name }} vklopi +{% endif %}
{{ rule.text }}
{% endfor %} -

- -

{% endblock %} diff --git a/web/templates/vpn/index.html b/web/templates/vpn/index.html index 473704d..a65bdad 100644 --- a/web/templates/vpn/index.html +++ b/web/templates/vpn/index.html @@ -2,33 +2,24 @@ {% block content %}

-Za VPN oziroma oddeljano povezavo v omrežje FRI uporabljamo WireGuard. Več informacij o uporabi in nastavitvah VPN najdete v dokumentaciji. - -

-Za priklop v omrežje spodaj ustvarite nov ključ in prenesite izpisano datoteko. Nato sledite napotkom za posamezni sistem. +Za oddeljano povezavo v omrežje FRI namestite WireGuard, ustvarite ključ in sledite napotkom za posamezni sistem.

Windows / Mac

-Namestite in zaženite WireGuard za Windows ali Mac. Kliknite Import tunnel(s) from file in izberite preneseno datoteko z nastavitvami wg-fri.conf. VPN nato aktivirate oziroma deaktivirate s klikom na gumb (De)activate. +Zaženite WireGuard, kliknite Import tunnel(s) from file in izberite preneseno datoteko z nastavitvami. VPN nato (de)aktivirate s klikom na gumb (De)activate.

Android / iOS

-Namestite WireGuard za Android ali iOS. Zaženite WireGuard, dodajte novo povezavo z Import from file in izberite preneseno datoteko z nastavitvami. - -

-Ključ lahko ustvarite tudi na računalniku in ga v telefon dodate s Scan from QR code s kodo, prikazano ob novem ključu. +Zaženite WireGuard, izberite Scan from QR code in skenirajte kodo, prikazano ob izdelavi novega ključa.

Linux / BSD

-Nastavitve shranite (kot skrbnik) v /etc/wireguard/wg-fri.conf. VPN nato (de)aktivirate s sudo wg-quick up wg-fri oz. sudo wg-quick down wg-fri. - -

-Povezavo lahko uvozite tudi v NetworkManager z ukazom nmcli connection import type wireguard file wg-fri.conf. +Nastavitve shranite (kot skrbnik) v /etc/wireguard/wg-fri.conf. VPN nato (de)aktivirate s sudo wg-quick up wg-fri oz. sudo wg-quick down wg-fri. Povezavo lahko uvozite tudi v NetworkManager ali podobno.

@@ -36,21 +27,19 @@ Povezavo lahko uvozite tudi v NetworkManager z ukazom nmcli connection imp

-Na vsaki napravi, ki jo želite povezati v omrežje FRI, ustvarite nov ključ. Privzete nastavitve usmerijo čez VPN le promet, namenjen strežnikom na FRI in UL. +Vnesite poljubno oznako in kliknite Ustvari ključ. Če vklopite prvo opcijo, bo vaš računalnik čez VPN usmeril ves mrežni promet, ne le tistega, ki je namenjen strežnikom na FRI. Če izklopite drugo opcijo, bodo nekatere storitve dostopne le prek naslova IP. Če ste v dvomih, pustite privzete nastavitve.


- - +


-

-Če vklopite prvo opcijo, bo vaš računalnik čez VPN usmerjal ves promet. Če izklopite drugo opcijo, bodo nekateri strežniki dostopni le prek naslova IP. Če ste v dvomih, pustite privzete nastavitve. +

diff --git a/web/vpn.py b/web/vpn.py index ce82fe4..8a5b818 100644 --- a/web/vpn.py +++ b/web/vpn.py @@ -50,7 +50,7 @@ def new(): server_pubkey = subprocess.run([f'wg pubkey'], input=settings.get('wg_key'), text=True, capture_output=True, shell=True).stdout.strip() - host = ipaddress.ip_interface(settings.get('wg_net') or '10.0.0.1/24') + host = ipaddress.ip_interface(settings.get('wg_net', '10.0.0.1/24')) ip6 = None with db.locked(): # Find a free address for the new key. @@ -63,7 +63,7 @@ def new(): else: return flask.Response('no more available IP addresses', status=500, mimetype='text/plain') now = datetime.datetime.utcnow() - name = re.sub('[^-._A-Za-z0-9]', '', flask.request.json.get('name', '')) + name = re.sub('[^\w ]', '', flask.request.json.get('name', '')) keys[str(ip)] = { 'key': pubkey, @@ -80,7 +80,7 @@ def new(): # Template arguments. args = { 'server': settings.get('wg_endpoint'), - 'port': settings.get('wg_port') or '51820', + 'port': settings.get('wg_port', '51820'), 'server_key': server_pubkey, 'pubkey': pubkey, 'ip': str(ip), @@ -88,7 +88,7 @@ def new(): 'timestamp': now, 'name': name, 'dns': settings.get('wg_dns') if flask.request.json.get('use_dns', True) else False, - 'allowed_nets': settings.get('wg_allowed_nets', ''), + 'allowed_nets': settings.get('wg_allowed_nets', []), 'add_default': flask.request.json.get('add_default', False), } return flask.render_template('vpn/wg-fri.conf', **args)