Skip to content

Commit

Permalink
Merge pull request #44 from freeflowuniverse/development_wg
Browse files Browse the repository at this point in the history
Add SAL for wireguard
  • Loading branch information
Mahmoud-Emad authored Feb 2, 2025
2 parents 5a8ad0a + 749fa94 commit c886f85
Show file tree
Hide file tree
Showing 13 changed files with 620 additions and 0 deletions.
8 changes: 8 additions & 0 deletions examples/develop/wireguard/wg0.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[Interface]
Address = 10.10.3.0/24
PrivateKey = wDewSiri8jlaGnUDN6SwK7QhN082U7gfX27YMGILvVA=
[Peer]
PublicKey = 2JEGJQ8FbajdFk0fFs/881H/D3FRjwlUxvNDZFxDeWQ=
AllowedIPs = 10.10.0.0/16, 100.64.0.0/16
PersistentKeepalive = 25
Endpoint = 185.206.122.31:3241
35 changes: 35 additions & 0 deletions examples/develop/wireguard/wireguard.vsh
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
#!/usr/bin/env -S v -n -w -gc none -no-retry-compilation -d use_openssl -enable-globals run

import freeflowuniverse.herolib.clients.wireguard
import freeflowuniverse.herolib.installers.net.wireguard as wireguard_installer
import time
import os

mut wg_installer := wireguard_installer.get()!
wg_installer.install()!

// Create Wireguard client
mut wg := wireguard.get()!
config_file_path := '${os.dir(@FILE)}/wg0.conf'

wg.start(config_file_path: config_file_path)!
println('${config_file_path} is started')

time.sleep(time.second * 2)

info := wg.show()!
println('info: ${info}')

config := wg.show_config(interface_name: 'wg0')!
println('config: ${config}')

private_key := wg.generate_private_key()!
println('private_key: ${private_key}')

public_key := wg.get_public_key(private_key: private_key)!
println('public_key: ${public_key}')

wg.down(config_file_path: config_file_path)!
println('${config_file_path} is down')

wg_installer.destroy()!
8 changes: 8 additions & 0 deletions lib/clients/wireguard/.heroscript
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@

!!hero_code.generate_client
name:'wireguard'
classname:'WireGuard'
singleton:0
default:1
hasconfig:1
reset:0
114 changes: 114 additions & 0 deletions lib/clients/wireguard/client.v
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
module wireguard

import os

pub struct WGPeer {
pub mut:
endpoint string
allowed_ips string
latest_handshake string
transfer string
persistent_keepalive string
}

pub struct WGInterface {
pub mut:
name string
public_key string
listening_port int
}

pub struct WGInfo {
pub mut:
interface_ WGInterface
peers map[string]WGPeer
}

pub struct WGShow {
pub mut:
configs map[string]WGInfo
}

pub fn (wg WireGuard) show() !WGShow {
cmd := 'sudo wg show'
res := os.execute(cmd)
if res.exit_code != 0 {
return error('failed to execute show command due to: ${res.output}')
}

return wg.parse_show_command_output(res.output)
}

@[params]
pub struct ShowConfigArgs {
pub:
interface_name string @[required]
}

pub fn (wg WireGuard) show_config(args ShowConfigArgs) !WGInfo {
configs := wg.show()!.configs
config := configs[args.interface_name] or {
return error('key ${args.interface_name} does not exists.')
}
return config
}

@[params]
pub struct StartArgs {
pub:
config_file_path string @[required]
}

pub fn (wg WireGuard) start(args StartArgs) ! {
if !os.exists(args.config_file_path) {
return error('File ${args.config_file_path} does not exists.')
}

cmd := 'sudo wg-quick up ${args.config_file_path}'
res := os.execute(cmd)
if res.exit_code != 0 {
return error('failed to execute start command due to: ${res.output}')
}
}

@[params]
pub struct DownArgs {
pub:
config_file_path string @[required]
}

pub fn (wg WireGuard) down(args DownArgs) ! {
if !os.exists(args.config_file_path) {
return error('File ${args.config_file_path} does not exists.')
}

cmd := 'sudo wg-quick down ${args.config_file_path}'
res := os.execute(cmd)
if res.exit_code != 0 {
return error('failed to execute down command due to: ${res.output}')
}
}

pub fn (wg WireGuard) generate_private_key() !string {
cmd := 'wg genkey'
res := os.execute(cmd)
if res.exit_code != 0 {
return error('failed to execute genkey command due to: ${res.output}')
}
return res.output.trim_space()
}

@[params]
pub struct GetPublicKeyArgs {
pub:
private_key string @[required]
}

pub fn (wg WireGuard) get_public_key(args GetPublicKeyArgs) !string {
cmd := 'echo ${args.private_key} | wg pubkey'
res := os.execute(cmd)
if res.exit_code != 0 {
return error('failed to execute pubkey command due to: ${res.output}')
}
return res.output.trim_space()
}
30 changes: 30 additions & 0 deletions lib/clients/wireguard/readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# wireguard



To get started

```vlang
import freeflowuniverse.herolib.clients. wireguard
mut client:= wireguard.get()!
client...
```

## example heroscript

```hero
!!wireguard.configure
secret: '...'
host: 'localhost'
port: 8888
```


72 changes: 72 additions & 0 deletions lib/clients/wireguard/utils.v
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
module wireguard

fn (wg WireGuard) parse_show_command_output(res string) !WGShow {
mut configs := map[string]WGInfo{}
mut lines := res.split('\n')
mut current_interface := ''
mut current_peers := map[string]WGPeer{}
mut iface := WGInterface{}
mut peer_key := ''

for line in lines {
mut parts := line.trim_space().split(': ')
if parts.len < 2 {
continue
}

key := parts[0]
value := parts[1]

if key.starts_with('interface') {
if current_interface != '' {
configs[current_interface] = WGInfo{
interface_: iface
peers: current_peers.clone()
}
current_peers.clear()
}

current_interface = value
iface = WGInterface{
name: current_interface
public_key: ''
listening_port: 0
}
} else if key == 'public key' {
iface.public_key = value
} else if key == 'listening port' {
iface.listening_port = value.int()
} else if key.starts_with('peer') {
peer_key = value
mut peer := WGPeer{
endpoint: ''
allowed_ips: ''
latest_handshake: ''
transfer: ''
persistent_keepalive: ''
}
current_peers[peer_key] = peer
} else if key == 'endpoint' {
current_peers[peer_key].endpoint = value
} else if key == 'allowed ips' {
current_peers[peer_key].allowed_ips = value
} else if key == 'latest handshake' {
current_peers[peer_key].latest_handshake = value
} else if key == 'transfer' {
current_peers[peer_key].transfer = value
} else if key == 'persistent keepalive' {
current_peers[peer_key].persistent_keepalive = value
}
}

if current_interface != '' {
configs[current_interface] = WGInfo{
interface_: iface
peers: current_peers.clone()
}
}

return WGShow{
configs: configs
}
}
102 changes: 102 additions & 0 deletions lib/clients/wireguard/wireguard_factory_.v
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
module wireguard

import freeflowuniverse.herolib.core.base
import freeflowuniverse.herolib.core.playbook

__global (
wireguard_global map[string]&WireGuard
wireguard_default string
)

/////////FACTORY

@[params]
pub struct ArgsGet {
pub mut:
name string
}

fn args_get(args_ ArgsGet) ArgsGet {
mut args := args_
if args.name == '' {
args.name = wireguard_default
}
if args.name == '' {
args.name = 'wireguard'
}
return args
}

pub fn get(args_ ArgsGet) !&WireGuard {
mut args := args_get(args_)
if args.name !in wireguard_global {
if args.name == 'wireguard' {
if !config_exists(args) {
if default {
println('When saving')
config_save(args)!
}
}
config_load(args)!
}
}
return wireguard_global[args.name] or {
println(wireguard_global)
panic('could not get config for wireguard with name:${args.name}')
}
}

fn config_exists(args_ ArgsGet) bool {
mut args := args_get(args_)
mut context := base.context() or { panic('bug') }
return context.hero_config_exists('wireguard', args.name)
}

fn config_load(args_ ArgsGet) ! {
mut args := args_get(args_)
mut context := base.context()!
mut heroscript := context.hero_config_get('wireguard', args.name)!
play(heroscript: heroscript)!
}

fn config_save(args_ ArgsGet) ! {
mut args := args_get(args_)
mut context := base.context()!
context.hero_config_set('wireguard', args.name, heroscript_default()!)!
}

fn set(o WireGuard) ! {
mut o2 := obj_init(o)!
wireguard_global[o.name] = &o2
wireguard_default = o.name
}

@[params]
pub struct PlayArgs {
pub mut:
heroscript string // if filled in then plbook will be made out of it
plbook ?playbook.PlayBook
reset bool
}

pub fn play(args_ PlayArgs) ! {
mut args := args_

if args.heroscript == '' {
args.heroscript = heroscript_default()!
}
mut plbook := args.plbook or { playbook.new(text: args.heroscript)! }

mut install_actions := plbook.find(filter: 'wireguard.configure')!
if install_actions.len > 0 {
for install_action in install_actions {
mut p := install_action.params
cfg_play(p)!
}
}
}

// switch instance to be used for wireguard
pub fn switch(name string) {
wireguard_default = name
}
Loading

0 comments on commit c886f85

Please sign in to comment.