Merge pull request #37 from wzooff/feat/add-custom-client-config-template
add option to specify custom user template path
This commit is contained in:
commit
ace42f729e
3 changed files with 320 additions and 282 deletions
24
.editorconfig
Normal file
24
.editorconfig
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
|
||||||
|
; https://editorconfig.org/
|
||||||
|
|
||||||
|
root = true
|
||||||
|
|
||||||
|
[*]
|
||||||
|
insert_final_newline = true
|
||||||
|
charset = utf-8
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 2
|
||||||
|
|
||||||
|
[{Makefile,go.mod,go.sum,*.go,.gitmodules}]
|
||||||
|
indent_style = tab
|
||||||
|
indent_size = 4
|
||||||
|
|
||||||
|
[*.md]
|
||||||
|
indent_size = 4
|
||||||
|
trim_trailing_whitespace = false
|
||||||
|
|
||||||
|
eclint_indent_style = unset
|
||||||
|
|
||||||
|
[Dockerfile]
|
||||||
|
indent_size = 4
|
|
@ -94,6 +94,9 @@ Flags:
|
||||||
path to easyrsa index file.
|
path to easyrsa index file.
|
||||||
--ccd Enable client-config-dir.
|
--ccd Enable client-config-dir.
|
||||||
--ccd.path="./ccd" path to client-config-dir
|
--ccd.path="./ccd" path to client-config-dir
|
||||||
|
--templates.clientconfig-path=""
|
||||||
|
path to custom client.config.tpl file
|
||||||
|
--templates.ccd-path="" path to custom ccd.tpl file
|
||||||
--auth.password Enable additional password authorization.
|
--auth.password Enable additional password authorization.
|
||||||
--auth.db="./easyrsa/pki/users.db"
|
--auth.db="./easyrsa/pki/users.db"
|
||||||
Database path fort password authorization.
|
Database path fort password authorization.
|
||||||
|
|
575
main.go
575
main.go
|
@ -5,9 +5,6 @@ import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
|
||||||
"github.com/prometheus/client_golang/prometheus/promhttp"
|
|
||||||
"gopkg.in/alecthomas/kingpin.v2"
|
|
||||||
"log"
|
"log"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
@ -19,73 +16,77 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/gobuffalo/packr/v2"
|
"github.com/gobuffalo/packr/v2"
|
||||||
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
|
"github.com/prometheus/client_golang/prometheus/promhttp"
|
||||||
|
|
||||||
|
"gopkg.in/alecthomas/kingpin.v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
usernameRegexp = `^([a-zA-Z0-9_.-@])+$`
|
usernameRegexp = `^([a-zA-Z0-9_.-@])+$`
|
||||||
passwordRegexp = `^([a-zA-Z0-9_.-@])+$`
|
passwordRegexp = `^([a-zA-Z0-9_.-@])+$`
|
||||||
passwordMinLength = 6
|
passwordMinLength = 6
|
||||||
downloadCertsApiUrl = "/api/data/certs/download"
|
downloadCertsApiUrl = "/api/data/certs/download"
|
||||||
downloadCcdApiUrl = "/api/data/ccd/download"
|
downloadCcdApiUrl = "/api/data/ccd/download"
|
||||||
certsArchiveFileName = "certs.tar.gz"
|
certsArchiveFileName = "certs.tar.gz"
|
||||||
ccdArchiveFileName = "ccd.tar.gz"
|
ccdArchiveFileName = "ccd.tar.gz"
|
||||||
indexTxtDateLayout = "060102150405Z"
|
indexTxtDateLayout = "060102150405Z"
|
||||||
stringDateFormat = "2006-01-02 15:04:05"
|
stringDateFormat = "2006-01-02 15:04:05"
|
||||||
ovpnStatusDateLayout = "2006-01-02 15:04:05"
|
ovpnStatusDateLayout = "2006-01-02 15:04:05"
|
||||||
version = "1.6.2"
|
version = "1.6.3"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
listenHost = kingpin.Flag("listen.host","host for ovpn-admin").Default("0.0.0.0").String()
|
listenHost = kingpin.Flag("listen.host", "host for ovpn-admin").Default("0.0.0.0").String()
|
||||||
listenPort = kingpin.Flag("listen.port","port for ovpn-admin").Default("8080").String()
|
listenPort = kingpin.Flag("listen.port", "port for ovpn-admin").Default("8080").String()
|
||||||
serverRole = kingpin.Flag("role","server role master or slave").Default("master").HintOptions("master", "slave").String()
|
serverRole = kingpin.Flag("role", "server role master or slave").Default("master").HintOptions("master", "slave").String()
|
||||||
masterHost = kingpin.Flag("master.host","url for master server").Default("http://127.0.0.1").String()
|
masterHost = kingpin.Flag("master.host", "url for master server").Default("http://127.0.0.1").String()
|
||||||
masterBasicAuthUser = kingpin.Flag("master.basic-auth.user","user for basic auth on master server url").Default("").String()
|
masterBasicAuthUser = kingpin.Flag("master.basic-auth.user", "user for basic auth on master server url").Default("").String()
|
||||||
masterBasicAuthPassword = kingpin.Flag("master.basic-auth.password","password for basic auth on master server url").Default("").String()
|
masterBasicAuthPassword = kingpin.Flag("master.basic-auth.password", "password for basic auth on master server url").Default("").String()
|
||||||
masterSyncFrequency = kingpin.Flag("master.sync-frequency", "master host data sync frequency in seconds.").Default("600").Int()
|
masterSyncFrequency = kingpin.Flag("master.sync-frequency", "master host data sync frequency in seconds.").Default("600").Int()
|
||||||
masterSyncToken = kingpin.Flag("master.sync-token", "master host data sync security token").Default("VerySecureToken").PlaceHolder("TOKEN").String()
|
masterSyncToken = kingpin.Flag("master.sync-token", "master host data sync security token").Default("VerySecureToken").PlaceHolder("TOKEN").String()
|
||||||
openvpnNetwork = kingpin.Flag("ovpn.network","network for openvpn server").Default("172.16.100.0/24").String()
|
openvpnNetwork = kingpin.Flag("ovpn.network", "network for openvpn server").Default("172.16.100.0/24").String()
|
||||||
openvpnServer = kingpin.Flag("ovpn.server","comma separated addresses for openvpn servers").Default("127.0.0.1:7777:tcp").PlaceHolder("HOST:PORT:PROTOCOL").Strings()
|
openvpnServer = kingpin.Flag("ovpn.server", "comma separated addresses for openvpn servers").Default("127.0.0.1:7777:tcp").PlaceHolder("HOST:PORT:PROTOCOL").Strings()
|
||||||
mgmtAddress = kingpin.Flag("mgmt","comma separated (alias=address) for openvpn servers mgmt interfaces").Default("main=127.0.0.1:8989").Strings()
|
mgmtAddress = kingpin.Flag("mgmt", "comma separated (alias=address) for openvpn servers mgmt interfaces").Default("main=127.0.0.1:8989").Strings()
|
||||||
metricsPath = kingpin.Flag("metrics.path", "URL path for surfacing collected metrics").Default("/metrics").String()
|
metricsPath = kingpin.Flag("metrics.path", "URL path for surfacing collected metrics").Default("/metrics").String()
|
||||||
easyrsaDirPath = kingpin.Flag("easyrsa.path", "path to easyrsa dir").Default("./easyrsa/").String()
|
easyrsaDirPath = kingpin.Flag("easyrsa.path", "path to easyrsa dir").Default("./easyrsa/").String()
|
||||||
indexTxtPath = kingpin.Flag("easyrsa.index-path", "path to easyrsa index file.").Default("./easyrsa/pki/index.txt").String()
|
indexTxtPath = kingpin.Flag("easyrsa.index-path", "path to easyrsa index file.").Default("./easyrsa/pki/index.txt").String()
|
||||||
ccdEnabled = kingpin.Flag("ccd", "Enable client-config-dir.").Default("false").Bool()
|
ccdEnabled = kingpin.Flag("ccd", "Enable client-config-dir.").Default("false").Bool()
|
||||||
ccdDir = kingpin.Flag("ccd.path", "path to client-config-dir").Default("./ccd").String()
|
ccdDir = kingpin.Flag("ccd.path", "path to client-config-dir").Default("./ccd").String()
|
||||||
authByPassword = kingpin.Flag("auth.password", "Enable additional password authorization.").Default("false").Bool()
|
clientConfigTemplatePath = kingpin.Flag("templates.clientconfig-path", "path to custom client.conf.tpl").Default("").String()
|
||||||
authDatabase = kingpin.Flag("auth.db", "Database path fort password authorization.").Default("./easyrsa/pki/users.db").String()
|
ccdTemplatePath = kingpin.Flag("templates.ccd-path", "path to custom ccd.tpl").Default("").String()
|
||||||
debug = kingpin.Flag("debug", "Enable debug mode.").Default("false").Bool()
|
authByPassword = kingpin.Flag("auth.password", "Enable additional password authorization.").Default("false").Bool()
|
||||||
verbose = kingpin.Flag("verbose", "Enable verbose mode.").Default("false").Bool()
|
authDatabase = kingpin.Flag("auth.db", "Database path fort password authorization.").Default("./easyrsa/pki/users.db").String()
|
||||||
|
debug = kingpin.Flag("debug", "Enable debug mode.").Default("false").Bool()
|
||||||
certsArchivePath = "/tmp/" + certsArchiveFileName
|
verbose = kingpin.Flag("verbose", "Enable verbose mode.").Default("false").Bool()
|
||||||
ccdArchivePath = "/tmp/" + ccdArchiveFileName
|
|
||||||
|
|
||||||
|
certsArchivePath = "/tmp/" + certsArchiveFileName
|
||||||
|
ccdArchivePath = "/tmp/" + ccdArchiveFileName
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|
||||||
ovpnServerCertExpire = prometheus.NewGauge(prometheus.GaugeOpts{
|
ovpnServerCertExpire = prometheus.NewGauge(prometheus.GaugeOpts{
|
||||||
Name: "ovpn_server_cert_expire",
|
Name: "ovpn_server_cert_expire",
|
||||||
Help: "openvpn server certificate expire time in days",
|
Help: "openvpn server certificate expire time in days",
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
ovpnServerCaCertExpire = prometheus.NewGauge(prometheus.GaugeOpts{
|
ovpnServerCaCertExpire = prometheus.NewGauge(prometheus.GaugeOpts{
|
||||||
Name: "ovpn_server_ca_cert_expire",
|
Name: "ovpn_server_ca_cert_expire",
|
||||||
Help: "openvpn server CA certificate expire time in days",
|
Help: "openvpn server CA certificate expire time in days",
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
ovpnClientsTotal = prometheus.NewGauge(prometheus.GaugeOpts{
|
ovpnClientsTotal = prometheus.NewGauge(prometheus.GaugeOpts{
|
||||||
Name: "ovpn_clients_total",
|
Name: "ovpn_clients_total",
|
||||||
Help: "total openvpn users",
|
Help: "total openvpn users",
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
ovpnClientsRevoked = prometheus.NewGauge(prometheus.GaugeOpts{
|
ovpnClientsRevoked = prometheus.NewGauge(prometheus.GaugeOpts{
|
||||||
Name: "ovpn_clients_revoked",
|
Name: "ovpn_clients_revoked",
|
||||||
Help: "revoked openvpn users",
|
Help: "revoked openvpn users",
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
ovpnClientsExpired = prometheus.NewGauge(prometheus.GaugeOpts{
|
ovpnClientsExpired = prometheus.NewGauge(prometheus.GaugeOpts{
|
||||||
|
@ -95,9 +96,9 @@ var (
|
||||||
)
|
)
|
||||||
|
|
||||||
ovpnClientsConnected = prometheus.NewGauge(prometheus.GaugeOpts{
|
ovpnClientsConnected = prometheus.NewGauge(prometheus.GaugeOpts{
|
||||||
Name: "ovpn_clients_connected",
|
Name: "ovpn_clients_connected",
|
||||||
Help: "connected openvpn users",
|
Help: "connected openvpn users",
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
ovpnClientCertificateExpire = prometheus.NewGaugeVec(prometheus.GaugeOpts{
|
ovpnClientCertificateExpire = prometheus.NewGaugeVec(prometheus.GaugeOpts{
|
||||||
|
@ -108,9 +109,9 @@ var (
|
||||||
)
|
)
|
||||||
|
|
||||||
ovpnClientConnectionInfo = prometheus.NewGaugeVec(prometheus.GaugeOpts{
|
ovpnClientConnectionInfo = prometheus.NewGaugeVec(prometheus.GaugeOpts{
|
||||||
Name: "ovpn_client_connection_info",
|
Name: "ovpn_client_connection_info",
|
||||||
Help: "openvpn user connection info. ip - assigned address from ovpn network. value - last time when connection was refreshed in unix format",
|
Help: "openvpn user connection info. ip - assigned address from ovpn network. value - last time when connection was refreshed in unix format",
|
||||||
},
|
},
|
||||||
[]string{"client", "ip"},
|
[]string{"client", "ip"},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -122,69 +123,68 @@ var (
|
||||||
)
|
)
|
||||||
|
|
||||||
ovpnClientBytesReceived = prometheus.NewGaugeVec(prometheus.GaugeOpts{
|
ovpnClientBytesReceived = prometheus.NewGaugeVec(prometheus.GaugeOpts{
|
||||||
Name: "ovpn_client_bytes_received",
|
Name: "ovpn_client_bytes_received",
|
||||||
Help: "openvpn user bytes received",
|
Help: "openvpn user bytes received",
|
||||||
},
|
},
|
||||||
[]string{"client"},
|
[]string{"client"},
|
||||||
)
|
)
|
||||||
|
|
||||||
ovpnClientBytesSent = prometheus.NewGaugeVec(prometheus.GaugeOpts{
|
ovpnClientBytesSent = prometheus.NewGaugeVec(prometheus.GaugeOpts{
|
||||||
Name: "ovpn_client_bytes_sent",
|
Name: "ovpn_client_bytes_sent",
|
||||||
Help: "openvpn user bytes sent",
|
Help: "openvpn user bytes sent",
|
||||||
},
|
},
|
||||||
[]string{"client"},
|
[]string{"client"},
|
||||||
)
|
)
|
||||||
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type OvpnAdmin struct {
|
type OvpnAdmin struct {
|
||||||
role string
|
role string
|
||||||
lastSyncTime string
|
lastSyncTime string
|
||||||
lastSuccessfulSyncTime string
|
lastSuccessfulSyncTime string
|
||||||
masterHostBasicAuth bool
|
masterHostBasicAuth bool
|
||||||
masterSyncToken string
|
masterSyncToken string
|
||||||
clients []OpenvpnClient
|
clients []OpenvpnClient
|
||||||
activeClients []clientStatus
|
activeClients []clientStatus
|
||||||
promRegistry *prometheus.Registry
|
promRegistry *prometheus.Registry
|
||||||
mgmtInterfaces map[string]string
|
mgmtInterfaces map[string]string
|
||||||
templates *packr.Box
|
templates *packr.Box
|
||||||
modules []string
|
modules []string
|
||||||
}
|
}
|
||||||
|
|
||||||
type OpenvpnServer struct {
|
type OpenvpnServer struct {
|
||||||
Host string
|
Host string
|
||||||
Port string
|
Port string
|
||||||
Protocol string
|
Protocol string
|
||||||
}
|
}
|
||||||
|
|
||||||
type openvpnClientConfig struct {
|
type openvpnClientConfig struct {
|
||||||
Hosts []OpenvpnServer
|
Hosts []OpenvpnServer
|
||||||
CA string
|
CA string
|
||||||
Cert string
|
Cert string
|
||||||
Key string
|
Key string
|
||||||
TLS string
|
TLS string
|
||||||
PasswdAuth bool
|
PasswdAuth bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type OpenvpnClient struct {
|
type OpenvpnClient struct {
|
||||||
Identity string `json:"Identity"`
|
Identity string `json:"Identity"`
|
||||||
AccountStatus string `json:"AccountStatus"`
|
AccountStatus string `json:"AccountStatus"`
|
||||||
ExpirationDate string `json:"ExpirationDate"`
|
ExpirationDate string `json:"ExpirationDate"`
|
||||||
RevocationDate string `json:"RevocationDate"`
|
RevocationDate string `json:"RevocationDate"`
|
||||||
ConnectionStatus string `json:"ConnectionStatus"`
|
ConnectionStatus string `json:"ConnectionStatus"`
|
||||||
ConnectionServer string `json:"ConnectionServer"`
|
ConnectionServer string `json:"ConnectionServer"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ccdRoute struct {
|
type ccdRoute struct {
|
||||||
Address string `json:"Address"`
|
Address string `json:"Address"`
|
||||||
Mask string `json:"Mask"`
|
Mask string `json:"Mask"`
|
||||||
Description string `json:"Description"`
|
Description string `json:"Description"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Ccd struct {
|
type Ccd struct {
|
||||||
User string `json:"User"`
|
User string `json:"User"`
|
||||||
ClientAddress string `json:"ClientAddress"`
|
ClientAddress string `json:"ClientAddress"`
|
||||||
CustomRoutes []ccdRoute `json:"CustomRoutes"`
|
CustomRoutes []ccdRoute `json:"CustomRoutes"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type indexTxtLine struct {
|
type indexTxtLine struct {
|
||||||
|
@ -229,13 +229,13 @@ func (oAdmin *OvpnAdmin) userCreateHandler(w http.ResponseWriter, r *http.Reques
|
||||||
r.ParseForm()
|
r.ParseForm()
|
||||||
userCreated, userCreateStatus := oAdmin.userCreate(r.FormValue("username"), r.FormValue("password"))
|
userCreated, userCreateStatus := oAdmin.userCreate(r.FormValue("username"), r.FormValue("password"))
|
||||||
|
|
||||||
if userCreated {
|
if userCreated {
|
||||||
w.WriteHeader(http.StatusOK)
|
w.WriteHeader(http.StatusOK)
|
||||||
fmt.Fprintf(w, userCreateStatus)
|
fmt.Fprintf(w, userCreateStatus)
|
||||||
return
|
return
|
||||||
} else {
|
} else {
|
||||||
http.Error(w, userCreateStatus, http.StatusUnprocessableEntity)
|
http.Error(w, userCreateStatus, http.StatusUnprocessableEntity)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (oAdmin *OvpnAdmin) userRevokeHandler(w http.ResponseWriter, r *http.Request) {
|
func (oAdmin *OvpnAdmin) userRevokeHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
@ -271,7 +271,7 @@ func (oAdmin *OvpnAdmin) userChangePasswordHandler(w http.ResponseWriter, r *htt
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
http.Error(w, `{"status":"error"}`, http.StatusNotImplemented )
|
http.Error(w, `{"status":"error"}`, http.StatusNotImplemented)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -283,7 +283,7 @@ func (oAdmin *OvpnAdmin) userShowConfigHandler(w http.ResponseWriter, r *http.Re
|
||||||
|
|
||||||
func (oAdmin *OvpnAdmin) userDisconnectHandler(w http.ResponseWriter, r *http.Request) {
|
func (oAdmin *OvpnAdmin) userDisconnectHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
r.ParseForm()
|
r.ParseForm()
|
||||||
// fmt.Fprintf(w, "%s", userDisconnect(r.FormValue("username")))
|
// fmt.Fprintf(w, "%s", userDisconnect(r.FormValue("username")))
|
||||||
fmt.Fprintf(w, "%s", r.FormValue("username"))
|
fmt.Fprintf(w, "%s", r.FormValue("username"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -298,32 +298,32 @@ func (oAdmin *OvpnAdmin) userApplyCcdHandler(w http.ResponseWriter, r *http.Requ
|
||||||
http.Error(w, `{"status":"error"}`, http.StatusLocked)
|
http.Error(w, `{"status":"error"}`, http.StatusLocked)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
var ccd Ccd
|
var ccd Ccd
|
||||||
if r.Body == nil {
|
if r.Body == nil {
|
||||||
http.Error(w, "Please send a request body", http.StatusBadRequest)
|
http.Error(w, "Please send a request body", http.StatusBadRequest)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
err := json.NewDecoder(r.Body).Decode(&ccd)
|
err := json.NewDecoder(r.Body).Decode(&ccd)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println(err)
|
log.Println(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
ccdApplied, applyStatus := oAdmin.modifyCcd(ccd)
|
ccdApplied, applyStatus := oAdmin.modifyCcd(ccd)
|
||||||
|
|
||||||
if ccdApplied {
|
if ccdApplied {
|
||||||
w.WriteHeader(http.StatusOK)
|
w.WriteHeader(http.StatusOK)
|
||||||
fmt.Fprintf(w, applyStatus)
|
fmt.Fprintf(w, applyStatus)
|
||||||
return
|
return
|
||||||
} else {
|
} else {
|
||||||
http.Error(w, applyStatus, http.StatusUnprocessableEntity)
|
http.Error(w, applyStatus, http.StatusUnprocessableEntity)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (oAdmin *OvpnAdmin) serverSettingsHandler(w http.ResponseWriter, r *http.Request) {
|
func (oAdmin *OvpnAdmin) serverSettingsHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
enabledModules, enabledModulesErr := json.Marshal(oAdmin.modules)
|
enabledModules, enabledModulesErr := json.Marshal(oAdmin.modules)
|
||||||
if enabledModulesErr != nil {
|
if enabledModulesErr != nil {
|
||||||
log.Printf("ERROR: %s\n",enabledModulesErr)
|
log.Printf("ERROR: %s\n", enabledModulesErr)
|
||||||
}
|
}
|
||||||
fmt.Fprintf(w, `{"status":"ok", "serverRole": "%s", "modules": %s }`, oAdmin.role, string(enabledModules))
|
fmt.Fprintf(w, `{"status":"ok", "serverRole": "%s", "modules": %s }`, oAdmin.role, string(enabledModules))
|
||||||
}
|
}
|
||||||
|
@ -350,8 +350,8 @@ func (oAdmin *OvpnAdmin) downloadCertsHandler(w http.ResponseWriter, r *http.Req
|
||||||
}
|
}
|
||||||
|
|
||||||
archiveCerts()
|
archiveCerts()
|
||||||
w.Header().Set("Content-Disposition", "attachment; filename=" + certsArchiveFileName)
|
w.Header().Set("Content-Disposition", "attachment; filename="+certsArchiveFileName)
|
||||||
http.ServeFile(w,r, certsArchivePath)
|
http.ServeFile(w, r, certsArchivePath)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (oAdmin *OvpnAdmin) downloadCcdHandler(w http.ResponseWriter, r *http.Request) {
|
func (oAdmin *OvpnAdmin) downloadCcdHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
@ -368,15 +368,14 @@ func (oAdmin *OvpnAdmin) downloadCcdHandler(w http.ResponseWriter, r *http.Reque
|
||||||
}
|
}
|
||||||
|
|
||||||
archiveCcd()
|
archiveCcd()
|
||||||
w.Header().Set("Content-Disposition", "attachment; filename=" + ccdArchiveFileName)
|
w.Header().Set("Content-Disposition", "attachment; filename="+ccdArchiveFileName)
|
||||||
http.ServeFile(w,r, ccdArchivePath)
|
http.ServeFile(w, r, ccdArchivePath)
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
kingpin.Version(version)
|
kingpin.Version(version)
|
||||||
kingpin.Parse()
|
kingpin.Parse()
|
||||||
|
|
||||||
|
|
||||||
ovpnAdmin := new(OvpnAdmin)
|
ovpnAdmin := new(OvpnAdmin)
|
||||||
ovpnAdmin.lastSyncTime = "unknown"
|
ovpnAdmin.lastSyncTime = "unknown"
|
||||||
ovpnAdmin.role = *serverRole
|
ovpnAdmin.role = *serverRole
|
||||||
|
@ -388,7 +387,7 @@ func main() {
|
||||||
ovpnAdmin.mgmtInterfaces = make(map[string]string)
|
ovpnAdmin.mgmtInterfaces = make(map[string]string)
|
||||||
|
|
||||||
for _, mgmtInterface := range *mgmtAddress {
|
for _, mgmtInterface := range *mgmtAddress {
|
||||||
parts := strings.SplitN(mgmtInterface, "=",2)
|
parts := strings.SplitN(mgmtInterface, "=", 2)
|
||||||
ovpnAdmin.mgmtInterfaces[parts[0]] = parts[len(parts)-1]
|
ovpnAdmin.mgmtInterfaces[parts[0]] = parts[len(parts)-1]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -415,7 +414,7 @@ func main() {
|
||||||
|
|
||||||
if ovpnAdmin.role == "slave" {
|
if ovpnAdmin.role == "slave" {
|
||||||
ovpnAdmin.syncDataFromMaster()
|
ovpnAdmin.syncDataFromMaster()
|
||||||
go ovpnAdmin.syncWithMaster()
|
go ovpnAdmin.syncWithMaster()
|
||||||
}
|
}
|
||||||
|
|
||||||
ovpnAdmin.templates = packr.New("template", "./templates")
|
ovpnAdmin.templates = packr.New("template", "./templates")
|
||||||
|
@ -447,7 +446,7 @@ func main() {
|
||||||
})
|
})
|
||||||
|
|
||||||
fmt.Println("Bind: http://" + *listenHost + ":" + *listenPort)
|
fmt.Println("Bind: http://" + *listenHost + ":" + *listenPort)
|
||||||
log.Fatal(http.ListenAndServe(*listenHost + ":" + *listenPort, nil))
|
log.Fatal(http.ListenAndServe(*listenHost+":"+*listenPort, nil))
|
||||||
}
|
}
|
||||||
|
|
||||||
func CacheControlWrapper(h http.Handler) http.Handler {
|
func CacheControlWrapper(h http.Handler) http.Handler {
|
||||||
|
@ -500,9 +499,9 @@ func indexTxtParser(txt string) []indexTxtLine {
|
||||||
switch {
|
switch {
|
||||||
// case strings.HasPrefix(str[0], "E"):
|
// case strings.HasPrefix(str[0], "E"):
|
||||||
case strings.HasPrefix(str[0], "V"):
|
case strings.HasPrefix(str[0], "V"):
|
||||||
indexTxt = append(indexTxt, indexTxtLine{Flag: str[0], ExpirationDate: str[1], SerialNumber: str[2], Filename: str[3], DistinguishedName: str[4], Identity: str[4][strings.Index(str[4], "=")+1:]})
|
indexTxt = append(indexTxt, indexTxtLine{Flag: str[0], ExpirationDate: str[1], SerialNumber: str[2], Filename: str[3], DistinguishedName: str[4], Identity: str[4][strings.Index(str[4], "=")+1:]})
|
||||||
case strings.HasPrefix(str[0], "R"):
|
case strings.HasPrefix(str[0], "R"):
|
||||||
indexTxt = append(indexTxt, indexTxtLine{Flag: str[0], ExpirationDate: str[1], RevocationDate: str[2], SerialNumber: str[3], Filename: str[4], DistinguishedName: str[5], Identity: str[5][strings.Index(str[5], "=")+1:]})
|
indexTxt = append(indexTxt, indexTxtLine{Flag: str[0], ExpirationDate: str[1], RevocationDate: str[2], SerialNumber: str[3], Filename: str[4], DistinguishedName: str[5], Identity: str[5][strings.Index(str[5], "=")+1:]})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -515,25 +514,37 @@ func renderIndexTxt(data []indexTxtLine) string {
|
||||||
for _, line := range data {
|
for _, line := range data {
|
||||||
switch {
|
switch {
|
||||||
case line.Flag == "V":
|
case line.Flag == "V":
|
||||||
indexTxt += fmt.Sprintf("%s\t%s\t\t%s\t%s\t%s\n", line.Flag, line.ExpirationDate, line.SerialNumber, line.Filename, line.DistinguishedName)
|
indexTxt += fmt.Sprintf("%s\t%s\t\t%s\t%s\t%s\n", line.Flag, line.ExpirationDate, line.SerialNumber, line.Filename, line.DistinguishedName)
|
||||||
case line.Flag == "R":
|
case line.Flag == "R":
|
||||||
indexTxt += fmt.Sprintf("%s\t%s\t%s\t%s\t%s\t%s\n", line.Flag, line.ExpirationDate, line.RevocationDate, line.SerialNumber, line.Filename, line.DistinguishedName)
|
indexTxt += fmt.Sprintf("%s\t%s\t%s\t%s\t%s\t%s\n", line.Flag, line.ExpirationDate, line.RevocationDate, line.SerialNumber, line.Filename, line.DistinguishedName)
|
||||||
// case line.flag == "E":
|
// case line.flag == "E":
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return indexTxt
|
return indexTxt
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (oAdmin *OvpnAdmin) getClientConfigTemplate() *template.Template {
|
||||||
|
if *clientConfigTemplatePath != "" {
|
||||||
|
return template.Must(template.ParseFiles(*clientConfigTemplatePath))
|
||||||
|
} else {
|
||||||
|
clientConfigTpl, clientConfigTplErr := oAdmin.templates.FindString("client.conf.tpl")
|
||||||
|
if clientConfigTplErr != nil {
|
||||||
|
log.Println("ERROR: clientConfigTpl not found in templates box")
|
||||||
|
}
|
||||||
|
return template.Must(template.New("client-config").Parse(clientConfigTpl))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (oAdmin *OvpnAdmin) renderClientConfig(username string) string {
|
func (oAdmin *OvpnAdmin) renderClientConfig(username string) string {
|
||||||
if checkUserExist(username) {
|
if checkUserExist(username) {
|
||||||
var hosts []OpenvpnServer
|
var hosts []OpenvpnServer
|
||||||
|
|
||||||
for _, server := range *openvpnServer {
|
for _, server := range *openvpnServer {
|
||||||
parts := strings.SplitN(server, ":",3)
|
parts := strings.SplitN(server, ":", 3)
|
||||||
hosts = append(hosts, OpenvpnServer{Host: parts[0], Port: parts[1], Protocol: parts[2]})
|
hosts = append(hosts, OpenvpnServer{Host: parts[0], Port: parts[1], Protocol: parts[2]})
|
||||||
}
|
}
|
||||||
if *debug {
|
if *debug {
|
||||||
log.Printf("WARNING: hosts for %s\n %v", username, hosts )
|
log.Printf("WARNING: hosts for %s\n %v", username, hosts)
|
||||||
}
|
}
|
||||||
|
|
||||||
conf := openvpnClientConfig{}
|
conf := openvpnClientConfig{}
|
||||||
|
@ -544,18 +555,14 @@ func (oAdmin *OvpnAdmin) renderClientConfig(username string) string {
|
||||||
conf.TLS = fRead(*easyrsaDirPath + "/pki/ta.key")
|
conf.TLS = fRead(*easyrsaDirPath + "/pki/ta.key")
|
||||||
conf.PasswdAuth = *authByPassword
|
conf.PasswdAuth = *authByPassword
|
||||||
|
|
||||||
clientConfigTpl, clientConfigTplErr := oAdmin.templates.FindString("client.conf.tpl")
|
t := oAdmin.getClientConfigTemplate()
|
||||||
if clientConfigTplErr != nil {
|
|
||||||
log.Println("ERROR: clientConfigTpl not found in templates box")
|
|
||||||
}
|
|
||||||
|
|
||||||
t := template.Must(template.New("client-config").Parse(clientConfigTpl))
|
|
||||||
var tmp bytes.Buffer
|
var tmp bytes.Buffer
|
||||||
err := t.Execute(&tmp, conf)
|
err := t.Execute(&tmp, conf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("WARNING: something goes wrong during rendering config for %s", username )
|
log.Printf("WARNING: something goes wrong during rendering config for %s", username)
|
||||||
if *debug {
|
if *debug {
|
||||||
log.Printf("ERROR: rendering config for %s failed \n %v", username, err )
|
log.Printf("ERROR: rendering config for %s failed \n %v", username, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -568,22 +575,34 @@ func (oAdmin *OvpnAdmin) renderClientConfig(username string) string {
|
||||||
return fmt.Sprintf("User \"%s\" not found", username)
|
return fmt.Sprintf("User \"%s\" not found", username)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (oAdmin *OvpnAdmin) getCcdTemplate() *template.Template {
|
||||||
|
if *ccdTemplatePath != "" {
|
||||||
|
return template.Must(template.ParseFiles(*ccdTemplatePath))
|
||||||
|
} else {
|
||||||
|
ccdTpl, ccdTplErr := oAdmin.templates.FindString("ccd.tpl")
|
||||||
|
if ccdTplErr != nil {
|
||||||
|
log.Printf("ERROR: ccdTpl not found in templates box")
|
||||||
|
}
|
||||||
|
return template.Must(template.New("ccd").Parse(ccdTpl))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (oAdmin *OvpnAdmin) parseCcd(username string) Ccd {
|
func (oAdmin *OvpnAdmin) parseCcd(username string) Ccd {
|
||||||
ccd := Ccd{}
|
ccd := Ccd{}
|
||||||
ccd.User = username
|
ccd.User = username
|
||||||
ccd.ClientAddress = "dynamic"
|
ccd.ClientAddress = "dynamic"
|
||||||
ccd.CustomRoutes = []ccdRoute{}
|
ccd.CustomRoutes = []ccdRoute{}
|
||||||
|
|
||||||
txtLinesArray := strings.Split(fRead(*ccdDir + "/" + username), "\n")
|
txtLinesArray := strings.Split(fRead(*ccdDir+"/"+username), "\n")
|
||||||
|
|
||||||
for _, v := range txtLinesArray {
|
for _, v := range txtLinesArray {
|
||||||
str := strings.Fields(v)
|
str := strings.Fields(v)
|
||||||
if len(str) > 0 {
|
if len(str) > 0 {
|
||||||
switch {
|
switch {
|
||||||
case strings.HasPrefix(str[0], "ifconfig-push"):
|
case strings.HasPrefix(str[0], "ifconfig-push"):
|
||||||
ccd.ClientAddress = str[1]
|
ccd.ClientAddress = str[1]
|
||||||
case strings.HasPrefix(str[0], "push"):
|
case strings.HasPrefix(str[0], "push"):
|
||||||
ccd.CustomRoutes = append(ccd.CustomRoutes, ccdRoute{Address: strings.Trim(str[2], "\""), Mask: strings.Trim(str[3], "\""), Description: strings.Trim(strings.Join(str[4:], ""), "#")})
|
ccd.CustomRoutes = append(ccd.CustomRoutes, ccdRoute{Address: strings.Trim(str[2], "\""), Mask: strings.Trim(str[3], "\""), Description: strings.Trim(strings.Join(str[4:], ""), "#")})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -594,85 +613,78 @@ func (oAdmin *OvpnAdmin) parseCcd(username string) Ccd {
|
||||||
func (oAdmin *OvpnAdmin) modifyCcd(ccd Ccd) (bool, string) {
|
func (oAdmin *OvpnAdmin) modifyCcd(ccd Ccd) (bool, string) {
|
||||||
ccdErr := "something goes wrong"
|
ccdErr := "something goes wrong"
|
||||||
|
|
||||||
if fCreate(*ccdDir + "/" + ccd.User) {
|
if fCreate(*ccdDir + "/" + ccd.User) {
|
||||||
ccdValid, ccdErr := validateCcd(ccd)
|
ccdValid, ccdErr := validateCcd(ccd)
|
||||||
if ccdErr != "" {
|
if ccdErr != "" {
|
||||||
return false, ccdErr
|
return false, ccdErr
|
||||||
}
|
}
|
||||||
|
|
||||||
if ccdValid {
|
if ccdValid {
|
||||||
ccdTpl, ccdTplErr := oAdmin.templates.FindString("ccd.tpl")
|
t := oAdmin.getCcdTemplate()
|
||||||
if ccdTplErr != nil {
|
var tmp bytes.Buffer
|
||||||
ccdErr = "ccdTpl not found in templates box"
|
tplErr := t.Execute(&tmp, ccd)
|
||||||
log.Printf("ERROR: %s\n",ccdErr)
|
|
||||||
return false, ccdErr
|
|
||||||
}
|
|
||||||
|
|
||||||
t := template.Must(template.New("ccd").Parse(ccdTpl))
|
|
||||||
var tmp bytes.Buffer
|
|
||||||
tplErr := t.Execute(&tmp, ccd)
|
|
||||||
if tplErr != nil {
|
if tplErr != nil {
|
||||||
log.Println(tplErr)
|
log.Println(tplErr)
|
||||||
}
|
}
|
||||||
fWrite(*ccdDir + "/" + ccd.User, tmp.String())
|
fWrite(*ccdDir+"/"+ccd.User, tmp.String())
|
||||||
return true, "ccd updated successfully"
|
return true, "ccd updated successfully"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false, ccdErr
|
return false, ccdErr
|
||||||
}
|
}
|
||||||
|
|
||||||
func validateCcd(ccd Ccd) (bool, string) {
|
func validateCcd(ccd Ccd) (bool, string) {
|
||||||
ccdErr := ""
|
ccdErr := ""
|
||||||
|
|
||||||
if ccd.ClientAddress != "dynamic" {
|
if ccd.ClientAddress != "dynamic" {
|
||||||
_, ovpnNet, err := net.ParseCIDR(*openvpnNetwork)
|
_, ovpnNet, err := net.ParseCIDR(*openvpnNetwork)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println(err)
|
log.Println(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if ! checkStaticAddressIsFree(ccd.ClientAddress, ccd.User) {
|
if !checkStaticAddressIsFree(ccd.ClientAddress, ccd.User) {
|
||||||
ccdErr = fmt.Sprintf("ClientAddress \"%s\" already assigned to another user", ccd.ClientAddress)
|
ccdErr = fmt.Sprintf("ClientAddress \"%s\" already assigned to another user", ccd.ClientAddress)
|
||||||
if *debug {
|
if *debug {
|
||||||
log.Printf("ERROR: Modify ccd for user %s: %s", ccd.User, ccdErr)
|
log.Printf("ERROR: Modify ccd for user %s: %s", ccd.User, ccdErr)
|
||||||
}
|
}
|
||||||
return false, ccdErr
|
return false, ccdErr
|
||||||
}
|
}
|
||||||
|
|
||||||
if net.ParseIP(ccd.ClientAddress) == nil {
|
if net.ParseIP(ccd.ClientAddress) == nil {
|
||||||
ccdErr = fmt.Sprintf("ClientAddress \"%s\" not a valid IP address", ccd.ClientAddress)
|
ccdErr = fmt.Sprintf("ClientAddress \"%s\" not a valid IP address", ccd.ClientAddress)
|
||||||
if *debug {
|
if *debug {
|
||||||
log.Printf("ERROR: Modify ccd for user %s: %s", ccd.User, ccdErr)
|
log.Printf("ERROR: Modify ccd for user %s: %s", ccd.User, ccdErr)
|
||||||
}
|
}
|
||||||
return false, ccdErr
|
return false, ccdErr
|
||||||
}
|
}
|
||||||
|
|
||||||
if ! ovpnNet.Contains(net.ParseIP(ccd.ClientAddress)) {
|
if !ovpnNet.Contains(net.ParseIP(ccd.ClientAddress)) {
|
||||||
ccdErr = fmt.Sprintf("ClientAddress \"%s\" not belongs to openvpn server network", ccd.ClientAddress)
|
ccdErr = fmt.Sprintf("ClientAddress \"%s\" not belongs to openvpn server network", ccd.ClientAddress)
|
||||||
if *debug {
|
if *debug {
|
||||||
log.Printf("ERROR: Modify ccd for user %s: %s", ccd.User, ccdErr)
|
log.Printf("ERROR: Modify ccd for user %s: %s", ccd.User, ccdErr)
|
||||||
}
|
}
|
||||||
return false, ccdErr
|
return false, ccdErr
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, route := range ccd.CustomRoutes {
|
for _, route := range ccd.CustomRoutes {
|
||||||
if net.ParseIP(route.Address) == nil {
|
if net.ParseIP(route.Address) == nil {
|
||||||
ccdErr = fmt.Sprintf("CustomRoute.Address \"%s\" must be a valid IP address", route.Address)
|
ccdErr = fmt.Sprintf("CustomRoute.Address \"%s\" must be a valid IP address", route.Address)
|
||||||
if *debug {
|
if *debug {
|
||||||
log.Printf("ERROR: Modify ccd for user %s: %s", ccd.User, ccdErr)
|
log.Printf("ERROR: Modify ccd for user %s: %s", ccd.User, ccdErr)
|
||||||
}
|
}
|
||||||
return false, ccdErr
|
return false, ccdErr
|
||||||
}
|
}
|
||||||
|
|
||||||
if net.ParseIP(route.Mask) == nil {
|
if net.ParseIP(route.Mask) == nil {
|
||||||
ccdErr = fmt.Sprintf("CustomRoute.Mask \"%s\" must be a valid IP address", route.Mask)
|
ccdErr = fmt.Sprintf("CustomRoute.Mask \"%s\" must be a valid IP address", route.Mask)
|
||||||
if *debug {
|
if *debug {
|
||||||
log.Printf("ERROR: Modify ccd for user %s: %s", ccd.User, ccdErr)
|
log.Printf("ERROR: Modify ccd for user %s: %s", ccd.User, ccdErr)
|
||||||
}
|
}
|
||||||
return false, ccdErr
|
return false, ccdErr
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true, ccdErr
|
return true, ccdErr
|
||||||
}
|
}
|
||||||
|
@ -683,19 +695,19 @@ func (oAdmin *OvpnAdmin) getCcd(username string) Ccd {
|
||||||
ccd.ClientAddress = "dynamic"
|
ccd.ClientAddress = "dynamic"
|
||||||
ccd.CustomRoutes = []ccdRoute{}
|
ccd.CustomRoutes = []ccdRoute{}
|
||||||
|
|
||||||
if fCreate(*ccdDir + "/" + username) {
|
if fCreate(*ccdDir + "/" + username) {
|
||||||
ccd = oAdmin.parseCcd(username)
|
ccd = oAdmin.parseCcd(username)
|
||||||
}
|
}
|
||||||
return ccd
|
return ccd
|
||||||
}
|
}
|
||||||
|
|
||||||
func checkStaticAddressIsFree(staticAddress string, username string) bool {
|
func checkStaticAddressIsFree(staticAddress string, username string) bool {
|
||||||
o := runBash(fmt.Sprintf("grep -rl %s %s | grep -vx %s/%s | wc -l", staticAddress, *ccdDir, *ccdDir, username))
|
o := runBash(fmt.Sprintf("grep -rl %s %s | grep -vx %s/%s | wc -l", staticAddress, *ccdDir, *ccdDir, username))
|
||||||
|
|
||||||
if strings.TrimSpace(o) == "0" {
|
if strings.TrimSpace(o) == "0" {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func validateUsername(username string) bool {
|
func validateUsername(username string) bool {
|
||||||
|
@ -731,37 +743,37 @@ func (oAdmin *OvpnAdmin) usersList() []OpenvpnClient {
|
||||||
apochNow := time.Now().Unix()
|
apochNow := time.Now().Unix()
|
||||||
|
|
||||||
for _, line := range indexTxtParser(fRead(*indexTxtPath)) {
|
for _, line := range indexTxtParser(fRead(*indexTxtPath)) {
|
||||||
if line.Identity != "server" {
|
if line.Identity != "server" {
|
||||||
totalCerts += 1
|
totalCerts += 1
|
||||||
ovpnClient := OpenvpnClient{Identity: line.Identity, ExpirationDate: parseDateToString(indexTxtDateLayout, line.ExpirationDate, stringDateFormat)}
|
ovpnClient := OpenvpnClient{Identity: line.Identity, ExpirationDate: parseDateToString(indexTxtDateLayout, line.ExpirationDate, stringDateFormat)}
|
||||||
switch {
|
switch {
|
||||||
case line.Flag == "V":
|
case line.Flag == "V":
|
||||||
ovpnClient.AccountStatus = "Active"
|
ovpnClient.AccountStatus = "Active"
|
||||||
ovpnClientCertificateExpire.WithLabelValues(line.Identity).Set(float64((parseDateToUnix(indexTxtDateLayout, line.ExpirationDate) - apochNow) / 3600 / 24))
|
ovpnClientCertificateExpire.WithLabelValues(line.Identity).Set(float64((parseDateToUnix(indexTxtDateLayout, line.ExpirationDate) - apochNow) / 3600 / 24))
|
||||||
validCerts += 1
|
validCerts += 1
|
||||||
case line.Flag == "R":
|
case line.Flag == "R":
|
||||||
ovpnClient.AccountStatus = "Revoked"
|
ovpnClient.AccountStatus = "Revoked"
|
||||||
ovpnClient.RevocationDate = parseDateToString(indexTxtDateLayout, line.RevocationDate, stringDateFormat)
|
ovpnClient.RevocationDate = parseDateToString(indexTxtDateLayout, line.RevocationDate, stringDateFormat)
|
||||||
ovpnClientCertificateExpire.WithLabelValues(line.Identity).Set(float64((parseDateToUnix(indexTxtDateLayout, line.ExpirationDate) - apochNow) / 3600 / 24))
|
ovpnClientCertificateExpire.WithLabelValues(line.Identity).Set(float64((parseDateToUnix(indexTxtDateLayout, line.ExpirationDate) - apochNow) / 3600 / 24))
|
||||||
revokedCerts += 1
|
revokedCerts += 1
|
||||||
case line.Flag == "E":
|
case line.Flag == "E":
|
||||||
ovpnClient.AccountStatus = "Expired"
|
ovpnClient.AccountStatus = "Expired"
|
||||||
ovpnClientCertificateExpire.WithLabelValues(line.Identity).Set(float64((parseDateToUnix(indexTxtDateLayout, line.ExpirationDate) - apochNow) / 3600 / 24))
|
ovpnClientCertificateExpire.WithLabelValues(line.Identity).Set(float64((parseDateToUnix(indexTxtDateLayout, line.ExpirationDate) - apochNow) / 3600 / 24))
|
||||||
expiredCerts += 1
|
expiredCerts += 1
|
||||||
}
|
}
|
||||||
|
|
||||||
ovpnClient.ConnectionServer = ""
|
ovpnClient.ConnectionServer = ""
|
||||||
|
|
||||||
userConnected, userConnectedTo := isUserConnected(line.Identity, oAdmin.activeClients)
|
userConnected, userConnectedTo := isUserConnected(line.Identity, oAdmin.activeClients)
|
||||||
if userConnected {
|
if userConnected {
|
||||||
ovpnClient.ConnectionStatus = "Connected"
|
ovpnClient.ConnectionStatus = "Connected"
|
||||||
ovpnClient.ConnectionServer = userConnectedTo
|
ovpnClient.ConnectionServer = userConnectedTo
|
||||||
connectedUsers += 1
|
connectedUsers += 1
|
||||||
}
|
}
|
||||||
|
|
||||||
users = append(users, ovpnClient)
|
users = append(users, ovpnClient)
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
ovpnServerCertExpire.Set(float64((parseDateToUnix(indexTxtDateLayout, line.ExpirationDate) - apochNow) / 3600 / 24))
|
ovpnServerCertExpire.Set(float64((parseDateToUnix(indexTxtDateLayout, line.ExpirationDate) - apochNow) / 3600 / 24))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -781,7 +793,7 @@ func (oAdmin *OvpnAdmin) usersList() []OpenvpnClient {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (oAdmin *OvpnAdmin) userCreate(username, password string) (bool, string) {
|
func (oAdmin *OvpnAdmin) userCreate(username, password string) (bool, string) {
|
||||||
ucErr := fmt.Sprintf("User \"%s\" created", username)
|
ucErr := fmt.Sprintf("User \"%s\" created", username)
|
||||||
|
|
||||||
if checkUserExist(username) {
|
if checkUserExist(username) {
|
||||||
ucErr = fmt.Sprintf("User \"%s\" already exists\n", username)
|
ucErr = fmt.Sprintf("User \"%s\" already exists\n", username)
|
||||||
|
@ -791,7 +803,7 @@ func (oAdmin *OvpnAdmin) userCreate(username, password string) (bool, string) {
|
||||||
return false, ucErr
|
return false, ucErr
|
||||||
}
|
}
|
||||||
|
|
||||||
if ! validateUsername(username) {
|
if !validateUsername(username) {
|
||||||
ucErr = fmt.Sprintf("Username \"%s\" incorrect, you can use only %s\n", username, usernameRegexp)
|
ucErr = fmt.Sprintf("Username \"%s\" incorrect, you can use only %s\n", username, usernameRegexp)
|
||||||
if *debug {
|
if *debug {
|
||||||
log.Printf("ERROR: userCreate: %s", ucErr)
|
log.Printf("ERROR: userCreate: %s", ucErr)
|
||||||
|
@ -832,7 +844,7 @@ func (oAdmin *OvpnAdmin) userChangePassword(username, password string) (bool, st
|
||||||
o := runBash(fmt.Sprintf("openvpn-user check --db.path %s --user %s | grep %s | wc -l", *authDatabase, username, username))
|
o := runBash(fmt.Sprintf("openvpn-user check --db.path %s --user %s | grep %s | wc -l", *authDatabase, username, username))
|
||||||
fmt.Println(o)
|
fmt.Println(o)
|
||||||
|
|
||||||
if ! validatePassword(password) {
|
if !validatePassword(password) {
|
||||||
ucpErr := fmt.Sprintf("Password for too short, password length must be greater or equal %d", passwordMinLength)
|
ucpErr := fmt.Sprintf("Password for too short, password length must be greater or equal %d", passwordMinLength)
|
||||||
if *debug {
|
if *debug {
|
||||||
log.Printf("ERROR: userChangePassword: %s\n", ucpErr)
|
log.Printf("ERROR: userChangePassword: %s\n", ucpErr)
|
||||||
|
@ -889,30 +901,30 @@ func (oAdmin *OvpnAdmin) userUnrevoke(username string) string {
|
||||||
usersFromIndexTxt := indexTxtParser(fRead(*indexTxtPath))
|
usersFromIndexTxt := indexTxtParser(fRead(*indexTxtPath))
|
||||||
for i := range usersFromIndexTxt {
|
for i := range usersFromIndexTxt {
|
||||||
if usersFromIndexTxt[i].DistinguishedName == ("/CN=" + username) {
|
if usersFromIndexTxt[i].DistinguishedName == ("/CN=" + username) {
|
||||||
if usersFromIndexTxt[i].Flag == "R" {
|
if usersFromIndexTxt[i].Flag == "R" {
|
||||||
usersFromIndexTxt[i].Flag = "V"
|
usersFromIndexTxt[i].Flag = "V"
|
||||||
usersFromIndexTxt[i].RevocationDate = ""
|
usersFromIndexTxt[i].RevocationDate = ""
|
||||||
o := runBash(fmt.Sprintf("cd %s && cp pki/revoked/certs_by_serial/%s.crt pki/issued/%s.crt", *easyrsaDirPath, usersFromIndexTxt[i].SerialNumber, username))
|
o := runBash(fmt.Sprintf("cd %s && cp pki/revoked/certs_by_serial/%s.crt pki/issued/%s.crt", *easyrsaDirPath, usersFromIndexTxt[i].SerialNumber, username))
|
||||||
//fmt.Println(o)
|
//fmt.Println(o)
|
||||||
o = runBash(fmt.Sprintf("cd %s && cp pki/revoked/certs_by_serial/%s.crt pki/certs_by_serial/%s.pem", *easyrsaDirPath, usersFromIndexTxt[i].SerialNumber, usersFromIndexTxt[i].SerialNumber))
|
o = runBash(fmt.Sprintf("cd %s && cp pki/revoked/certs_by_serial/%s.crt pki/certs_by_serial/%s.pem", *easyrsaDirPath, usersFromIndexTxt[i].SerialNumber, usersFromIndexTxt[i].SerialNumber))
|
||||||
//fmt.Println(o)
|
//fmt.Println(o)
|
||||||
o = runBash(fmt.Sprintf("cd %s && cp pki/revoked/private_by_serial/%s.key pki/private/%s.key", *easyrsaDirPath, usersFromIndexTxt[i].SerialNumber, username))
|
o = runBash(fmt.Sprintf("cd %s && cp pki/revoked/private_by_serial/%s.key pki/private/%s.key", *easyrsaDirPath, usersFromIndexTxt[i].SerialNumber, username))
|
||||||
//fmt.Println(o)
|
//fmt.Println(o)
|
||||||
o = runBash(fmt.Sprintf("cd %s && cp pki/revoked/reqs_by_serial/%s.req pki/reqs/%s.req", *easyrsaDirPath, usersFromIndexTxt[i].SerialNumber, username))
|
o = runBash(fmt.Sprintf("cd %s && cp pki/revoked/reqs_by_serial/%s.req pki/reqs/%s.req", *easyrsaDirPath, usersFromIndexTxt[i].SerialNumber, username))
|
||||||
//fmt.Println(o)
|
//fmt.Println(o)
|
||||||
fWrite(*indexTxtPath, renderIndexTxt(usersFromIndexTxt))
|
fWrite(*indexTxtPath, renderIndexTxt(usersFromIndexTxt))
|
||||||
//fmt.Print(renderIndexTxt(usersFromIndexTxt))
|
//fmt.Print(renderIndexTxt(usersFromIndexTxt))
|
||||||
o = runBash(fmt.Sprintf("cd %s && easyrsa gen-crl", *easyrsaDirPath))
|
o = runBash(fmt.Sprintf("cd %s && easyrsa gen-crl", *easyrsaDirPath))
|
||||||
//fmt.Println(o)
|
//fmt.Println(o)
|
||||||
if *authByPassword {
|
if *authByPassword {
|
||||||
o = runBash(fmt.Sprintf("openvpn-user restore --db-path %s --user %s", *authDatabase, username))
|
o = runBash(fmt.Sprintf("openvpn-user restore --db-path %s --user %s", *authDatabase, username))
|
||||||
//fmt.Println(o)
|
//fmt.Println(o)
|
||||||
}
|
}
|
||||||
crlFix()
|
crlFix()
|
||||||
o = ""
|
o = ""
|
||||||
fmt.Println(o)
|
fmt.Println(o)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fWrite(*indexTxtPath, renderIndexTxt(usersFromIndexTxt))
|
fWrite(*indexTxtPath, renderIndexTxt(usersFromIndexTxt))
|
||||||
|
@ -924,7 +936,6 @@ func (oAdmin *OvpnAdmin) userUnrevoke(username string) string {
|
||||||
return fmt.Sprintf("{\"msg\":\"User \"%s\" not found\"}", username)
|
return fmt.Sprintf("{\"msg\":\"User \"%s\" not found\"}", username)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func (oAdmin *OvpnAdmin) mgmtRead(conn net.Conn) string {
|
func (oAdmin *OvpnAdmin) mgmtRead(conn net.Conn) string {
|
||||||
buf := make([]byte, 32768)
|
buf := make([]byte, 32768)
|
||||||
bufLen, _ := conn.Read(buf)
|
bufLen, _ := conn.Read(buf)
|
||||||
|
@ -960,8 +971,8 @@ func (oAdmin *OvpnAdmin) mgmtConnectedUsersParser(text, serverName string) []cli
|
||||||
|
|
||||||
userName := user[0]
|
userName := user[0]
|
||||||
userAddress := user[1]
|
userAddress := user[1]
|
||||||
userBytesReceived:= user[2]
|
userBytesReceived := user[2]
|
||||||
userBytesSent:= user[3]
|
userBytesSent := user[3]
|
||||||
userConnectedSince := user[4]
|
userConnectedSince := user[4]
|
||||||
|
|
||||||
userStatus := clientStatus{CommonName: userName, RealAddress: userAddress, BytesReceived: userBytesReceived, BytesSent: userBytesSent, ConnectedSince: userConnectedSince, ConnectedTo: serverName}
|
userStatus := clientStatus{CommonName: userName, RealAddress: userAddress, BytesReceived: userBytesReceived, BytesSent: userBytesSent, ConnectedSince: userConnectedSince, ConnectedTo: serverName}
|
||||||
|
@ -1017,20 +1028,20 @@ func (oAdmin *OvpnAdmin) mgmtGetActiveClients() []clientStatus {
|
||||||
}
|
}
|
||||||
|
|
||||||
func isUserConnected(username string, connectedUsers []clientStatus) (bool, string) {
|
func isUserConnected(username string, connectedUsers []clientStatus) (bool, string) {
|
||||||
for _, connectedUser := range connectedUsers {
|
for _, connectedUser := range connectedUsers {
|
||||||
if connectedUser.CommonName == username {
|
if connectedUser.CommonName == username {
|
||||||
return true, connectedUser.ConnectedTo
|
return true, connectedUser.ConnectedTo
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false, ""
|
return false, ""
|
||||||
}
|
}
|
||||||
|
|
||||||
func (oAdmin *OvpnAdmin) downloadCerts() bool {
|
func (oAdmin *OvpnAdmin) downloadCerts() bool {
|
||||||
if fExist(certsArchivePath) {
|
if fExist(certsArchivePath) {
|
||||||
fDelete(certsArchivePath)
|
fDelete(certsArchivePath)
|
||||||
}
|
}
|
||||||
err := fDownload(certsArchivePath, *masterHost + downloadCertsApiUrl + "?token=" + oAdmin.masterSyncToken, oAdmin.masterHostBasicAuth)
|
err := fDownload(certsArchivePath, *masterHost+downloadCertsApiUrl+"?token="+oAdmin.masterSyncToken, oAdmin.masterHostBasicAuth)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println(err)
|
log.Println(err)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
@ -1043,7 +1054,7 @@ func (oAdmin *OvpnAdmin) downloadCcd() bool {
|
||||||
fDelete(ccdArchivePath)
|
fDelete(ccdArchivePath)
|
||||||
}
|
}
|
||||||
|
|
||||||
err := fDownload(ccdArchivePath, *masterHost + downloadCcdApiUrl + "?token=" + oAdmin.masterSyncToken, oAdmin.masterHostBasicAuth)
|
err := fDownload(ccdArchivePath, *masterHost+downloadCcdApiUrl+"?token="+oAdmin.masterSyncToken, oAdmin.masterHostBasicAuth)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println(err)
|
log.Println(err)
|
||||||
return false
|
return false
|
||||||
|
@ -1053,24 +1064,24 @@ func (oAdmin *OvpnAdmin) downloadCcd() bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
func archiveCerts() {
|
func archiveCerts() {
|
||||||
o := runBash(fmt.Sprintf("cd %s && tar -czf %s *", *easyrsaDirPath + "/pki", certsArchivePath ))
|
o := runBash(fmt.Sprintf("cd %s && tar -czf %s *", *easyrsaDirPath+"/pki", certsArchivePath))
|
||||||
fmt.Println(o)
|
fmt.Println(o)
|
||||||
}
|
}
|
||||||
|
|
||||||
func archiveCcd() {
|
func archiveCcd() {
|
||||||
o := runBash(fmt.Sprintf("cd %s && tar -czf %s *", *ccdDir, ccdArchivePath ))
|
o := runBash(fmt.Sprintf("cd %s && tar -czf %s *", *ccdDir, ccdArchivePath))
|
||||||
fmt.Println(o)
|
fmt.Println(o)
|
||||||
}
|
}
|
||||||
|
|
||||||
func unArchiveCerts() {
|
func unArchiveCerts() {
|
||||||
runBash(fmt.Sprintf("mkdir -p %s", *easyrsaDirPath + "/pki"))
|
runBash(fmt.Sprintf("mkdir -p %s", *easyrsaDirPath+"/pki"))
|
||||||
o := runBash(fmt.Sprintf("cd %s && tar -xzf %s", *easyrsaDirPath + "/pki", certsArchivePath ))
|
o := runBash(fmt.Sprintf("cd %s && tar -xzf %s", *easyrsaDirPath+"/pki", certsArchivePath))
|
||||||
fmt.Println(o)
|
fmt.Println(o)
|
||||||
}
|
}
|
||||||
|
|
||||||
func unArchiveCcd() {
|
func unArchiveCcd() {
|
||||||
runBash(fmt.Sprintf("mkdir -p %s", *ccdDir))
|
runBash(fmt.Sprintf("mkdir -p %s", *ccdDir))
|
||||||
o := runBash(fmt.Sprintf("cd %s && tar -xzf %s", *ccdDir, ccdArchivePath ))
|
o := runBash(fmt.Sprintf("cd %s && tar -xzf %s", *ccdDir, ccdArchivePath))
|
||||||
fmt.Println(o)
|
fmt.Println(o)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1112,10 +1123,10 @@ func (oAdmin *OvpnAdmin) syncDataFromMaster() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (oAdmin *OvpnAdmin) syncWithMaster() {
|
func (oAdmin *OvpnAdmin) syncWithMaster() {
|
||||||
for {
|
for {
|
||||||
time.Sleep(time.Duration(*masterSyncFrequency) * time.Second)
|
time.Sleep(time.Duration(*masterSyncFrequency) * time.Second)
|
||||||
oAdmin.syncDataFromMaster()
|
oAdmin.syncDataFromMaster()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func getOvpnCaCertExpireDate() time.Time {
|
func getOvpnCaCertExpireDate() time.Time {
|
||||||
|
@ -1134,11 +1145,11 @@ func getOvpnCaCertExpireDate() time.Time {
|
||||||
|
|
||||||
// https://community.openvpn.net/openvpn/ticket/623
|
// https://community.openvpn.net/openvpn/ticket/623
|
||||||
func crlFix() {
|
func crlFix() {
|
||||||
err1 := os.Chmod(*easyrsaDirPath + "/pki", 0755)
|
err1 := os.Chmod(*easyrsaDirPath+"/pki", 0755)
|
||||||
if err1 != nil {
|
if err1 != nil {
|
||||||
log.Println(err1)
|
log.Println(err1)
|
||||||
}
|
}
|
||||||
err2 := os.Chmod(*easyrsaDirPath + "/pki/crl.pem", 0644)
|
err2 := os.Chmod(*easyrsaDirPath+"/pki/crl.pem", 0644)
|
||||||
if err2 != nil {
|
if err2 != nil {
|
||||||
log.Println(err2)
|
log.Println(err2)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue