| line | stmt | bran | cond | sub | pod | time | code | 
| 1 |  |  |  |  |  |  | package Wireguard::WGmeta::Cli::Commands::Add; | 
| 2 | 1 |  |  | 1 |  | 7 | use strict; | 
|  | 1 |  |  |  |  | 2 |  | 
|  | 1 |  |  |  |  | 33 |  | 
| 3 | 1 |  |  | 1 |  | 6 | use warnings FATAL => 'all'; | 
|  | 1 |  |  |  |  | 2 |  | 
|  | 1 |  |  |  |  | 32 |  | 
| 4 |  |  |  |  |  |  |  | 
| 5 | 1 |  |  | 1 |  | 6 | use experimental 'signatures'; | 
|  | 1 |  |  |  |  | 2 |  | 
|  | 1 |  |  |  |  | 5 |  | 
| 6 |  |  |  |  |  |  |  | 
| 7 | 1 |  |  | 1 |  | 88 | use parent 'Wireguard::WGmeta::Cli::Commands::Command'; | 
|  | 1 |  |  |  |  | 2 |  | 
|  | 1 |  |  |  |  | 4 |  | 
| 8 |  |  |  |  |  |  |  | 
| 9 | 1 |  |  | 1 |  | 194 | use Wireguard::WGmeta::Wrapper::Bridge; | 
|  | 1 |  |  |  |  | 2 |  | 
|  | 1 |  |  |  |  | 119 |  | 
| 10 | 1 |  |  | 1 |  | 44 | use Wireguard::WGmeta::ValidAttributes; | 
|  | 1 |  |  |  |  | 4 |  | 
|  | 1 |  |  |  |  | 169 |  | 
| 11 | 1 |  |  | 1 |  | 10 | use Wireguard::WGmeta::Parser::Middleware; | 
|  | 1 |  |  |  |  | 1 |  | 
|  | 1 |  |  |  |  | 871 |  | 
| 12 |  |  |  |  |  |  |  | 
| 13 | 0 |  |  | 0 | 1 |  | sub entry_point($self) { | 
|  | 0 |  |  |  |  |  |  | 
|  | 0 |  |  |  |  |  |  | 
| 14 | 0 | 0 |  |  |  |  | if ($self->_retrieve_or_die($self->{input_args}, 0) eq 'help') { | 
| 15 | 0 |  |  |  |  |  | $self->cmd_help(); | 
| 16 |  |  |  |  |  |  | } | 
| 17 | 0 |  |  |  |  |  | $self->check_privileges(); | 
| 18 |  |  |  |  |  |  | # read input parameters | 
| 19 | 0 |  |  |  |  |  | my $len = @{$self->{input_args}}; | 
|  | 0 |  |  |  |  |  |  | 
| 20 | 0 |  |  |  |  |  | $self->{interface} = $self->_retrieve_or_die($self->{input_args}, 0); | 
| 21 | 0 |  |  |  |  |  | $self->{ips} = $self->_retrieve_or_die($self->{input_args}, 1); | 
| 22 | 0 | 0 |  |  |  |  | if ($len > 2) { | 
| 23 |  |  |  |  |  |  | # We hav additional arguments | 
| 24 | 0 |  |  |  |  |  | my @additional_args = @{$self->{input_args}}[2 .. $len - 1]; | 
|  | 0 |  |  |  |  |  |  | 
| 25 | 0 | 0 |  |  |  |  | die 'Uneven number of elements (one pair would be without value!)' if scalar @additional_args % 2 != 0; | 
| 26 | 0 |  |  |  |  |  | $self->{additional_args} = \@additional_args; | 
| 27 |  |  |  |  |  |  | } | 
| 28 |  |  |  |  |  |  | # generate private/public keypair | 
| 29 | 0 |  |  |  |  |  | my ($privkey, $pubkey) = gen_keypair(); | 
| 30 | 0 |  |  |  |  |  | $self->{pub_key} = $pubkey; | 
| 31 | 0 |  |  |  |  |  | $self->{priv_key} = $privkey; | 
| 32 |  |  |  |  |  |  |  | 
| 33 | 0 |  |  |  |  |  | $self->_run_command(); | 
| 34 |  |  |  |  |  |  | } | 
| 35 |  |  |  |  |  |  |  | 
| 36 |  |  |  |  |  |  |  | 
| 37 | 0 |  |  | 0 |  |  | sub _run_command($self) { | 
|  | 0 |  |  |  |  |  |  | 
|  | 0 |  |  |  |  |  |  | 
| 38 |  |  |  |  |  |  | my ($iface_privkey, $iface_listen) = $self->wg_meta->add_peer( | 
| 39 |  |  |  |  |  |  | $self->{interface}, | 
| 40 |  |  |  |  |  |  | $self->{ips}, | 
| 41 |  |  |  |  |  |  | $self->{pub_key} | 
| 42 | 0 |  |  |  |  |  | ); | 
| 43 |  |  |  |  |  |  | # get pubkey of iface priv-key | 
| 44 | 0 |  |  |  |  |  | my $iface_pubkey = get_pub_key($iface_privkey); | 
| 45 |  |  |  |  |  |  |  | 
| 46 |  |  |  |  |  |  | # get interface config | 
| 47 | 0 |  |  |  |  |  | my %host_interface = $self->wg_meta->get_interface_section($self->{interface}, $self->{interface}); | 
| 48 | 0 | 0 |  |  |  |  | my $fqdn = exists($host_interface{FQDN}) ? $host_interface{FQDN} : 'insert.valid.fqdn.not.valid'; | 
| 49 |  |  |  |  |  |  |  | 
| 50 |  |  |  |  |  |  | # lets create a temporary interface | 
| 51 | 0 |  |  |  |  |  | $self->wg_meta->add_interface('temp', $self->{ips}, 44544, $self->{priv_key}); | 
| 52 | 0 |  |  |  |  |  | $self->wg_meta->add_peer('temp', '0.0.0.0/0, ::/0', $iface_pubkey); | 
| 53 | 0 |  |  |  |  |  | $self->wg_meta->set('temp', $iface_pubkey, 'endpoint', "$fqdn:$iface_listen"); | 
| 54 | 0 | 0 |  |  |  |  | if (exists($host_interface{DNSHost})){ | 
| 55 | 0 |  |  |  |  |  | $self->wg_meta->set('temp', 'temp', 'dns', $host_interface{DNSHost}); | 
| 56 |  |  |  |  |  |  | } | 
| 57 | 0 |  |  |  |  |  | $self->wg_meta->set('temp', $iface_pubkey, 'persistent-keepalive', 25); | 
| 58 |  |  |  |  |  |  |  | 
| 59 | 0 |  |  | 0 |  |  | my $unknown_handler_temp = sub($attribute, $value) { | 
|  | 0 |  |  |  |  |  |  | 
|  | 0 |  |  |  |  |  |  | 
|  | 0 |  |  |  |  |  |  | 
| 60 | 0 |  |  |  |  |  | my $prefix = substr $attribute, 0, 1; | 
| 61 | 0 | 0 |  |  |  |  | $prefix eq '+' ? return (substr $attribute, 1), $value : return $attribute, $value; | 
| 62 | 0 |  |  |  |  |  | }; | 
| 63 |  |  |  |  |  |  |  | 
| 64 | 0 | 0 |  |  |  |  | if (defined $self->{additional_args}) { | 
| 65 | 0 |  |  |  |  |  | my @additional_args = @{$self->{additional_args}}; | 
|  | 0 |  |  |  |  |  |  | 
| 66 | 0 |  |  |  |  |  | for (my $i = 0; $i < scalar @additional_args; $i += 2) { | 
| 67 | 0 |  |  |  |  |  | my $attribute = $additional_args[$i]; | 
| 68 | 0 |  |  |  |  |  | my $value = $additional_args[$i + 1]; | 
| 69 | 0 |  |  |  |  |  | my $attr_type = get_attr_type($attribute); | 
| 70 | 0 | 0 |  |  |  |  | if ($attr_type == ATTR_TYPE_IS_WG_META) { | 
|  |  | 0 |  |  |  |  |  | 
| 71 | 0 |  |  |  |  |  | $self->wg_meta->set($self->{interface}, $self->{pub_key}, $attribute, $value); | 
| 72 | 0 |  |  |  |  |  | $self->wg_meta->set('temp', 'temp', $attribute, $value); | 
| 73 |  |  |  |  |  |  | } | 
| 74 |  |  |  |  |  |  | elsif ($attr_type == ATTR_TYPE_IS_WG_ORIG_INTERFACE) { | 
| 75 | 0 |  |  |  |  |  | $self->wg_meta->set('temp', 'temp', $attribute, $value); | 
| 76 |  |  |  |  |  |  | } | 
| 77 |  |  |  |  |  |  | else { | 
| 78 | 0 |  |  |  |  |  | $self->wg_meta->set($self->{interface}, $self->{pub_key}, $attribute, $value, \&Wireguard::WGmeta::Cli::Commands::Command::_unknown_attr_handler); | 
| 79 | 0 | 0 |  |  |  |  | $self->wg_meta->set('temp', 'temp', $attribute, $value, $unknown_handler_temp) if $attr_type != ATTR_TYPE_IS_WG_ORIG_PEER; | 
| 80 |  |  |  |  |  |  | } | 
| 81 |  |  |  |  |  |  |  | 
| 82 |  |  |  |  |  |  | } | 
| 83 |  |  |  |  |  |  | } | 
| 84 |  |  |  |  |  |  |  | 
| 85 | 0 |  |  |  |  |  | print "#Generated by wg-meta\n" . $self->wg_meta->create_config('temp', 0); | 
| 86 |  |  |  |  |  |  | # remove our temp interface again | 
| 87 | 0 |  |  |  |  |  | $self->wg_meta->remove_interface('temp'); | 
| 88 | 0 |  |  |  |  |  | $self->wg_meta->commit(1); | 
| 89 |  |  |  |  |  |  | } | 
| 90 |  |  |  |  |  |  |  | 
| 91 | 0 |  |  | 0 | 1 |  | sub cmd_help($self) { | 
|  | 0 |  |  |  |  |  |  | 
|  | 0 |  |  |  |  |  |  | 
| 92 | 0 |  |  |  |  |  | print "Usage: wg-meta addpeer   [attr1 value1] [attr2 value2] ...\n\n" | 
| 93 |  |  |  |  |  |  | . "Notes: \nAttributes meant to reside in the [Interface] section are only applied to the peer's interface\n" | 
| 94 |  |  |  |  |  |  | . "wg-meta attributes are applied to the host's peer config and the client interface config\n" | 
| 95 |  |  |  |  |  |  | . "and finally, attributes meant to be in the [Peer] section are only applied to the host's peer entry.\n\n" | 
| 96 |  |  |  |  |  |  | . "To automatically fill in dns and endpoint name, make sure #+DNSHost and #+FQDN is present in [Interface]\n" | 
| 97 |  |  |  |  |  |  | . "Do not forget to reload the configuration afterwards!\n"; | 
| 98 |  |  |  |  |  |  |  | 
| 99 | 0 |  |  |  |  |  | exit(); | 
| 100 |  |  |  |  |  |  | } | 
| 101 |  |  |  |  |  |  |  | 
| 102 |  |  |  |  |  |  | 1; |