Subversion Repositories web_pages

Rev

Rev 14 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 14 Rev 16
Line 21... Line 21...
21
# TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
21
# TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
22
# BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22
# BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
23
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
24
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
24
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
25
# DAMAGE.
25
# DAMAGE.
-
 
26
#
-
 
27
# Library to interface with the OPNsense API
-
 
28
# Provides methods to interact with OPNsense routers via their API.
-
 
29
#
-
 
30
# Change History:
-
 
31
#  v1.0.0 2025-10-01 - RWR
-
 
32
#    Initial version
26
 
33
 
27
package opnsense;
34
package opnsense;
28
 
-
 
29
use strict;
35
use strict;
30
use warnings;
36
use warnings;
31
 
37
 
32
use LWP::UserAgent;
38
use LWP::UserAgent;
33
use JSON;
39
use JSON;
34
use Data::Dumper;
40
use Data::Dumper;
35
use XML::Simple;
41
use XML::Simple;
36
 
42
 
-
 
43
our $VERSION = "1.0.0";
37
 
44
 
38
our $USE_CURL = 1; # set to 1 to use curl for API requests, 0 to use LWP
45
our $useCurl = 1; # set to 1 to use curl for API requests, 0 to use LWP
39
our $DEBUG = 0;    # set to 1 for debug output
46
our $debug = 0;    # set to 1 for debug output
40
 
47
 
-
 
48
#-----------------------------
-
 
49
# new: Constructor
-
 
50
#-----------------------------
41
sub new {
51
sub new {
42
    my ($class, %args) = @_;
52
   my ($class, %args) = @_;
43
    my $self = {
53
   my $self = {
44
        base_url => $args{url},
54
      baseUrl   => $args{url},
45
        apiKey  => $args{apiKey},
55
      apiKey    => $args{apiKey},
46
        apiSecret => $args{apiSecret},
56
      apiSecret => $args{apiSecret},
47
        ovpnIndex => $args{ovpnIndex},
57
      ovpnIndex => $args{ovpnIndex},
48
        template => $args{template},
58
      template  => $args{template},
49
        hostname => $args{hostname},
59
      hostname  => $args{hostname},
50
        localport => $args{localport},
60
      localPort => $args{localPort},
51
        ua => $USE_CURL ? 
61
      ua        => $useCurl ?
52
           'curl -s --insecure' :
62
         'curl -s --insecure' :
53
           LWP::UserAgent->new(
63
         LWP::UserAgent->new(
54
              ssl_opts => { verify_hostname => 0, SSL_verify_mode => 0 }
64
            ssl_opts => { verify_hostname => 0, SSL_verify_mode => 0 }
55
           ),
65
         ),
56
    };
66
   };
57
    bless $self, $class;
67
   bless $self, $class;
58
    return $self;
68
   return $self;
59
}
69
}
60
 
70
 
-
 
71
#-----------------------------
-
 
72
# apiRequest: API request dispatcher
-
 
73
#-----------------------------
61
sub api_request {
74
sub apiRequest {
62
 
75
 
63
   if ( $USE_CURL ) {
76
   if ($useCurl) {
64
       return api_request_curl(@_);
77
       return apiRequestCurl(@_);
65
   } else {
78
   } else {
66
       return api_request_lwp(@_);
79
       return apiRequestLwp(@_);
67
   }
80
   }
68
}
81
}
69
 
82
 
-
 
83
#-----------------------------
-
 
84
# apiRequestCurl: API request using curl
-
 
85
#-----------------------------
70
sub api_request_curl {
86
sub apiRequestCurl {
71
   my ($self, $endpoint, $method, $data) = @_;
87
   my ($self, $endpoint, $method, $data) = @_;
72
   $method ||= 'GET';
88
   $method ||= 'GET';
73
   my $url = $self->{base_url} . $endpoint;
89
   my $url = $self->{baseUrl} . $endpoint;
74
 
90
 
75
   my @data = ();
91
   my @data = ();
76
   push @data, '--request', $method;
92
   push @data, '--request', $method;
77
   push @data, "--header 'Content-Type: application/json'" if ( $method eq 'POST' || $method eq 'PUT' );
93
   push @data, "--header 'Content-Type: application/json'" if ( $method eq 'POST' || $method eq 'PUT' );
78
   push @data, "--user '$self->{apiKey}:$self->{apiSecret}'";
94
   push @data, "--user '$self->{apiKey}:$self->{apiSecret}'";
79
   push @data, "--data '" . encode_json($data) . "'" if $data;
95
   push @data, "--data '" . encode_json($data) . "'" if $data;
80
   my $cmd = join(' ', $self->{ua}, @data, $url);
96
   my $cmd = join(' ', $self->{ua}, @data, $url);
81
   die "In api_request_curl, command is:\n $cmd" if $DEBUG;
97
   die "In apiRequestCurl, command is:\n $cmd" if $debug;
82
   my $json_text = `$cmd`;
98
   my $json_text = `$cmd`;
83
   if ( $json_text =~ /<\?xml/) {
99
   if ( $json_text =~ /<\?xml/) {
84
      # returned an XML string, just send it
100
      # returned an XML string, just send it
85
      return $json_text;
101
      return $json_text;
86
   }
102
   }
87
   return decode_json($json_text);
103
   return decode_json($json_text);
88
}
104
}
89
 
105
 
90
 
106
 
-
 
107
#-----------------------------
-
 
108
# apiRequestLwp: API request using LWP
-
 
109
#-----------------------------
91
sub api_request_lwp {
110
sub apiRequestLwp {
92
    my ($self, $endpoint, $method, $data) = @_;
111
    my ($self, $endpoint, $method, $data) = @_;
93
    $method ||= 'GET';
112
    $method ||= 'GET';
94
    my $url = $self->{base_url} . $endpoint;
113
    my $url = $self->{baseUrl} . $endpoint;
95
    my $req = HTTP::Request->new($method => $url);
114
    my $req = HTTP::Request->new($method => $url);
96
    $req->header('Content-Type' => 'application/json');
115
    $req->header('Content-Type' => 'application/json');
97
    $req->header('Authorization' => 'key ' . $self->{apiKey} . ':' . $self->{apiSecret});
116
    $req->header('Authorization' => 'key ' . $self->{apiKey} . ':' . $self->{apiSecret});
98
    die "In api_request_lwp, request object:\n" . Dumper($req);
117
    die "In apiRequestLwp, request object:\n" . Dumper($req);
99
    $req->content(encode_json($data)) if $data;
118
    $req->content(encode_json($data)) if $data;
100
    my $res = $self->{ua}->request($req);
119
    my $res = $self->{ua}->request($req);
101
    return decode_json($res->decoded_content) if $res->is_success;
120
    return decode_json($res->decoded_content) if $res->is_success;
102
    die "API request failed: " . $res->status_line;
121
    die "API request failed: " . $res->status_line;
103
 
122
 
104
}
123
}
105
 
124
 
-
 
125
#-----------------------------
-
 
126
# getVpnUsers: get VPN users
-
 
127
#-----------------------------
106
sub get_vpn_users {
128
sub getVpnUsers {
107
    my ($self) = @_;
129
    my ($self) = @_;
108
    my $return = {};
130
    my $return = {};
109
    my $endpoint = "/api/openvpn/export/accounts/$self->{ovpnIndex}";
131
    my $endpoint = "/api/openvpn/export/accounts/$self->{ovpnIndex}";
110
    my $users = $self->api_request($endpoint);
132
    my $users = $self->apiRequest($endpoint);
111
    # die "In get_vpn_users, users object:\n" . Dumper($users);
133
    # die "In get_vpn_users, users object:\n" . Dumper($users);
112
    foreach my $user ( keys %$users ) {
134
    foreach my $user ( keys %$users ) {
113
      next unless
135
      next unless
114
         $user && 
136
         $user && 
115
         $users->{$user}->{'users'} &&
137
         $users->{$user}->{'users'} &&
Line 120... Line 142...
120
    }
142
    }
121
    #die Dumper($return);
143
    #die Dumper($return);
122
    return $return;
144
    return $return;
123
}
145
}
124
 
146
 
-
 
147
#-----------------------------
125
# get all users on the system
148
# getAllUsers: get all users on the system
-
 
149
#-----------------------------
126
# returns a hashref keyed by username, value is the user object
150
# returns a hashref keyed by username, value is the user object
127
# The api is seriously broken. It is supposed to be /api/system/user, but that returns an error
151
# The api is seriously broken. It is supposed to be /api/system/user, but that returns an error
128
# so, we download the entire config and extract the users from there
152
# so, we download the entire config and extract the users from there
129
sub get_all_users {
153
sub getAllUsers {
130
    my ($self) = @_;
154
    my ($self) = @_;
131
    my $endpoint = "/api/core/backup/download/this";
155
    my $endpoint = "/api/core/backup/download/this";
132
    my $xml = XML::Simple->new();
156
    my $xml = XML::Simple->new();
133
    my $data = $self->api_request($endpoint);
157
    my $data = $self->apiRequest($endpoint);
134
    my $config = $xml->XMLin($data);
158
    my $config = $xml->XMLin($data);
135
    my $return = {};
159
    my $return = {};
136
    if (ref($config->{system}->{user}) eq 'ARRAY') {
160
    if (ref($config->{system}->{user}) eq 'ARRAY') {
137
        foreach my $user (@{$config->{system}->{user}}) {
161
        foreach my $user (@{$config->{system}->{user}}) {
138
            $return->{$user->{name}} = $user;
162
            $return->{$user->{name}} = $user;
Line 141... Line 165...
141
        $return = $config->{system}->{user};
165
        $return = $config->{system}->{user};
142
    }
166
    }
143
    return $return;
167
    return $return;
144
}
168
}
145
 
169
 
-
 
170
#-----------------------------
-
 
171
# getVpnProviders: get VPN providers
-
 
172
#-----------------------------
146
sub get_vpn_providers {
173
sub getVpnProviders {
147
   my ($self) = @_;
174
   my ($self) = @_;
148
   my $endpoint = "/api/openvpn/export/providers";
175
   my $endpoint = "/api/openvpn/export/providers";
149
   my $return = {};
176
   my $return = {};
150
   my $providers = $self->api_request($endpoint);
177
   my $providers = $self->apiRequest($endpoint);
151
   #die "In getVPNProviders, providers object:\n" . Dumper($providers);
178
   #die "In getVPNProviders, providers object:\n" . Dumper($providers);
152
   return $return unless
179
   return $return unless
153
      ref($providers) eq 'HASH' && keys %$providers;
180
      ref($providers) eq 'HASH' && keys %$providers;
154
    # key by vpnid, value is name
181
    # key by vpnid, value is name
155
   foreach my $provider ( keys %$providers ) {
182
   foreach my $provider ( keys %$providers ) {
156
       $return->{$providers->{$provider}->{'vpnid'}} = $providers->{$provider}->{'name'};
183
       $return->{$providers->{$provider}->{'vpnid'}} = $providers->{$provider}->{'name'};
157
    }
184
    }
158
   return $return; 
185
   return $return; 
159
}
186
}
160
 
187
 
161
###
188
#-----------------------------
162
# get VPN configuration file
189
# getVpnConfig: get VPN configuration file
-
 
190
#-----------------------------
163
sub get_vpn_config {
191
sub getVpnConfig {
164
   my ( $self, $cert ) = @_;
192
   my ( $self, $cert ) = @_;
165
   my $endpoint = "/api/openvpn/export/download/$self->{ovpnIndex}/$cert";
193
   my $endpoint = "/api/openvpn/export/download/$self->{ovpnIndex}/$cert";
166
   my $payload = ();
194
   my $payload = ();
167
   $payload->{'openvpn_export'} = {
195
   $payload->{'openvpn_export'} = {
168
       validate_server_cn => 1,
196
       validate_server_cn => 1,
Line 175... Line 203...
175
       plain_config => "",
203
       plain_config => "",
176
       p12_password => "",
204
       p12_password => "",
177
       local_port => $self->{localport},
205
       local_port => $self->{localport},
178
       cryptoapi => 0
206
       cryptoapi => 0
179
   };
207
   };
180
   $DEBUG = 0;
208
   $debug = 0;
181
   my $return = $self->api_request($endpoint, 'POST', $payload);
209
   my $return = $self->apiRequest($endpoint, 'POST', $payload);
182
   return $return;
210
   return $return;
183
}
211
}
184
 
212
 
185
 
213
 
186
1;
214
1;