| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046 |
- package ovpm
- import (
- "bytes"
- "fmt"
- "io"
- "math/big"
- "net"
- "os"
- "os/exec"
- "path/filepath"
- "strings"
- "sync"
- "text/template"
- "time"
- "github.com/asaskevich/govalidator"
- "github.com/cad/ovpm/pki"
- "github.com/cad/ovpm/supervisor"
- "github.com/coreos/go-iptables/iptables"
- "github.com/google/uuid"
- "github.com/jinzhu/gorm"
- "github.com/sirupsen/logrus"
- )
- // Possible VPN protocols.
- const (
- TCPProto string = "tcp"
- UDPProto string = "udp"
- )
- // serverModel is database model for storing VPN server related stuff.
- type dbServerModel struct {
- gorm.Model
- Name string `gorm:"unique_index"` // Server name.
- SerialNumber string
- Hostname string // Server's ip address or FQDN
- Port string // Server's listening port
- Proto string // Server's proto udp or tcp
- Cert string // Server RSA certificate.
- Key string // Server RSA private key.
- CACert string // Root CA RSA certificate.
- CAKey string // Root CA RSA key.
- Net string // VPN network.
- Mask string // VPN network mask.
- CRL string // Certificate Revocation List
- DNS string // DNS servers to push to the clients.
- KeepalivePeriod string // Keepalive ping period
- KeepaliveTimeout string // Keepalive timeout
- UseLZO bool // Use LZO compression
- }
- var serverInstance *Server
- var once sync.Once
- // Server represents VPN server.
- type Server struct {
- dbServerModel
- webPort string
- emitToFileFunc func(path, content string, mode uint) error
- openFunc func(path string) (io.Reader, error)
- parseStatusLogFunc func(f io.Reader) ([]clEntry, []rtEntry)
- }
- // TheServer returns a pointer to the server instance.
- //
- // Server instance is a singleton instance that is initialized
- // on the first call made to the TheServer().
- func TheServer() *Server {
- once.Do(func() {
- // Initialize the server instance by setting default mockable funcs & attributes.
- serverInstance = &Server{
- emitToFileFunc: emitToFile,
- openFunc: func(path string) (io.Reader, error) {
- return os.Open(path)
- },
- parseStatusLogFunc: parseStatusLog,
- }
- })
- if db != nil {
- serverInstance.Refresh()
- } else {
- logrus.Warn("database is not connected yet. skipping server instance refresh")
- }
- return serverInstance
- }
- // CheckSerial takes a serial number and checks it against the current server's serial number.
- func (svr *Server) CheckSerial(serial string) bool {
- return serial == svr.SerialNumber
- }
- // GetSerialNumber returns server's serial number.
- func (svr *Server) GetSerialNumber() string {
- return svr.SerialNumber
- }
- // GetServerName returns server's name.
- func (svr *Server) GetServerName() string {
- if svr.Name != "" {
- return svr.Name
- }
- return "default"
- }
- // GetHostname returns vpn server's hostname.
- func (svr *Server) GetHostname() string {
- return svr.Hostname
- }
- // GetPort returns vpn server's port.
- func (svr *Server) GetPort() string {
- if svr.Port != "" {
- return svr.Port
- }
- return DefaultVPNPort
- }
- // GetProto returns vpn server's proto.
- func (svr *Server) GetProto() string {
- if svr.Proto != "" {
- return svr.Proto
- }
- return DefaultVPNProto
- }
- // CAExpiresAt returns the expiry date time of the CA.
- func (svr *Server) CAExpiresAt() time.Time {
- if !svr.IsInitialized() {
- return time.Time{}
- }
- crt, err := pki.ReadCertFromPEM(svr.CACert)
- if err != nil {
- logrus.Fatalf("can't parse cert: %v", err)
- }
- return crt.NotAfter
- }
- // ExpiresAt returns the expiry date time of the server cert.
- func (svr *Server) ExpiresAt() time.Time {
- if !svr.IsInitialized() {
- return time.Time{}
- }
- crt, err := pki.ReadCertFromPEM(svr.Cert)
- if err != nil {
- logrus.Fatalf("can't parse cert: %v", err)
- }
- return crt.NotAfter
- }
- // GetKey returns vpn server's key.
- func (svr *Server) GetKey() string {
- return svr.Key
- }
- // GetCACert returns vpn server's cacert.
- func (svr *Server) GetCACert() string {
- return svr.CACert
- }
- // GetCAKey returns vpn server's cakey.
- func (svr *Server) GetCAKey() string {
- return svr.CAKey
- }
- // GetNet returns vpn server's net.
- func (svr *Server) GetNet() string {
- return svr.Net
- }
- // GetMask returns vpn server's mask.
- func (svr *Server) GetMask() string {
- return svr.Mask
- }
- // GetCRL returns vpn server's crl.
- func (svr *Server) GetCRL() string {
- return svr.CRL
- }
- // GetDNS returns vpn server's dns.
- func (svr *Server) GetDNS() string {
- if svr.DNS != "" {
- return svr.DNS
- }
- return DefaultVPNDNS
- }
- // GetCreatedAt returns server's created at.
- func (svr *Server) GetCreatedAt() string {
- return svr.CreatedAt.Format(time.UnixDate)
- }
- func (svr *Server) GetKeepalivePeriod() string {
- if svr.KeepalivePeriod != "" {
- return svr.KeepalivePeriod
- }
- return DefaultKeepalivePeriod
- }
- func (svr *Server) GetKeepaliveTimeout() string {
- if svr.KeepaliveTimeout != "" {
- return svr.KeepaliveTimeout
- }
- return DefaultKeepaliveTimeout
- }
- func (svr *Server) IsUseLZO() bool {
- return svr.UseLZO
- }
- // Init regenerates keys and certs for a Root CA, gets initial settings for the VPN server
- // and saves them in the database.
- //
- // 'proto' can be either "udp" or "tcp" and if it's "" it defaults to "udp".
- //
- // 'ipblock' is a IP network in the CIDR form. VPN clients get their IP addresses from this network.
- // It defaults to const 'DefaultVPNNetwork'.
- //
- // 'keepalivePeriod' is the ping period to check if the remote peer is alive.
- // It defaults to const 'DefaultKeepalivePeriod'
- //
- // 'keeapliveTimeout' is the ping timeout to assume that remote peer is down.
- // It defaults to const 'DefaultKeepaliveTimeout'
- //
- // 'useLZO' is used to determine whether to use the lzo compression algorithm to support older clients.
- // It defaults to false due to security issues and deprecation
- //
- // Please note that, Init is potentially destructive procedure, it will cause invalidation of
- // existing .ovpn profiles of the current users. So it should be used carefully.
- func (svr *Server) Init(hostname string, port string, proto string, ipblock string, dns string, keepalivePeriod string, keepaliveTimeout string, useLZO bool) error {
- if port == "" {
- port = DefaultVPNPort
- }
- if dns == "" {
- dns = DefaultVPNDNS
- }
- if keepalivePeriod == "" {
- keepalivePeriod = DefaultKeepalivePeriod
- }
- if keepaliveTimeout == "" {
- keepaliveTimeout = DefaultKeepaliveTimeout
- }
- switch proto {
- case "":
- proto = UDPProto
- case UDPProto:
- proto = UDPProto
- case TCPProto:
- proto = TCPProto
- default:
- return fmt.Errorf("validation error: proto:`%s` should be either 'tcp' or 'udp'", proto)
- }
- // vpn network to use.
- var ipnet *net.IPNet
- // If user didn't specify, pick the vpn network from defaults.
- if ipblock == "" {
- var err error
- _, ipnet, err = net.ParseCIDR(DefaultVPNNetwork)
- if err != nil {
- return fmt.Errorf("can not parse CIDR %s: %v", DefaultVPNNetwork, err)
- }
- }
- // Check if the user specified vpn network is valid.
- if ipblock != "" && !govalidator.IsCIDR(ipblock) {
- return fmt.Errorf("validation error: ipblock:`%s` should be a CIDR network", ipblock)
- }
- // Use user specified vpn network.
- if ipblock != "" {
- var err error
- _, ipnet, err = net.ParseCIDR(ipblock)
- if err != nil {
- return fmt.Errorf("can parse ipblock: %s", err)
- }
- }
- if !govalidator.IsNumeric(port) {
- return fmt.Errorf("validation error: port:`%s` should be numeric", port)
- }
- if !govalidator.IsNumeric(keepaliveTimeout) {
- return fmt.Errorf("validation error: keepaliveTimeout:`%s` should be numeric", keepaliveTimeout)
- }
- if !govalidator.IsNumeric(keepalivePeriod) {
- return fmt.Errorf("validation error: keepalivePeriod:`%s` should be numeric", keepalivePeriod)
- }
- serverName := "default"
- if svr := TheServer(); svr.IsInitialized() {
- if err := svr.Deinit(); err != nil {
- logrus.Errorf("server can not be deleted: %v", err)
- return err
- }
- }
- if !govalidator.IsHost(hostname) {
- return fmt.Errorf("validation error: hostname:`%s` should be either an ip address or a FQDN", hostname)
- }
- if !govalidator.IsIPv4(dns) {
- return fmt.Errorf("validation error: dns:`%s` should be an ip address", dns)
- }
- ca, err := pki.NewCA()
- if err != nil {
- return fmt.Errorf("can not create ca creds: %s", err)
- }
- srv, err := pki.NewServerCertHolder(ca)
- if err != nil {
- return fmt.Errorf("can not create server cert creds: %s", err)
- }
- serialNumber := uuid.New().String()
- serverInstance := dbServerModel{
- Name: serverName,
- SerialNumber: serialNumber,
- Hostname: hostname,
- Proto: proto,
- Port: port,
- Cert: srv.Cert,
- Key: srv.Key,
- CACert: ca.Cert,
- CAKey: ca.Key,
- Net: ipnet.IP.To4().String(),
- Mask: net.IP(ipnet.Mask).To4().String(),
- DNS: dns,
- KeepalivePeriod: keepalivePeriod,
- KeepaliveTimeout: keepaliveTimeout,
- UseLZO: useLZO,
- }
- db.Create(&serverInstance)
- if db.NewRecord(&serverInstance) {
- return fmt.Errorf("can not create server instance on database")
- }
- users, err := GetAllUsers()
- if err != nil {
- return err
- }
- // Sign all users in the db with the new server
- for _, user := range users {
- err := user.Renew()
- logrus.Infof("user certificate changed for %s, you should run: $ ovpm user export-config --user %s", user.Username, user.Username)
- if err != nil {
- logrus.Errorf("can not sign user %s: %v", user.Username, err)
- continue
- }
- // Set dynamic ip to user.
- user.HostID = 0
- db.Save(&user.dbUserModel)
- }
- TheServer().EmitWithRestart()
- logrus.Infof("server initialized")
- return nil
- }
- // Update updates VPN server attributes.
- func (svr *Server) Update(ipblock string, dns string) error {
- if !svr.IsInitialized() {
- return fmt.Errorf("server is not initialized")
- }
- var changed bool
- if ipblock != "" && govalidator.IsCIDR(ipblock) {
- var ipnet *net.IPNet
- _, ipnet, err := net.ParseCIDR(ipblock)
- if err != nil {
- return fmt.Errorf("can not parse CIDR %s: %v", ipblock, err)
- }
- svr.dbServerModel.Net = ipnet.IP.To4().String()
- svr.dbServerModel.Mask = net.IP(ipnet.Mask).To4().String()
- changed = true
- }
- if dns != "" && govalidator.IsIPv4(dns) {
- svr.dbServerModel.DNS = dns
- changed = true
- }
- if changed {
- db.Save(svr.dbServerModel)
- users, err := GetAllUsers()
- if err != nil {
- return err
- }
- // Set all users to dynamic ip address.
- // This way we prevent any ip range mismatch.
- for _, user := range users {
- user.HostID = 0
- db.Save(user.dbUserModel)
- }
- svr.EmitWithRestart()
- logrus.Infof("server updated")
- }
- return nil
- }
- // Deinit deletes the VPN server from the database and frees the allocated resources.
- func (svr *Server) Deinit() error {
- if !svr.IsInitialized() {
- return fmt.Errorf("server not found")
- }
- db.Unscoped().Delete(&dbServerModel{})
- db.Unscoped().Delete(&dbRevokedModel{})
- svr.EmitWithRestart()
- return nil
- }
- // DumpsClientConfig generates .ovpn file for the given vpn user and returns it as a string.
- func (svr *Server) DumpsClientConfig(username string) (string, error) {
- var result bytes.Buffer
- user, err := GetUser(username)
- if err != nil {
- return "", err
- }
- params := struct {
- Hostname string
- Port string
- CA string
- Key string
- Cert string
- NoGW bool
- Proto string
- KeepalivePeriod string
- KeepaliveTimeout string
- UseLZO bool
- }{
- Hostname: svr.GetHostname(),
- Port: svr.GetPort(),
- CA: svr.GetCACert(),
- Key: user.getKey(),
- Cert: user.GetCert(),
- NoGW: user.IsNoGW(),
- Proto: svr.GetProto(),
- KeepalivePeriod: svr.GetKeepalivePeriod(),
- KeepaliveTimeout: svr.GetKeepaliveTimeout(),
- UseLZO: svr.IsUseLZO(),
- }
- t, err := template.New("client.ovpn").Parse(clientOvpnTemplate)
- if err != nil {
- return "", fmt.Errorf("can not parse client.ovpn.tmpl template: %s", err)
- }
- err = t.Execute(&result, params)
- if err != nil {
- return "", fmt.Errorf("can not render client.ovpn: %s", err)
- }
- return result.String(), nil
- }
- // DumpClientConfig generates .ovpn file for the given vpn user and dumps it to outPath.
- func (svr *Server) DumpClientConfig(username, path string) error {
- result, err := svr.DumpsClientConfig(username)
- if err != nil {
- return err
- }
- // Wite rendered content into openvpn server conf.
- return svr.emitToFile(path, result, 0)
- }
- // GetSystemCA returns the system CA from the database if available.
- func (svr *Server) GetSystemCA() (*pki.CA, error) {
- server := dbServerModel{}
- db.First(&server)
- if db.NewRecord(&server) {
- return nil, fmt.Errorf("server record does not exists in db")
- }
- return &pki.CA{
- CertHolder: pki.CertHolder{
- Cert: server.CACert,
- Key: server.CAKey,
- },
- }, nil
- }
- // vpnProc represents the OpenVPN process that is managed by the ovpm supervisor globally OpenVPN.
- var vpnProc supervisor.Supervisable
- // StartVPNProc starts the OpenVPN process.
- func (svr *Server) StartVPNProc() {
- if !svr.IsInitialized() {
- logrus.Error("can not launch OpenVPN because system is not initialized")
- return
- }
- if vpnProc == nil {
- panic(fmt.Sprintf("vpnProc is not initialized!"))
- }
- if vpnProc.Status() == supervisor.RUNNING {
- logrus.Error("OpenVPN is already started")
- return
- }
- svr.Emit()
- vpnProc.Start()
- ensureNatEnabled()
- }
- // RestartVPNProc restarts the OpenVPN process.
- func (svr *Server) RestartVPNProc() {
- if !svr.IsInitialized() {
- logrus.Error("can not launch OpenVPN because system is not initialized")
- return
- }
- if vpnProc == nil {
- panic(fmt.Sprintf("vpnProc is not initialized!"))
- }
- svr.Emit()
- vpnProc.Restart()
- ensureNatEnabled()
- }
- // StopVPNProc stops the OpenVPN process.
- func (svr *Server) StopVPNProc() {
- if vpnProc == nil {
- panic(fmt.Sprintf("vpnProc is not initialized!"))
- }
- if vpnProc.Status() != supervisor.RUNNING {
- logrus.Error("OpenVPN is already not running")
- return
- }
- vpnProc.Stop()
- }
- // Emit generates all needed files for the OpenVPN server and dumps them to their corresponding paths defined in the config.
- func (svr *Server) Emit() error {
- // Check dependencies
- if !checkOpenVPNExecutable() {
- return fmt.Errorf("openvpn executable can not be found! you should install OpenVPN on this machine")
- }
- if !checkOpenSSLExecutable() {
- return fmt.Errorf("openssl executable can not be found! you should install openssl on this machine")
- }
- if !checkIptablesExecutable() {
- return fmt.Errorf("iptables executable can not be found")
- }
- if !svr.IsInitialized() {
- return fmt.Errorf("you should create a server first. e.g. $ ovpm vpn create-server")
- }
- if err := svr.emitServerConf(); err != nil {
- return fmt.Errorf("can not emit server conf: %s", err)
- }
- if err := svr.emitServerCert(); err != nil {
- return fmt.Errorf("can not emit server cert: %s", err)
- }
- if err := svr.emitServerKey(); err != nil {
- return fmt.Errorf("can not emit server key: %s", err)
- }
- if err := svr.emitCACert(); err != nil {
- return fmt.Errorf("can not emit ca cert : %s", err)
- }
- if err := svr.emitCAKey(); err != nil {
- return fmt.Errorf("can not emit ca key: %s", err)
- }
- if err := svr.emitDHParams(); err != nil {
- return fmt.Errorf("can not emit dhparams: %s", err)
- }
- if err := svr.emitCCD(); err != nil {
- return fmt.Errorf("can not emit ccd: %s", err)
- }
- if err := svr.emitIptables(); err != nil {
- return fmt.Errorf("can not emit iptables: %s", err)
- }
- if err := svr.emitCRL(); err != nil {
- return fmt.Errorf("can not emit crl: %s", err)
- }
- logrus.Info("configurations emitted to the filesystem")
- return nil
- }
- // EmitWithRestart restarts vpnProc after calling EmitWithRestart().
- func (svr *Server) EmitWithRestart() error {
- if err := svr.Emit(); err != nil {
- return err
- }
- if svr.IsInitialized() {
- for {
- if vpnProc.Status() == supervisor.RUNNING || vpnProc.Status() == supervisor.STOPPED {
- logrus.Info("OpenVPN process is restarting")
- svr.RestartVPNProc()
- break
- }
- time.Sleep(1 * time.Second)
- }
- }
- return nil
- }
- // emitToFile is a proxy that calls svr.emitToFileFunc.
- func (svr *Server) emitToFile(path, content string, mode uint) error {
- return svr.emitToFileFunc(path, content, mode)
- }
- // emitToFile is an implementation for svr.emitToFileFunc.
- func emitToFile(path, content string, mode uint) error {
- // When testing don't emit files to the filesystem. Just pretend you did.
- if Testing {
- return nil
- }
- file, err := os.Create(path)
- if err != nil {
- return fmt.Errorf("Cannot create file %s: %v", path, err)
- }
- if mode != 0 {
- file.Chmod(os.FileMode(mode))
- }
- defer file.Close()
- fmt.Fprintf(file, content)
- return nil
- }
- func (svr *Server) emitServerConf() error {
- port := DefaultVPNPort
- if serverInstance.Port != "" {
- port = serverInstance.Port
- }
- proto := DefaultVPNProto
- if serverInstance.Proto != "" {
- proto = serverInstance.Proto
- }
- dns := DefaultVPNDNS
- if serverInstance.DNS != "" {
- dns = serverInstance.DNS
- }
- var result bytes.Buffer
- server := struct {
- CertPath string
- KeyPath string
- CACertPath string
- CAKeyPath string
- CCDPath string
- CRLPath string
- DHParamsPath string
- Net string
- Mask string
- Port string
- Proto string
- DNS string
- KeepalivePeriod string
- KeepaliveTimeout string
- UseLZO bool
- }{
- CertPath: _DefaultCertPath,
- KeyPath: _DefaultKeyPath,
- CACertPath: _DefaultCACertPath,
- CAKeyPath: _DefaultCAKeyPath,
- CCDPath: _DefaultVPNCCDPath,
- CRLPath: _DefaultCRLPath,
- DHParamsPath: _DefaultDHParamsPath,
- Net: svr.Net,
- Mask: svr.Mask,
- Port: port,
- Proto: proto,
- DNS: dns,
- KeepalivePeriod: svr.GetKeepalivePeriod(),
- KeepaliveTimeout: svr.GetKeepaliveTimeout(),
- UseLZO: svr.IsUseLZO(),
- }
- t, err := template.New("server.conf").Parse(serverConfTemplate)
- if err != nil {
- return fmt.Errorf("can not parse server.conf.tmpl template: %s", err)
- }
- err = t.Execute(&result, server)
- if err != nil {
- return fmt.Errorf("can not render server.conf: %s", err)
- }
- // Wite rendered content into openvpn server conf.
- return svr.emitToFile(_DefaultVPNConfPath, result.String(), 0)
- }
- // Refresh synchronizes the server instance from db.
- func (svr *Server) Refresh() error {
- //db = CreateDB("sqlite3", "")
- var dbServer dbServerModel
- q := db.First(&dbServer)
- if err := q.Error; err != nil {
- return fmt.Errorf("can't get server from db: %v", err)
- }
- if q.RecordNotFound() {
- return fmt.Errorf("server is not initialized")
- }
- svr.dbServerModel = dbServer
- return nil
- }
- // GetConnectedUsers will return a list of users who are currently connected
- // to the VPN service.
- func (svr *Server) GetConnectedUsers() ([]User, error) {
- var users []User
- // Open the status log file.
- f, err := svr.openFunc(_DefaultStatusLogPath)
- if err != nil {
- panic(err)
- }
- cl, _ := svr.parseStatusLogFunc(f) // client list from OpenVPN status log
- for _, c := range cl {
- var u dbUserModel
- q := db.Where(dbUserModel{Username: c.CommonName}).First(&u)
- if q.RecordNotFound() {
- logrus.WithFields(
- logrus.Fields{"CommonName": c.CommonName},
- ).Error("user not found: common name reported by the OpenVPN is not found in the database")
- continue
- }
- if err := q.Error; err != nil {
- return nil, fmt.Errorf("unknown db error: %v", err)
- }
- users = append(users, User{
- dbUserModel: u,
- isConnected: true,
- connectedSince: c.ConnectedSince,
- bytesReceived: c.BytesReceived,
- bytesSent: c.BytesSent,
- })
- }
- return users, nil
- }
- // IsInitialized checks if there is a default VPN server configured in the database or not.
- func (svr *Server) IsInitialized() bool {
- var serverModel dbServerModel
- q := db.First(&serverModel)
- if err := q.Error; err != nil {
- logrus.Errorf("can't retrieve server from db: %v", err)
- }
- if q.RecordNotFound() {
- return false
- }
- return true
- }
- func (svr *Server) emitServerKey() error {
- // Write rendered content into key file.
- return svr.emitToFile(_DefaultKeyPath, svr.Key, 0600)
- }
- func (svr *Server) emitServerCert() error {
- // Write rendered content into the cert file.
- return svr.emitToFile(_DefaultCertPath, svr.Cert, 0)
- }
- func (svr *Server) emitCRL() error {
- var revokedDBItems []*dbRevokedModel
- db.Find(&revokedDBItems)
- var revokedCertSerials []*big.Int
- for _, item := range revokedDBItems {
- bi := big.NewInt(0)
- bi.SetString(item.SerialNumber, 16)
- revokedCertSerials = append(revokedCertSerials, bi)
- }
- systemCA, err := svr.GetSystemCA()
- if err != nil {
- return fmt.Errorf("can not emit CRL: %v", err)
- }
- crl, err := pki.NewCRL(systemCA, revokedCertSerials...)
- if err != nil {
- return fmt.Errorf("can not emit crl: %v", err)
- }
- return svr.emitToFile(_DefaultCRLPath, crl, 0)
- }
- func (svr *Server) emitCACert() error {
- // Write rendered content into the ca cert file.
- return svr.emitToFile(_DefaultCACertPath, svr.CACert, 0)
- }
- func (svr *Server) emitCAKey() error {
- // Write rendered content into the ca key file.
- return svr.emitToFile(_DefaultCAKeyPath, svr.CAKey, 0600)
- }
- func (svr *Server) emitCCD() error {
- users, err := GetAllUsers()
- if err != nil {
- return err
- }
- // Filesystem related stuff. Skipping when testing.
- if !Testing {
- // Clean and then create and write rendered ccd data.
- err = os.RemoveAll(_DefaultVPNCCDPath)
- if err != nil {
- if os.IsNotExist(err) {
- } else {
- return err
- }
- }
- if _, err := os.Stat(_DefaultVPNCCDPath); err != nil {
- }
- err = os.Mkdir(_DefaultVPNCCDPath, 0755)
- if err != nil {
- if !os.IsExist(err) {
- return err
- }
- }
- }
- // Render ccd templates for the users.
- for _, user := range users {
- var associatedRoutes [][3]string
- var serverNets [][2]string
- for _, network := range GetAllNetworks() {
- switch network.Type {
- case ROUTE:
- for _, assocUsername := range network.GetAssociatedUsernames() {
- if assocUsername == user.Username {
- via := network.Via
- ip, mask, err := net.ParseCIDR(network.CIDR)
- if err != nil {
- return err
- }
- associatedRoutes = append(associatedRoutes, [3]string{ip.To4().String(), net.IP(mask.Mask).To4().String(), via})
- }
- }
- case SERVERNET:
- // Push associated servernets to client when client is not getting vpn server as default gw.
- if user.IsNoGW() {
- for _, assocUsername := range network.GetAssociatedUsernames() {
- if assocUsername == user.Username {
- ip, mask, err := net.ParseCIDR(network.CIDR)
- if err != nil {
- return err
- }
- serverNets = append(serverNets, [2]string{ip.To4().String(), net.IP(mask.Mask).To4().String()})
- }
- }
- }
- }
- }
- var result bytes.Buffer
- params := struct {
- IP string
- NetMask string
- Routes [][3]string // [0] is IP, [1] is Netmask, [2] is Via
- Servernets [][2]string // [0] is IP, [1] is Netmask
- RedirectGW bool
- }{IP: user.getIP().String(), NetMask: svr.Mask, Routes: associatedRoutes, Servernets: serverNets, RedirectGW: !user.NoGW}
- t, err := template.New("ccd.file.tmpl").Parse(ccdFileTemplate)
- if err != nil {
- return fmt.Errorf("can not parse ccd.file.tmpl template: %s", err)
- }
- err = t.Execute(&result, params)
- if err != nil {
- return fmt.Errorf("can not render ccd file %s: %s", user.Username, err)
- }
- if err = svr.emitToFile(filepath.Join(_DefaultVPNCCDPath, user.Username), result.String(), 0); err != nil {
- return err
- }
- }
- return nil
- }
- func (svr *Server) emitDHParams() error {
- var result bytes.Buffer
- t, err := template.New("dh4096.pem.tmpl").Parse(dh4096PemTemplate)
- if err != nil {
- return fmt.Errorf("can not parse dh4096.pem template: %s", err)
- }
- err = t.Execute(&result, nil)
- if err != nil {
- return fmt.Errorf("can not render dh4096.pem file: %s", err)
- }
- return svr.emitToFile(_DefaultDHParamsPath, result.String(), 0)
- }
- func (svr *Server) emitIptables() error {
- if Testing {
- return nil
- }
- ipt, err := iptables.NewWithProtocol(iptables.ProtocolIPv4)
- if err != nil {
- return fmt.Errorf("can not create new iptables object: %v", err)
- }
- for _, network := range GetAllNetworks() {
- associatedUsernames := network.GetAssociatedUsernames()
- switch network.Type {
- case SERVERNET:
- users, err := GetAllUsers()
- if err != nil {
- return err
- }
- // Find associated users and emit iptables configs for the users
- // regarding the network's type and attributes.
- for _, user := range users {
- // Find out if the user is associated or not.
- var found bool
- for _, auser := range associatedUsernames {
- if user.Username == auser {
- found = true
- break
- }
- }
- userIP, _, err := net.ParseCIDR(user.GetIPNet())
- if err != nil {
- return err
- }
- _, networkIPNet, err := net.ParseCIDR(network.CIDR)
- if err != nil {
- return err
- }
- // get destination network's iface
- iface := interfaceOfIP(networkIPNet)
- if iface == nil {
- logrus.Warnf("network doesn't exist on server %s[SERVERNET]: cant find interface for %s", network.Name, networkIPNet.String())
- return nil
- }
- // enable nat for the user to the destination network n
- if found {
- err = ipt.AppendUnique("nat", "POSTROUTING", "-s", userIP.String(), "-o", iface.Name, "-j", "MASQUERADE")
- if err != nil {
- logrus.Error(err)
- return err
- }
- } else {
- err = ipt.Delete("nat", "POSTROUTING", "-s", userIP.String(), "-o", iface.Name, "-j", "MASQUERADE")
- if err != nil {
- logrus.Debug(err)
- }
- }
- }
- }
- }
- return nil
- }
- func checkOpenVPNExecutable() bool {
- executable := getOpenVPNExecutable()
- if executable == "" {
- logrus.Error("openvpn is not installed ✘")
- return false
- }
- logrus.Debugf("openvpn executable detected: %s ✔", executable)
- return true
- }
- func getOpenVPNExecutable() string {
- cmd := exec.Command("which", "openvpn")
- output, err := cmd.Output()
- if err != nil {
- logrus.Errorf("openvpn is not installed: %s ✘", err)
- return ""
- }
- logrus.Debugf("openvpn executable detected: %s ✔", strings.TrimSpace(string(output[:])))
- return strings.TrimSpace(string(output[:]))
- }
- func checkOpenSSLExecutable() bool {
- cmd := exec.Command("which", "openssl")
- output, err := cmd.Output()
- if err != nil {
- logrus.Errorf("openssl is not installed: %s ✘", err)
- return false
- }
- logrus.Debugf("openssl executable detected: %s ✔", strings.TrimSpace(string(output[:])))
- return true
- }
- func checkIptablesExecutable() bool {
- cmd := exec.Command("which", "iptables")
- output, err := cmd.Output()
- if err != nil {
- logrus.Errorf("iptables is not installed: %s ✘", err)
- return false
- }
- logrus.Debugf("iptables executable detected: %s ✔", strings.TrimSpace(string(output[:])))
- return true
- }
- func ensureBaseDir() {
- if Testing {
- return
- }
- os.Mkdir(varBasePath, 0755)
- }
- func init() {
- ensureBaseDir()
- var err error
- vpnProc, err = supervisor.NewProcess(getOpenVPNExecutable(), varBasePath, []string{"--config", _DefaultVPNConfPath})
- if err != nil {
- logrus.Errorf("can not create process: %v", err)
- }
- }
|