vpn.go 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609
  1. //go:generate go-bindata -pkg bindata -o bindata/bindata.go template/
  2. //go:generate protoc -I pb/ pb/user.proto pb/vpn.proto --go_out=plugins=grpc:pb
  3. package ovpm
  4. import (
  5. "bytes"
  6. "fmt"
  7. "math/big"
  8. "net"
  9. "os"
  10. "os/exec"
  11. "strings"
  12. "text/template"
  13. "github.com/Sirupsen/logrus"
  14. "github.com/asaskevich/govalidator"
  15. "github.com/cad/ovpm/bindata"
  16. "github.com/cad/ovpm/pki"
  17. "github.com/cad/ovpm/supervisor"
  18. "github.com/google/uuid"
  19. "github.com/jinzhu/gorm"
  20. "time"
  21. )
  22. // DBNetwork is database model for external networks on the VPN server.
  23. type DBNetwork struct {
  24. gorm.Model
  25. ServerID uint
  26. Server DBServer
  27. Name string
  28. NetworkCIDR string
  29. }
  30. // DBServer is database model for storing VPN server related stuff.
  31. type DBServer struct {
  32. gorm.Model
  33. Name string `gorm:"unique_index"` // Server name.
  34. SerialNumber string
  35. Hostname string // Server's ip address or FQDN
  36. Port string // Server's listening port
  37. Cert string // Server RSA certificate.
  38. Key string // Server RSA private key.
  39. CACert string // Root CA RSA certificate.
  40. CAKey string // Root CA RSA key.
  41. Net string // VPN network.
  42. Mask string // VPN network mask.
  43. CRL string // Certificate Revocation List
  44. }
  45. // CheckSerial takes a serial number and checks it against the current server's serial number.
  46. func (s *DBServer) CheckSerial(serial string) bool {
  47. return serial == s.SerialNumber
  48. }
  49. type _VPNServerConfig struct {
  50. CertPath string
  51. KeyPath string
  52. CACertPath string
  53. CAKeyPath string
  54. CCDPath string
  55. CRLPath string
  56. DHParamsPath string
  57. Net string
  58. Mask string
  59. Port string
  60. }
  61. // Init regenerates keys and certs for a Root CA, and saves them in the database.
  62. func Init(hostname string, port string) error {
  63. if port == "" {
  64. port = DefaultVPNPort
  65. }
  66. if !govalidator.IsNumeric(port) {
  67. return fmt.Errorf("validation error: port:`%s` should be numeric", hostname)
  68. }
  69. serverName := "default"
  70. if IsInitialized() {
  71. if err := Deinit(); err != nil {
  72. logrus.Errorf("server can not be deleted: %v", err)
  73. return err
  74. }
  75. }
  76. if !govalidator.IsHost(hostname) {
  77. return fmt.Errorf("validation error: hostname:`%s` should be either an ip address or a FQDN", hostname)
  78. }
  79. ca, err := pki.NewCA()
  80. if err != nil {
  81. return fmt.Errorf("can not create ca creds: %s", err)
  82. }
  83. srv, err := pki.NewServerCertHolder(ca)
  84. if err != nil {
  85. return fmt.Errorf("can not create server cert creds: %s", err)
  86. }
  87. serialNumber := uuid.New().String()
  88. serverInstance := DBServer{
  89. Name: serverName,
  90. SerialNumber: serialNumber,
  91. Hostname: hostname,
  92. Port: port,
  93. Cert: srv.Cert,
  94. Key: srv.Key,
  95. CACert: ca.Cert,
  96. CAKey: ca.Key,
  97. Net: _DefaultServerNetwork,
  98. Mask: _DefaultServerNetMask,
  99. }
  100. db.Create(&serverInstance)
  101. if db.NewRecord(&serverInstance) {
  102. return fmt.Errorf("can not create server instance on database")
  103. }
  104. users, err := GetAllUsers()
  105. if err != nil {
  106. return err
  107. }
  108. // Sign all users in the db with the new server
  109. for _, user := range users {
  110. err := user.Renew()
  111. logrus.Infof("user certificate changed for %s, you should run: $ ovpm user export-config --user %s", user.Username, user.Username)
  112. if err != nil {
  113. logrus.Errorf("can not sign user %s: %v", user.Username, err)
  114. continue
  115. }
  116. }
  117. Emit()
  118. logrus.Infof("server initialized")
  119. return nil
  120. }
  121. // Deinit deletes the server with the given serverName from the database and frees the allocated resources.
  122. func Deinit() error {
  123. if !IsInitialized() {
  124. return fmt.Errorf("server not found")
  125. }
  126. db.Unscoped().Delete(&DBServer{})
  127. db.Unscoped().Delete(&DBRevoked{})
  128. Emit()
  129. return nil
  130. }
  131. // DumpsClientConfig generates .ovpn file for the given vpn user and returns it as a string.
  132. func DumpsClientConfig(username string) (string, error) {
  133. var result bytes.Buffer
  134. user, err := GetUser(username)
  135. if err != nil {
  136. return "", err
  137. }
  138. server, err := GetServerInstance()
  139. if err != nil {
  140. return "", err
  141. }
  142. params := struct {
  143. Hostname string
  144. Port string
  145. CA string
  146. Key string
  147. Cert string
  148. }{
  149. Hostname: server.Hostname,
  150. Port: server.Port,
  151. CA: server.CACert,
  152. Key: user.Key,
  153. Cert: user.Cert,
  154. }
  155. data, err := bindata.Asset("template/client.ovpn.tmpl")
  156. if err != nil {
  157. return "", err
  158. }
  159. t, err := template.New("client.ovpn").Parse(string(data))
  160. if err != nil {
  161. return "", fmt.Errorf("can not parse client.ovpn.tmpl template: %s", err)
  162. }
  163. err = t.Execute(&result, params)
  164. if err != nil {
  165. return "", fmt.Errorf("can not render client.ovpn: %s", err)
  166. }
  167. return result.String(), nil
  168. }
  169. // DumpClientConfig generates .ovpn file for the given vpn user and dumps it to outPath.
  170. func DumpClientConfig(username, path string) error {
  171. result, err := DumpsClientConfig(username)
  172. if err != nil {
  173. return err
  174. }
  175. // Wite rendered content into openvpn server conf.
  176. return emitToFile(path, result, 0)
  177. }
  178. // GetSystemCA returns the system CA from the database if available.
  179. func GetSystemCA() (*pki.CA, error) {
  180. server := DBServer{}
  181. db.First(&server)
  182. if db.NewRecord(&server) {
  183. return nil, fmt.Errorf("server record does not exists in db")
  184. }
  185. return &pki.CA{
  186. CertHolder: pki.CertHolder{
  187. Cert: server.CACert,
  188. Key: server.CAKey,
  189. },
  190. }, nil
  191. }
  192. // vpnProc represents the OpenVPN process that is managed by the ovpm supervisor globally OpenVPN.
  193. var vpnProc supervisor.Supervisable
  194. // StartVPNProc starts the OpenVPN process.
  195. func StartVPNProc() {
  196. if !IsInitialized() {
  197. logrus.Error("can not launch OpenVPN because system is not initialized")
  198. return
  199. }
  200. if vpnProc == nil {
  201. panic(fmt.Sprintf("vpnProc is not initialized!"))
  202. }
  203. if vpnProc.Status() == supervisor.RUNNING {
  204. logrus.Error("OpenVPN is already started")
  205. return
  206. }
  207. vpnProc.Start()
  208. ensureNatEnabled()
  209. }
  210. // RestartVPNProc restarts the OpenVPN process.
  211. func RestartVPNProc() {
  212. if !IsInitialized() {
  213. logrus.Error("can not launch OpenVPN because system is not initialized")
  214. return
  215. }
  216. if vpnProc == nil {
  217. panic(fmt.Sprintf("vpnProc is not initialized!"))
  218. }
  219. vpnProc.Restart()
  220. }
  221. // StopVPNProc stops the OpenVPN process.
  222. func StopVPNProc() {
  223. if vpnProc == nil {
  224. panic(fmt.Sprintf("vpnProc is not initialized!"))
  225. }
  226. if vpnProc.Status() != supervisor.RUNNING {
  227. logrus.Error("OpenVPN is already not running")
  228. return
  229. }
  230. vpnProc.Stop()
  231. }
  232. // Emit generates all needed files for the OpenVPN server and dumps them to their corresponding paths defined in the config.
  233. func Emit() error {
  234. // Check dependencies
  235. if !checkOpenVPNExecutable() {
  236. return fmt.Errorf("openvpn executable can not be found! you should install OpenVPN on this machine")
  237. }
  238. if !checkOpenSSLExecutable() {
  239. return fmt.Errorf("openssl executable can not be found! you should install openssl on this machine")
  240. }
  241. if !checkIptablesExecutable() {
  242. return fmt.Errorf("iptables executable can not be found")
  243. }
  244. if !IsInitialized() {
  245. return fmt.Errorf("you should create a server first. e.g. $ ovpm vpn create-server")
  246. }
  247. if err := emitServerConf(); err != nil {
  248. return fmt.Errorf("can not emit server conf: %s", err)
  249. }
  250. if err := emitServerCert(); err != nil {
  251. return fmt.Errorf("can not emit server cert: %s", err)
  252. }
  253. if err := emitServerKey(); err != nil {
  254. return fmt.Errorf("can not emit server key: %s", err)
  255. }
  256. if err := emitCACert(); err != nil {
  257. return fmt.Errorf("can not emit ca cert : %s", err)
  258. }
  259. if err := emitCAKey(); err != nil {
  260. return fmt.Errorf("can not emit ca key: %s", err)
  261. }
  262. if err := emitDHParams(); err != nil {
  263. return fmt.Errorf("can not emit dhparams: %s", err)
  264. }
  265. if err := emitCCD(); err != nil {
  266. return fmt.Errorf("can not emit ccd: %s", err)
  267. }
  268. if err := emitIptables(); err != nil {
  269. return fmt.Errorf("can not emit iptables conf: %s", err)
  270. }
  271. if err := emitCRL(); err != nil {
  272. return fmt.Errorf("can not emit crl: %s", err)
  273. }
  274. logrus.Info("configurations emitted to the filesystem")
  275. if IsInitialized() {
  276. for {
  277. if vpnProc.Status() == supervisor.RUNNING || vpnProc.Status() == supervisor.STOPPED {
  278. logrus.Info("OpenVPN process is restarting")
  279. RestartVPNProc()
  280. break
  281. }
  282. time.Sleep(1 * time.Second)
  283. }
  284. }
  285. return nil
  286. }
  287. func emitToFile(path, content string, mode uint) error {
  288. // When testing don't emit files to the filesystem. Just pretend you did.
  289. if Testing {
  290. return nil
  291. }
  292. file, err := os.Create(path)
  293. if err != nil {
  294. return fmt.Errorf("Cannot create file %s: %v", path, err)
  295. }
  296. if mode != 0 {
  297. file.Chmod(os.FileMode(mode))
  298. }
  299. defer file.Close()
  300. fmt.Fprintf(file, content)
  301. return nil
  302. }
  303. func emitServerConf() error {
  304. serverInstance, err := GetServerInstance()
  305. if err != nil {
  306. return fmt.Errorf("can not retrieve server: %v", err)
  307. }
  308. port := DefaultVPNPort
  309. if serverInstance.Port != "" {
  310. port = serverInstance.Port
  311. }
  312. var result bytes.Buffer
  313. server := _VPNServerConfig{
  314. CertPath: _DefaultCertPath,
  315. KeyPath: _DefaultKeyPath,
  316. CACertPath: _DefaultCACertPath,
  317. CAKeyPath: _DefaultCAKeyPath,
  318. CCDPath: _DefaultVPNCCDPath,
  319. CRLPath: _DefaultCRLPath,
  320. DHParamsPath: _DefaultDHParamsPath,
  321. Net: _DefaultServerNetwork,
  322. Mask: _DefaultServerNetMask,
  323. Port: port,
  324. }
  325. data, err := bindata.Asset("template/server.conf.tmpl")
  326. if err != nil {
  327. return err
  328. }
  329. t, err := template.New("server.conf").Parse(string(data))
  330. if err != nil {
  331. return fmt.Errorf("can not parse server.conf.tmpl template: %s", err)
  332. }
  333. err = t.Execute(&result, server)
  334. if err != nil {
  335. return fmt.Errorf("can not render server.conf: %s", err)
  336. }
  337. // Wite rendered content into openvpn server conf.
  338. return emitToFile(_DefaultVPNConfPath, result.String(), 0)
  339. }
  340. // GetServerInstance returns the default server from the database.
  341. func GetServerInstance() (*DBServer, error) {
  342. var server DBServer
  343. db.First(&server)
  344. if db.NewRecord(server) {
  345. return nil, fmt.Errorf("can not retrieve server from db")
  346. }
  347. return &server, nil
  348. }
  349. // IsInitialized checks if there is a default server in the database or not.
  350. func IsInitialized() bool {
  351. var server DBServer
  352. db.First(&server)
  353. if db.NewRecord(server) {
  354. return false
  355. }
  356. return true
  357. }
  358. func emitServerKey() error {
  359. server, err := GetServerInstance()
  360. if err != nil {
  361. return err
  362. }
  363. // Write rendered content into key file.
  364. return emitToFile(_DefaultKeyPath, server.Key, 0600)
  365. }
  366. func emitServerCert() error {
  367. server, err := GetServerInstance()
  368. if err != nil {
  369. return err
  370. }
  371. // Write rendered content into the cert file.
  372. return emitToFile(_DefaultCertPath, server.Cert, 0)
  373. }
  374. func emitCRL() error {
  375. var revokedDBItems []*DBRevoked
  376. db.Find(&revokedDBItems)
  377. var revokedCertSerials []*big.Int
  378. for _, item := range revokedDBItems {
  379. bi := big.NewInt(0)
  380. bi.SetString(item.SerialNumber, 16)
  381. revokedCertSerials = append(revokedCertSerials, bi)
  382. }
  383. systemCA, err := GetSystemCA()
  384. if err != nil {
  385. return fmt.Errorf("can not emit CRL: %v", err)
  386. }
  387. crl, err := pki.NewCRL(systemCA, revokedCertSerials...)
  388. if err != nil {
  389. return fmt.Errorf("can not emit crl: %v", err)
  390. }
  391. return emitToFile(_DefaultCRLPath, crl, 0)
  392. }
  393. func emitCACert() error {
  394. server, err := GetServerInstance()
  395. if err != nil {
  396. return err
  397. }
  398. // Write rendered content into the ca cert file.
  399. return emitToFile(_DefaultCACertPath, server.CACert, 0)
  400. }
  401. func emitCAKey() error {
  402. server, err := GetServerInstance()
  403. if err != nil {
  404. return err
  405. }
  406. // Write rendered content into the ca key file.
  407. return emitToFile(_DefaultCAKeyPath, server.CAKey, 0600)
  408. }
  409. func emitCCD() error {
  410. users, err := GetAllUsers()
  411. if err != nil {
  412. return err
  413. }
  414. // Create and write rendered ccd data.
  415. os.Mkdir(_DefaultVPNCCDPath, 0755)
  416. clientsNetMask := net.IPMask(net.ParseIP(_DefaultServerNetMask))
  417. clientsNetPrefix := net.ParseIP(_DefaultServerNetwork)
  418. clientNet := clientsNetPrefix.Mask(clientsNetMask).To4()
  419. counter := 2
  420. for _, user := range users {
  421. var result bytes.Buffer
  422. clientNet[3] = byte(counter)
  423. params := struct {
  424. IP string
  425. NetMask string
  426. }{IP: clientNet.String(), NetMask: _DefaultServerNetMask}
  427. data, err := bindata.Asset("template/ccd.file.tmpl")
  428. if err != nil {
  429. return err
  430. }
  431. t, err := template.New("ccd.file.tmpl").Parse(string(data))
  432. if err != nil {
  433. return fmt.Errorf("can not parse ccd.file.tmpl template: %s", err)
  434. }
  435. err = t.Execute(&result, params)
  436. if err != nil {
  437. return fmt.Errorf("can not render ccd file %s: %s", user.Username, err)
  438. }
  439. err = emitToFile(_DefaultVPNCCDPath+user.Username, result.String(), 0)
  440. if err != nil {
  441. return err
  442. }
  443. counter++
  444. }
  445. return nil
  446. }
  447. func emitDHParams() error {
  448. var result bytes.Buffer
  449. data, err := bindata.Asset("template/dh4096.pem.tmpl")
  450. if err != nil {
  451. return err
  452. }
  453. t, err := template.New("dh4096.pem.tmpl").Parse(string(data))
  454. if err != nil {
  455. return fmt.Errorf("can not parse dh4096.pem template: %s", err)
  456. }
  457. err = t.Execute(&result, nil)
  458. if err != nil {
  459. return fmt.Errorf("can not render dh4096.pem file: %s", err)
  460. }
  461. err = emitToFile(_DefaultDHParamsPath, result.String(), 0)
  462. if err != nil {
  463. return err
  464. }
  465. return nil
  466. }
  467. func emitIptables() error {
  468. return nil
  469. }
  470. func checkOpenVPNExecutable() bool {
  471. executable := getOpenVPNExecutable()
  472. if executable == "" {
  473. logrus.Error("openvpn is not installed ✘")
  474. return false
  475. }
  476. logrus.Debugf("openvpn executable detected: %s ✔", executable)
  477. return true
  478. }
  479. func getOpenVPNExecutable() string {
  480. cmd := exec.Command("which", "openvpn")
  481. output, err := cmd.Output()
  482. if err != nil {
  483. logrus.Errorf("openvpn is not installed: %s ✘", err)
  484. return ""
  485. }
  486. logrus.Debugf("openvpn executable detected: %s ✔", strings.TrimSpace(string(output[:])))
  487. return strings.TrimSpace(string(output[:]))
  488. }
  489. func checkOpenSSLExecutable() bool {
  490. cmd := exec.Command("which", "openssl")
  491. output, err := cmd.Output()
  492. if err != nil {
  493. logrus.Errorf("openssl is not installed: %s ✘", err)
  494. return false
  495. }
  496. logrus.Debugf("openssl executable detected: %s ✔", strings.TrimSpace(string(output[:])))
  497. return true
  498. }
  499. func checkIptablesExecutable() bool {
  500. cmd := exec.Command("which", "iptables")
  501. output, err := cmd.Output()
  502. if err != nil {
  503. logrus.Errorf("iptables is not installed: %s ✘", err)
  504. return false
  505. }
  506. logrus.Debugf("iptables executable detected: %s ✔", strings.TrimSpace(string(output[:])))
  507. return true
  508. }
  509. func ensureBaseDir() {
  510. os.Mkdir(varBasePath, 0755)
  511. }
  512. func init() {
  513. ensureBaseDir()
  514. var err error
  515. vpnProc, err = supervisor.NewProcess(getOpenVPNExecutable(), varBasePath, []string{"--config", _DefaultVPNConfPath})
  516. if err != nil {
  517. logrus.Errorf("can not create process: %v", err)
  518. }
  519. }